| 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/arc_navigation_throttle.h" | 5 #include "chrome/browser/chromeos/arc/arc_navigation_throttle.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
| 12 #include "base/metrics/histogram_macros.h" | 12 #include "base/metrics/histogram_macros.h" |
| 13 #include "components/arc/arc_bridge_service.h" | 13 #include "components/arc/arc_bridge_service.h" |
| 14 #include "components/arc/arc_service_manager.h" | 14 #include "components/arc/arc_service_manager.h" |
| 15 #include "components/arc/intent_helper/arc_intent_helper_bridge.h" | 15 #include "components/arc/intent_helper/arc_intent_helper_bridge.h" |
| 16 #include "components/arc/intent_helper/local_activity_resolver.h" |
| 16 #include "content/public/browser/browser_thread.h" | 17 #include "content/public/browser/browser_thread.h" |
| 17 #include "content/public/browser/navigation_handle.h" | 18 #include "content/public/browser/navigation_handle.h" |
| 18 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 19 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| 19 #include "ui/base/page_transition_types.h" | 20 #include "ui/base/page_transition_types.h" |
| 20 | 21 |
| 21 namespace arc { | 22 namespace arc { |
| 22 | 23 |
| 23 namespace { | 24 namespace { |
| 24 | 25 |
| 25 constexpr int kMinInstanceVersion = 7; | 26 constexpr int kMinInstanceVersion = 7; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 47 VLOG(1) << "ARC intent helper instance is too old."; | 48 VLOG(1) << "ARC intent helper instance is too old."; |
| 48 return nullptr; | 49 return nullptr; |
| 49 } | 50 } |
| 50 return intent_helper_instance; | 51 return intent_helper_instance; |
| 51 } | 52 } |
| 52 | 53 |
| 53 } // namespace | 54 } // namespace |
| 54 | 55 |
| 55 ArcNavigationThrottle::ArcNavigationThrottle( | 56 ArcNavigationThrottle::ArcNavigationThrottle( |
| 56 content::NavigationHandle* navigation_handle, | 57 content::NavigationHandle* navigation_handle, |
| 57 const ShowDisambigDialogCallback& show_disambig_dialog_cb) | 58 const ShowIntentPickerCallback& show_intent_picker_cb) |
| 58 : content::NavigationThrottle(navigation_handle), | 59 : content::NavigationThrottle(navigation_handle), |
| 59 show_disambig_dialog_callback_(show_disambig_dialog_cb), | 60 show_intent_picker_callback_(show_intent_picker_cb), |
| 61 previous_user_action_(CloseReason::INVALID), |
| 60 weak_ptr_factory_(this) {} | 62 weak_ptr_factory_(this) {} |
| 61 | 63 |
| 62 ArcNavigationThrottle::~ArcNavigationThrottle() = default; | 64 ArcNavigationThrottle::~ArcNavigationThrottle() = default; |
| 63 | 65 |
| 64 content::NavigationThrottle::ThrottleCheckResult | 66 content::NavigationThrottle::ThrottleCheckResult |
| 65 ArcNavigationThrottle::WillStartRequest() { | 67 ArcNavigationThrottle::WillStartRequest() { |
| 66 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 68 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 69 return HandleRequest(); |
| 70 } |
| 67 | 71 |
| 72 content::NavigationThrottle::ThrottleCheckResult |
| 73 ArcNavigationThrottle::WillRedirectRequest() { |
| 74 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 75 |
| 76 switch (previous_user_action_) { |
| 77 case CloseReason::ERROR: |
| 78 case CloseReason::DIALOG_DEACTIVATED: |
| 79 // User dismissed the dialog, or some error occurred before. Don't |
| 80 // repeatedly pop up the dialog. |
| 81 return content::NavigationThrottle::PROCEED; |
| 82 |
| 83 case CloseReason::ALWAYS_PRESSED: |
| 84 case CloseReason::JUST_ONCE_PRESSED: |
| 85 case CloseReason::PREFERRED_ACTIVITY_FOUND: |
| 86 // Should never get here - if the user selected one of these previously, |
| 87 // Chrome should not see a redirect. |
| 88 NOTREACHED(); |
| 89 |
| 90 case CloseReason::INVALID: |
| 91 // No picker has previously been popped up for this - continue. |
| 92 break; |
| 93 } |
| 94 return HandleRequest(); |
| 95 } |
| 96 |
| 97 content::NavigationThrottle::ThrottleCheckResult |
| 98 ArcNavigationThrottle::HandleRequest() { |
| 99 const GURL& url = navigation_handle()->GetURL(); |
| 100 |
| 101 // Mask out any redirect qualifiers - this method handles navigation from |
| 102 // redirect and non-redirect navigations equivalently. |
| 68 const ui::PageTransition transition = | 103 const ui::PageTransition transition = |
| 69 navigation_handle()->GetPageTransition(); | 104 ui::PageTransitionFromInt(navigation_handle()->GetPageTransition() & |
| 105 ~ui::PAGE_TRANSITION_IS_REDIRECT_MASK); |
| 70 | 106 |
| 71 if (!ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_LINK)) { | 107 if (!ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_LINK)) { |
| 72 // If this navigation event wasn't spawned by the user clicking on a link. | 108 // Allow navigation to proceed if this event wasn't spawned by the user |
| 109 // clicking on a link. |
| 73 return content::NavigationThrottle::PROCEED; | 110 return content::NavigationThrottle::PROCEED; |
| 74 } | 111 } |
| 75 | 112 |
| 76 if (ui::PageTransitionGetQualifier(transition) != 0) { | 113 if (ui::PageTransitionGetQualifier(transition) != 0) { |
| 77 // Qualifiers indicate that this navigation was the result of a click on a | 114 // Qualifiers indicate that this navigation was the result of a click on a |
| 78 // forward/back button, or a redirect, or typing in the URL bar, etc. Don't | 115 // forward/back button, or typing in the URL bar, etc. Don't pass any of |
| 79 // pass any of those types of navigations to the intent helper (see | 116 // those types of navigations to the intent helper (see crbug.com/630072). |
| 80 // crbug.com/630072). | 117 // Note that redirects, which we do pass on, are masked out above. |
| 81 return content::NavigationThrottle::PROCEED; | 118 return content::NavigationThrottle::PROCEED; |
| 82 } | 119 } |
| 83 | 120 |
| 84 if (!ShouldOverrideUrlLoading(navigation_handle())) | 121 if (!ShouldOverrideUrlLoading(navigation_handle())) |
| 85 return content::NavigationThrottle::PROCEED; | 122 return content::NavigationThrottle::PROCEED; |
| 86 | 123 |
| 87 const GURL& url = navigation_handle()->GetURL(); | 124 arc::ArcServiceManager* arc_service_manager = arc::ArcServiceManager::Get(); |
| 125 DCHECK(arc_service_manager); |
| 126 scoped_refptr<arc::LocalActivityResolver> local_resolver = |
| 127 arc_service_manager->activity_resolver(); |
| 128 if (local_resolver->ShouldChromeHandleUrl(url)) { |
| 129 // Allow navigation to proceed if there isn't an android app that handles |
| 130 // the given URL. |
| 131 return content::NavigationThrottle::PROCEED; |
| 132 } |
| 133 |
| 88 mojom::IntentHelperInstance* bridge_instance = GetIntentHelper(); | 134 mojom::IntentHelperInstance* bridge_instance = GetIntentHelper(); |
| 89 if (!bridge_instance) | 135 if (!bridge_instance) |
| 90 return content::NavigationThrottle::PROCEED; | 136 return content::NavigationThrottle::PROCEED; |
| 91 bridge_instance->RequestUrlHandlerList( | 137 bridge_instance->RequestUrlHandlerList( |
| 92 url.spec(), base::Bind(&ArcNavigationThrottle::OnAppCandidatesReceived, | 138 url.spec(), base::Bind(&ArcNavigationThrottle::OnAppCandidatesReceived, |
| 93 weak_ptr_factory_.GetWeakPtr())); | 139 weak_ptr_factory_.GetWeakPtr())); |
| 94 return content::NavigationThrottle::DEFER; | 140 return content::NavigationThrottle::DEFER; |
| 95 } | 141 } |
| 96 | 142 |
| 97 content::NavigationThrottle::ThrottleCheckResult | |
| 98 ArcNavigationThrottle::WillRedirectRequest() { | |
| 99 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 100 return content::NavigationThrottle::PROCEED; | |
| 101 } | |
| 102 | |
| 103 // We received the array of app candidates to handle this URL (even the Chrome | 143 // We received the array of app candidates to handle this URL (even the Chrome |
| 104 // app is included). | 144 // app is included). |
| 105 void ArcNavigationThrottle::OnAppCandidatesReceived( | 145 void ArcNavigationThrottle::OnAppCandidatesReceived( |
| 106 mojo::Array<mojom::UrlHandlerInfoPtr> handlers) { | 146 mojo::Array<mojom::UrlHandlerInfoPtr> handlers) { |
| 107 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 147 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 108 if (handlers.empty() || | 148 if (handlers.empty() || |
| 109 (handlers.size() == 1 && ArcIntentHelperBridge::IsIntentHelperPackage( | 149 (handlers.size() == 1 && ArcIntentHelperBridge::IsIntentHelperPackage( |
| 110 handlers[0]->package_name))) { | 150 handlers[0]->package_name))) { |
| 111 // This scenario shouldn't be accesed as ArcNavigationThrottle is created | 151 // This scenario shouldn't be accesed as ArcNavigationThrottle is created |
| 112 // iff there are ARC apps which can actually handle the given URL. | 152 // iff there are ARC apps which can actually handle the given URL. |
| 113 DVLOG(1) << "There are no app candidates for this URL: " | 153 DVLOG(1) << "There are no app candidates for this URL: " |
| 114 << navigation_handle()->GetURL().spec(); | 154 << navigation_handle()->GetURL().spec(); |
| 115 navigation_handle()->Resume(); | 155 navigation_handle()->Resume(); |
| 116 return; | 156 return; |
| 117 } | 157 } |
| 118 | 158 |
| 119 // If one of the apps is marked as preferred, use it right away without | 159 // If one of the apps is marked as preferred, use it right away without |
| 120 // showing the UI. | 160 // showing the UI. |
| 121 for (size_t i = 0; i < handlers.size(); ++i) { | 161 for (size_t i = 0; i < handlers.size(); ++i) { |
| 122 if (!handlers[i]->is_preferred) | 162 if (!handlers[i]->is_preferred) |
| 123 continue; | 163 continue; |
| 124 if (ArcIntentHelperBridge::IsIntentHelperPackage( | 164 if (ArcIntentHelperBridge::IsIntentHelperPackage( |
| 125 handlers[i]->package_name)) { | 165 handlers[i]->package_name)) { |
| 126 // If Chrome browser was selected as the preferred app, we should't | 166 // If Chrome browser was selected as the preferred app, we should't |
| 127 // create a throttle. | 167 // create a throttle. |
| 128 DVLOG(1) | 168 DVLOG(1) |
| 129 << "Chrome browser is selected as the preferred app for this URL: " | 169 << "Chrome browser is selected as the preferred app for this URL: " |
| 130 << navigation_handle()->GetURL().spec(); | 170 << navigation_handle()->GetURL().spec(); |
| 131 } | 171 } |
| 132 OnDisambigDialogClosed(std::move(handlers), i, | 172 OnIntentPickerClosed(std::move(handlers), i, |
| 133 CloseReason::PREFERRED_ACTIVITY_FOUND); | 173 CloseReason::PREFERRED_ACTIVITY_FOUND); |
| 134 return; | 174 return; |
| 135 } | 175 } |
| 136 | 176 |
| 137 // Swap Chrome app with any app in row |kMaxAppResults-1| iff his index is | 177 // Swap Chrome app with any app in row |kMaxAppResults-1| iff his index is |
| 138 // bigger, thus ensuring the user can always see Chrome without scrolling. | 178 // bigger, thus ensuring the user can always see Chrome without scrolling. |
| 139 size_t chrome_app_index = 0; | 179 size_t chrome_app_index = 0; |
| 140 for (size_t i = 0; i < handlers.size(); ++i) { | 180 for (size_t i = 0; i < handlers.size(); ++i) { |
| 141 if (ArcIntentHelperBridge::IsIntentHelperPackage( | 181 if (ArcIntentHelperBridge::IsIntentHelperPackage( |
| 142 handlers[i]->package_name)) { | 182 handlers[i]->package_name)) { |
| 143 chrome_app_index = i; | 183 chrome_app_index = i; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 173 for (const auto& handler : handlers) { | 213 for (const auto& handler : handlers) { |
| 174 gfx::Image icon; | 214 gfx::Image icon; |
| 175 const ActivityIconLoader::ActivityName activity(handler->package_name, | 215 const ActivityIconLoader::ActivityName activity(handler->package_name, |
| 176 handler->activity_name); | 216 handler->activity_name); |
| 177 const auto it = icons->find(activity); | 217 const auto it = icons->find(activity); |
| 178 | 218 |
| 179 app_info.emplace_back( | 219 app_info.emplace_back( |
| 180 handler->name, it != icons->end() ? it->second.icon20 : gfx::Image()); | 220 handler->name, it != icons->end() ? it->second.icon20 : gfx::Image()); |
| 181 } | 221 } |
| 182 | 222 |
| 183 show_disambig_dialog_callback_.Run( | 223 show_intent_picker_callback_.Run( |
| 184 navigation_handle(), app_info, | 224 navigation_handle(), app_info, |
| 185 base::Bind(&ArcNavigationThrottle::OnDisambigDialogClosed, | 225 base::Bind(&ArcNavigationThrottle::OnIntentPickerClosed, |
| 186 weak_ptr_factory_.GetWeakPtr(), base::Passed(&handlers))); | 226 weak_ptr_factory_.GetWeakPtr(), base::Passed(&handlers))); |
| 187 } | 227 } |
| 188 | 228 |
| 189 void ArcNavigationThrottle::OnDisambigDialogClosed( | 229 void ArcNavigationThrottle::OnIntentPickerClosed( |
| 190 mojo::Array<mojom::UrlHandlerInfoPtr> handlers, | 230 mojo::Array<mojom::UrlHandlerInfoPtr> handlers, |
| 191 size_t selected_app_index, | 231 size_t selected_app_index, |
| 192 CloseReason close_reason) { | 232 CloseReason close_reason) { |
| 193 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 233 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 194 const GURL& url = navigation_handle()->GetURL(); | 234 const GURL& url = navigation_handle()->GetURL(); |
| 195 content::NavigationHandle* handle = navigation_handle(); | 235 content::NavigationHandle* handle = navigation_handle(); |
| 196 | 236 |
| 237 previous_user_action_ = close_reason; |
| 238 |
| 197 mojom::IntentHelperInstance* bridge = GetIntentHelper(); | 239 mojom::IntentHelperInstance* bridge = GetIntentHelper(); |
| 198 if (!bridge || selected_app_index >= handlers.size()) { | 240 if (!bridge || selected_app_index >= handlers.size()) { |
| 199 close_reason = CloseReason::ERROR; | 241 close_reason = CloseReason::ERROR; |
| 200 } | 242 } |
| 201 | 243 |
| 202 switch (close_reason) { | 244 switch (close_reason) { |
| 203 case CloseReason::ERROR: | 245 case CloseReason::ERROR: |
| 204 case CloseReason::DIALOG_DEACTIVATED: { | 246 case CloseReason::DIALOG_DEACTIVATED: { |
| 205 // If the user fails to select an option from the list, or the UI returned | 247 // If the user fails to select an option from the list, or the UI returned |
| 206 // an error or if |selected_app_index| is not a valid index, then resume | 248 // an error or if |selected_app_index| is not a valid index, then resume |
| (...skipping 12 matching lines...) Expand all Loading... |
| 219 handlers[selected_app_index]->package_name)) { | 261 handlers[selected_app_index]->package_name)) { |
| 220 handle->Resume(); | 262 handle->Resume(); |
| 221 } else { | 263 } else { |
| 222 bridge->HandleUrl(url.spec(), | 264 bridge->HandleUrl(url.spec(), |
| 223 handlers[selected_app_index]->package_name); | 265 handlers[selected_app_index]->package_name); |
| 224 handle->CancelDeferredNavigation( | 266 handle->CancelDeferredNavigation( |
| 225 content::NavigationThrottle::CANCEL_AND_IGNORE); | 267 content::NavigationThrottle::CANCEL_AND_IGNORE); |
| 226 } | 268 } |
| 227 break; | 269 break; |
| 228 } | 270 } |
| 229 case CloseReason::SIZE: { | 271 case CloseReason::INVALID: { |
| 230 NOTREACHED(); | 272 NOTREACHED(); |
| 231 return; | 273 return; |
| 232 } | 274 } |
| 233 } | 275 } |
| 234 | 276 |
| 235 UMA_HISTOGRAM_ENUMERATION("Arc.IntentHandlerAction", | 277 UMA_HISTOGRAM_ENUMERATION("Arc.IntentHandlerAction", |
| 236 static_cast<int>(close_reason), | 278 static_cast<int>(close_reason), |
| 237 static_cast<int>(CloseReason::SIZE)); | 279 static_cast<int>(CloseReason::SIZE)); |
| 238 } | 280 } |
| 239 | 281 |
| 240 bool ArcNavigationThrottle::ShouldOverrideUrlLoading( | 282 bool ArcNavigationThrottle::ShouldOverrideUrlLoading( |
| 241 content::NavigationHandle* navigation_handle) { | 283 content::NavigationHandle* navigation_handle) { |
| 242 GURL previous_url = navigation_handle->GetReferrer().url; | 284 GURL previous_url = navigation_handle->GetReferrer().url; |
| 243 GURL current_url = navigation_handle->GetURL(); | 285 GURL current_url = navigation_handle->GetURL(); |
| 244 return !net::registry_controlled_domains::SameDomainOrHost( | 286 return !net::registry_controlled_domains::SameDomainOrHost( |
| 245 current_url, previous_url, | 287 current_url, previous_url, |
| 246 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); | 288 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); |
| 247 } | 289 } |
| 248 | 290 |
| 249 } // namespace arc | 291 } // namespace arc |
| OLD | NEW |