Index: chrome/browser/chromeos/arc/arc_navigation_throttle.cc |
diff --git a/chrome/browser/chromeos/arc/arc_navigation_throttle.cc b/chrome/browser/chromeos/arc/arc_navigation_throttle.cc |
index 59367ca1ba537de42b6ba621933a72656e045a7c..eea441573d8a413082bd7e0bea6e82418af0a570 100644 |
--- a/chrome/browser/chromeos/arc/arc_navigation_throttle.cc |
+++ b/chrome/browser/chromeos/arc/arc_navigation_throttle.cc |
@@ -58,6 +58,59 @@ bool ShouldOverrideUrlLoading(const GURL& previous_url, |
net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); |
} |
+// Returns true if |handlers| contain one or more apps. When this function is |
+// called from OnAppCandidatesReceived, |handlers| always contain Chrome (aka |
+// intent_helper), but the function doesn't treat it as an app. |
+bool IsAppAvailable(const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers) { |
+ return handlers.size() > 1 || (handlers.size() == 1 && |
+ !ArcIntentHelperBridge::IsIntentHelperPackage( |
+ handlers[0]->package_name)); |
+} |
+ |
+// Searches for a preferred app in |handlers| and returns its index. If not |
+// found, returns |handlers.size()|. |
+size_t FindPreferredApp( |
+ const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers, |
+ const GURL& url_for_logging) { |
+ for (size_t i = 0; i < handlers.size(); ++i) { |
+ if (!handlers[i]->is_preferred) |
+ continue; |
+ if (ArcIntentHelperBridge::IsIntentHelperPackage( |
+ handlers[i]->package_name)) { |
+ // If Chrome browser was selected as the preferred app, we shouldn't |
+ // create a throttle. |
+ DVLOG(1) |
+ << "Chrome browser is selected as the preferred app for this URL: " |
+ << url_for_logging; |
+ } |
+ return i; |
+ } |
+ return handlers.size(); // not found |
+} |
+ |
+// Swaps Chrome app with any app in row |kMaxAppResults-1| iff its index is |
+// bigger, thus ensuring the user can always see Chrome without scrolling. |
+// When swap is needed, fills |out_indices| and returns true. If |handlers| |
+// do not have Chrome, returns false. |
+bool IsSwapElementsNeeded( |
+ const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers, |
+ std::pair<size_t, size_t>* out_indices) { |
+ size_t chrome_app_index = 0; |
+ for (size_t i = 0; i < handlers.size(); ++i) { |
+ if (ArcIntentHelperBridge::IsIntentHelperPackage( |
+ handlers[i]->package_name)) { |
+ chrome_app_index = i; |
+ break; |
+ } |
+ } |
+ if (chrome_app_index < ArcNavigationThrottle::kMaxAppResults) |
+ return false; |
+ |
+ *out_indices = std::make_pair(ArcNavigationThrottle::kMaxAppResults - 1, |
+ chrome_app_index); |
+ return true; |
+} |
+ |
} // namespace |
ArcNavigationThrottle::ArcNavigationThrottle( |
@@ -163,49 +216,29 @@ ArcNavigationThrottle::HandleRequest() { |
void ArcNavigationThrottle::OnAppCandidatesReceived( |
mojo::Array<mojom::IntentHandlerInfoPtr> handlers) { |
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
- if (handlers.empty() || |
- (handlers.size() == 1 && ArcIntentHelperBridge::IsIntentHelperPackage( |
- handlers[0]->package_name))) { |
+ if (!IsAppAvailable(handlers)) { |
// This scenario shouldn't be accesed as ArcNavigationThrottle is created |
// iff there are ARC apps which can actually handle the given URL. |
DVLOG(1) << "There are no app candidates for this URL: " |
- << navigation_handle()->GetURL().spec(); |
+ << navigation_handle()->GetURL(); |
navigation_handle()->Resume(); |
return; |
} |
// If one of the apps is marked as preferred, use it right away without |
// showing the UI. |
- for (size_t i = 0; i < handlers.size(); ++i) { |
- if (!handlers[i]->is_preferred) |
- continue; |
- if (ArcIntentHelperBridge::IsIntentHelperPackage( |
- handlers[i]->package_name)) { |
- // If Chrome browser was selected as the preferred app, we should't |
- // create a throttle. |
- DVLOG(1) |
- << "Chrome browser is selected as the preferred app for this URL: " |
- << navigation_handle()->GetURL().spec(); |
- } |
- std::string package_name = handlers[i]->package_name; |
+ const size_t index = |
+ FindPreferredApp(handlers, navigation_handle()->GetURL()); |
+ if (index != handlers.size()) { |
+ const std::string package_name = handlers[index]->package_name; |
OnIntentPickerClosed(std::move(handlers), package_name, |
CloseReason::PREFERRED_ACTIVITY_FOUND); |
return; |
} |
- // Swap Chrome app with any app in row |kMaxAppResults-1| iff its index is |
- // bigger, thus ensuring the user can always see Chrome without scrolling. |
- size_t chrome_app_index = 0; |
- for (size_t i = 0; i < handlers.size(); ++i) { |
- if (ArcIntentHelperBridge::IsIntentHelperPackage( |
- handlers[i]->package_name)) { |
- chrome_app_index = i; |
- break; |
- } |
- } |
- |
- if (chrome_app_index >= kMaxAppResults) |
- std::swap(handlers[kMaxAppResults - 1], handlers[chrome_app_index]); |
+ std::pair<size_t, size_t> indices; |
+ if (IsSwapElementsNeeded(handlers, &indices)) |
+ std::swap(handlers[indices.first], handlers[indices.second]); |
scoped_refptr<ActivityIconLoader> icon_loader = GetIconLoader(); |
if (!icon_loader) { |
@@ -214,9 +247,8 @@ void ArcNavigationThrottle::OnAppCandidatesReceived( |
return; |
} |
std::vector<ActivityIconLoader::ActivityName> activities; |
- for (const auto& handler : handlers) { |
+ for (const auto& handler : handlers) |
activities.emplace_back(handler->package_name, handler->activity_name); |
- } |
icon_loader->GetActivityIcons( |
activities, |
base::Bind(&ArcNavigationThrottle::OnAppIconsReceived, |
@@ -258,21 +290,14 @@ void ArcNavigationThrottle::OnIntentPickerClosed( |
// Make sure that the instance at least supports HandleUrl. |
auto* instance = ArcIntentHelperBridge::GetIntentHelperInstance( |
"HandleUrl", kMinVersionForHandleUrl); |
- size_t selected_app_index = handlers.size(); |
+ // Since we are selecting an app by its package name, we need to locate it |
+ // on the |handlers| structure before sending the IPC to ARC. |
+ const size_t selected_app_index = GetAppIndex(handlers, selected_app_package); |
if (!instance) { |
close_reason = CloseReason::ERROR; |
} else if (close_reason == CloseReason::JUST_ONCE_PRESSED || |
close_reason == CloseReason::ALWAYS_PRESSED || |
close_reason == CloseReason::PREFERRED_ACTIVITY_FOUND) { |
- // Since we are selecting an app by its package name, we need to locate it |
- // on the |handlers| structure before sending the IPC to ARC. |
- for (size_t i = 0; i < handlers.size(); ++i) { |
- if (handlers[i]->package_name == selected_app_package) { |
- selected_app_index = i; |
- break; |
- } |
- } |
- |
if (selected_app_index == handlers.size()) |
close_reason = CloseReason::ERROR; |
} |
@@ -323,10 +348,40 @@ void ArcNavigationThrottle::OnIntentPickerClosed( |
} |
// static |
+size_t ArcNavigationThrottle::GetAppIndex( |
+ const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers, |
+ const std::string& selected_app_package) { |
+ for (size_t i = 0; i < handlers.size(); ++i) { |
+ if (handlers[i]->package_name == selected_app_package) |
+ return i; |
+ } |
+ return handlers.size(); |
+} |
+ |
+// static |
bool ArcNavigationThrottle::ShouldOverrideUrlLoadingForTesting( |
const GURL& previous_url, |
const GURL& current_url) { |
return ShouldOverrideUrlLoading(previous_url, current_url); |
} |
+// static |
+bool ArcNavigationThrottle::IsAppAvailableForTesting( |
+ const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers) { |
+ return IsAppAvailable(handlers); |
+} |
+ |
+// static |
+size_t ArcNavigationThrottle::FindPreferredAppForTesting( |
+ const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers) { |
+ return FindPreferredApp(handlers, GURL()); |
+} |
+ |
+// static |
+bool ArcNavigationThrottle::IsSwapElementsNeededForTesting( |
+ const mojo::Array<mojom::IntentHandlerInfoPtr>& handlers, |
+ std::pair<size_t, size_t>* out_indices) { |
+ return IsSwapElementsNeeded(handlers, out_indices); |
+} |
+ |
} // namespace arc |