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

Unified Diff: chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc

Issue 2432013002: Improve intent: URI handling (Closed)
Patch Set: rebase onto Luis' directory reorganize CL Created 4 years, 2 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc b/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc
index 3cfeadabb75c53f84eac9111e2c58907b72054c0..cc7c17675c76c57d530ddd8c3df0e8bd272f3885 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.h"
#include <memory>
-#include <string>
#include <utility>
#include <vector>
@@ -23,7 +22,11 @@
#include "components/arc/intent_helper/page_transition_util.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/page_navigator.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/common/referrer.h"
+#include "ui/base/page_transition_types.h"
+#include "ui/base/window_open_disposition.h"
#include "ui/gfx/image/image.h"
#include "url/gurl.h"
@@ -65,6 +68,149 @@ void CloseTabIfNeeded(int render_process_host_id, int routing_id) {
web_contents->Close();
}
+// Shows |url| in the current tab.
+void OpenUrlInChrome(int render_process_host_id,
+ int routing_id,
+ const GURL& url) {
+ WebContents* web_contents =
+ tab_util::GetWebContentsByID(render_process_host_id, routing_id);
+ if (!web_contents)
+ return;
+
+ // Use the PAGE_TRANSITION_FROM_API qualifier so that this nativation won't
+ // end up showing the disambig dialog.
+ const ui::PageTransition page_transition_type = ui::PageTransitionFromInt(
+ ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_FROM_API);
+ constexpr bool kIsRendererInitiated = false;
+ const content::OpenURLParams params(
+ // TODO(yusukes): Send a non-empty referrer.
+ url, content::Referrer(), WindowOpenDisposition::CURRENT_TAB,
+ page_transition_type, kIsRendererInitiated);
+ web_contents->OpenURL(params);
+}
+
+// Sends |url| to ARC.
+void HandleUrlInArc(int render_process_host_id,
+ int routing_id,
+ const std::pair<GURL, std::string>& url_and_package) {
+ auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance(
+ "HandleUrl", kMinVersionForHandleUrl);
+ if (!instance)
+ return;
+
+ instance->HandleUrl(url_and_package.first.spec(), url_and_package.second);
+ CloseTabIfNeeded(render_process_host_id, routing_id);
+}
+
+// A helper function called by GetAction().
+GetActionResult GetActionInternal(
+ const GURL& original_url,
+ const mojom::IntentHandlerInfoPtr& handler,
+ std::pair<GURL, std::string>* out_url_and_package) {
+ if (!handler->fallback_url.is_null()) {
+ *out_url_and_package = std::make_pair(GURL(handler->fallback_url.get()),
+ handler->package_name.get());
+ if (ArcIntentHelperBridge::IsIntentHelperPackage(handler->package_name)) {
+ // Since |package_name| is "Chrome", and |fallback_url| is not null, the
+ // URL must be either http or https. Check it just in case, and if not,
+ // fallback to HANDLE_URL_IN_ARC;
+ if (out_url_and_package->first.SchemeIsHTTPOrHTTPS())
+ return GetActionResult::OPEN_URL_IN_CHROME;
+
+ LOG(WARNING) << "Failed to handle " << out_url_and_package->first
+ << " in Chrome. Falling back to ARC...";
+ }
+ // |fallback_url| which Chrome doesn't support is passed (e.g. market:).
+ return GetActionResult::HANDLE_URL_IN_ARC;
+ }
+
+ // Unlike |handler->fallback_url|, the |original_url| should always be handled
+ // in ARC since it's external to Chrome.
+ *out_url_and_package =
+ std::make_pair(original_url, handler->package_name.get());
+ return GetActionResult::HANDLE_URL_IN_ARC;
+}
+
+// Gets an action that should be done when ARC has the |handlers| for the
+// |original_url| and the user selects |selected_app_index|. When the user
+// hasn't selected any app, |selected_app_index| must be set to
+// |handlers.size()|.
+//
+// When the returned action is either OPEN_URL_IN_CHROME or HANDLE_URL_IN_ARC,
+// |out_url_and_package| is filled accordingly.
+GetActionResult GetAction(
+ const GURL& original_url,
+ const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers,
+ size_t selected_app_index,
+ std::pair<GURL, std::string>* out_url_and_package) {
+ DCHECK(out_url_and_package);
+ if (!handlers.size())
+ return GetActionResult::SHOW_CHROME_OS_DIALOG; // no apps found.
+
+ if (selected_app_index == handlers.size()) {
+ // The user hasn't made the selection yet.
+
+ // If |handlers| has only one element and its package is "Chrome", open
+ // the fallback URL in the current tab without showing the dialog.
+ if (handlers.size() == 1) {
+ if (GetActionInternal(original_url, handlers[0], out_url_and_package) ==
+ GetActionResult::OPEN_URL_IN_CHROME) {
+ return GetActionResult::OPEN_URL_IN_CHROME;
+ }
+ }
+
+ // If one of the apps is marked as preferred, use it right away without
+ // showing the UI. |is_preferred| will never be true unless the user
+ // explicitly makes it the default with the "always" button.
+ for (size_t i = 0; i < handlers.size(); ++i) {
+ const mojom::IntentHandlerInfoPtr& handler = handlers[i];
+ if (!handler->is_preferred)
+ continue;
+ // A preferred activity is found. Decide how to open it, either in Chrome
+ // or ARC.
+ return GetActionInternal(original_url, handler, out_url_and_package);
+ }
+ // Ask the user to pick one.
+ return GetActionResult::ASK_USER;
+ }
+
+ // The user has already made the selection. Decide how to open it, either in
+ // Chrome or ARC.
+ return GetActionInternal(original_url, handlers[selected_app_index],
+ out_url_and_package);
+}
+
+// Handles |url| if possible. Returns true if it is actually handled.
+bool HandleUrl(int render_process_host_id,
+ int routing_id,
+ const GURL& url,
+ const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers,
+ size_t selected_app_index,
+ GetActionResult* out_result) {
+ std::pair<GURL, std::string> url_and_package;
+ const GetActionResult result =
+ GetAction(url, handlers, selected_app_index, &url_and_package);
+ if (out_result)
+ *out_result = result;
+
+ switch (result) {
+ case GetActionResult::SHOW_CHROME_OS_DIALOG:
+ ShowFallbackExternalProtocolDialog(render_process_host_id, routing_id,
+ url);
+ return true;
+ case GetActionResult::OPEN_URL_IN_CHROME:
+ OpenUrlInChrome(render_process_host_id, routing_id,
+ url_and_package.first);
+ return true;
+ case GetActionResult::HANDLE_URL_IN_ARC:
+ HandleUrlInArc(render_process_host_id, routing_id, url_and_package);
+ return true;
+ case GetActionResult::ASK_USER:
+ break;
+ }
+ return false;
+}
+
// Called when the dialog is closed.
void OnIntentPickerClosed(int render_process_host_id,
int routing_id,
@@ -102,9 +248,8 @@ void OnIntentPickerClosed(int render_process_host_id,
}
case ArcNavigationThrottle::CloseReason::JUST_ONCE_PRESSED: {
// Launch the selected app.
- instance->HandleUrl(url.spec(),
- handlers[selected_app_index]->package_name);
- CloseTabIfNeeded(render_process_host_id, routing_id);
+ HandleUrl(render_process_host_id, routing_id, url, handlers,
+ selected_app_index, nullptr);
break;
}
case ArcNavigationThrottle::CloseReason::PREFERRED_ACTIVITY_FOUND:
@@ -169,22 +314,19 @@ void OnUrlHandlerList(int render_process_host_id,
"HandleUrl", kMinVersionForHandleUrl);
scoped_refptr<ActivityIconLoader> icon_loader = GetIconLoader();
- if (!instance || !icon_loader || !handlers.size()) {
- // No handler is available on ARC side. Show the Chrome OS dialog.
+ if (!instance || !icon_loader) {
+ // ARC is not running anymore. Show the Chrome OS dialog.
ShowFallbackExternalProtocolDialog(render_process_host_id, routing_id, url);
return;
}
- // If one of the apps is marked as preferred, use it right away without
- // showing the UI. |is_preferred| will never be true unless the user
- // explicitly makes it the default with the "always" button.
- for (size_t i = 0; i < handlers.size(); ++i) {
- if (!handlers[i]->is_preferred)
- continue;
- instance->HandleUrl(url.spec(), handlers[i]->package_name);
- CloseTabIfNeeded(render_process_host_id, routing_id);
- RecordUma(ArcNavigationThrottle::CloseReason::PREFERRED_ACTIVITY_FOUND);
- return;
+ // Check if the |url| should be handled right away without showing the UI.
+ GetActionResult result;
+ if (HandleUrl(render_process_host_id, routing_id, url, handlers,
+ handlers.size(), &result)) {
+ if (result == GetActionResult::HANDLE_URL_IN_ARC)
+ RecordUma(ArcNavigationThrottle::CloseReason::PREFERRED_ACTIVITY_FOUND);
+ return; // the |url| has been handled.
}
// Otherwise, retrieve icons of the activities.
@@ -204,6 +346,9 @@ bool RunArcExternalProtocolDialog(const GURL& url,
int routing_id,
ui::PageTransition page_transition,
bool has_user_gesture) {
+ // This function is for external protocols that Chrome cannot handle.
+ DCHECK(!url.SchemeIsHTTPOrHTTPS()) << url;
+
// Try to forward <form> submissions to ARC when possible.
constexpr bool kAllowFormSubmit = true;
if (ShouldIgnoreNavigation(page_transition, kAllowFormSubmit))
@@ -229,4 +374,13 @@ bool RunArcExternalProtocolDialog(const GURL& url,
return true;
}
+GetActionResult GetActionForTesting(
+ const GURL& original_url,
+ const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers,
+ size_t selected_app_index,
+ std::pair<GURL, std::string>* out_url_and_package) {
+ return GetAction(original_url, handlers, selected_app_index,
+ out_url_and_package);
+}
+
} // namespace arc

Powered by Google App Engine
This is Rietveld 408576698