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