1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/android/dev_tools_manager_delegate_android.h" 6 7#include "base/basictypes.h" 8#include "base/compiler_specific.h" 9#include "base/strings/string_number_conversions.h" 10#include "base/strings/utf_string_conversions.h" 11#include "chrome/browser/android/tab_android.h" 12#include "chrome/browser/browser_process.h" 13#include "chrome/browser/history/top_sites.h" 14#include "chrome/browser/profiles/profile_manager.h" 15#include "chrome/browser/ui/android/tab_model/tab_model.h" 16#include "chrome/browser/ui/android/tab_model/tab_model_list.h" 17#include "content/public/browser/devtools_agent_host.h" 18#include "content/public/browser/devtools_target.h" 19#include "content/public/browser/favicon_status.h" 20#include "content/public/browser/navigation_entry.h" 21#include "content/public/browser/web_contents.h" 22 23using content::DevToolsAgentHost; 24using content::WebContents; 25 26namespace { 27 28const char kTargetTypePage[] = "page"; 29const char kTargetTypeServiceWorker[] = "service_worker"; 30const char kTargetTypeOther[] = "other"; 31 32GURL GetFaviconURLForContents(WebContents* web_contents) { 33 content::NavigationController& controller = web_contents->GetController(); 34 content::NavigationEntry* entry = controller.GetActiveEntry(); 35 if (entry != NULL && entry->GetURL().is_valid()) 36 return entry->GetFavicon().url; 37 return GURL(); 38} 39 40GURL GetFaviconURLForAgentHost( 41 scoped_refptr<DevToolsAgentHost> agent_host) { 42 if (WebContents* web_contents = agent_host->GetWebContents()) 43 return GetFaviconURLForContents(web_contents); 44 return GURL(); 45} 46 47base::TimeTicks GetLastActiveTimeForAgentHost( 48 scoped_refptr<DevToolsAgentHost> agent_host) { 49 if (WebContents* web_contents = agent_host->GetWebContents()) 50 return web_contents->GetLastActiveTime(); 51 return base::TimeTicks(); 52} 53 54class TargetBase : public content::DevToolsTarget { 55 public: 56 // content::DevToolsTarget implementation: 57 virtual std::string GetParentId() const OVERRIDE { return std::string(); } 58 59 virtual std::string GetTitle() const OVERRIDE { return title_; } 60 61 virtual std::string GetDescription() const OVERRIDE { return std::string(); } 62 63 virtual GURL GetURL() const OVERRIDE { return url_; } 64 65 virtual GURL GetFaviconURL() const OVERRIDE { return favicon_url_; } 66 67 virtual base::TimeTicks GetLastActivityTime() const OVERRIDE { 68 return last_activity_time_; 69 } 70 71 protected: 72 explicit TargetBase(WebContents* web_contents) 73 : title_(base::UTF16ToUTF8(web_contents->GetTitle())), 74 url_(web_contents->GetURL()), 75 favicon_url_(GetFaviconURLForContents(web_contents)), 76 last_activity_time_(web_contents->GetLastActiveTime()) { 77 } 78 79 explicit TargetBase(scoped_refptr<DevToolsAgentHost> agent_host) 80 : title_(agent_host->GetTitle()), 81 url_(agent_host->GetURL()), 82 favicon_url_(GetFaviconURLForAgentHost(agent_host)), 83 last_activity_time_(GetLastActiveTimeForAgentHost(agent_host)) { 84 } 85 86 TargetBase(const std::string& title, const GURL& url) 87 : title_(title), 88 url_(url) { 89 } 90 91 private: 92 const std::string title_; 93 const GURL url_; 94 const GURL favicon_url_; 95 const base::TimeTicks last_activity_time_; 96}; 97 98class TabTarget : public TargetBase { 99 public: 100 static TabTarget* CreateForWebContents(int tab_id, 101 WebContents* web_contents) { 102 return new TabTarget(tab_id, web_contents); 103 } 104 105 static TabTarget* CreateForUnloadedTab(int tab_id, 106 const base::string16& title, 107 const GURL& url) { 108 return new TabTarget(tab_id, title, url); 109 } 110 111 // content::DevToolsTarget implementation: 112 virtual std::string GetId() const OVERRIDE { 113 return base::IntToString(tab_id_); 114 } 115 116 virtual std::string GetType() const OVERRIDE { 117 return kTargetTypePage; 118 } 119 120 virtual bool IsAttached() const OVERRIDE { 121 TabModel* model; 122 int index; 123 if (!FindTab(&model, &index)) 124 return false; 125 WebContents* web_contents = model->GetWebContentsAt(index); 126 if (!web_contents) 127 return false; 128 return DevToolsAgentHost::IsDebuggerAttached(web_contents); 129 } 130 131 virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const OVERRIDE { 132 TabModel* model; 133 int index; 134 if (!FindTab(&model, &index)) 135 return NULL; 136 WebContents* web_contents = model->GetWebContentsAt(index); 137 if (!web_contents) { 138 // The tab has been pushed out of memory, pull it back. 139 TabAndroid* tab = model->GetTabAt(index); 140 if (!tab) 141 return NULL; 142 143 if (!tab->LoadIfNeeded()) 144 return NULL; 145 146 web_contents = model->GetWebContentsAt(index); 147 if (!web_contents) 148 return NULL; 149 } 150 return DevToolsAgentHost::GetOrCreateFor(web_contents); 151 } 152 153 virtual bool Activate() const OVERRIDE { 154 TabModel* model; 155 int index; 156 if (!FindTab(&model, &index)) 157 return false; 158 model->SetActiveIndex(index); 159 return true; 160 } 161 162 virtual bool Close() const OVERRIDE { 163 TabModel* model; 164 int index; 165 if (!FindTab(&model, &index)) 166 return false; 167 model->CloseTabAt(index); 168 return true; 169 } 170 171 private: 172 TabTarget(int tab_id, WebContents* web_contents) 173 : TargetBase(web_contents), 174 tab_id_(tab_id) { 175 } 176 177 TabTarget(int tab_id, const base::string16& title, const GURL& url) 178 : TargetBase(base::UTF16ToUTF8(title), url), 179 tab_id_(tab_id) { 180 } 181 182 bool FindTab(TabModel** model_result, int* index_result) const { 183 for (TabModelList::const_iterator iter = TabModelList::begin(); 184 iter != TabModelList::end(); ++iter) { 185 TabModel* model = *iter; 186 for (int i = 0; i < model->GetTabCount(); ++i) { 187 TabAndroid* tab = model->GetTabAt(i); 188 if (tab && tab->GetAndroidId() == tab_id_) { 189 *model_result = model; 190 *index_result = i; 191 return true; 192 } 193 } 194 } 195 return false; 196 } 197 198 const int tab_id_; 199}; 200 201class NonTabTarget : public TargetBase { 202 public: 203 explicit NonTabTarget(scoped_refptr<DevToolsAgentHost> agent_host) 204 : TargetBase(agent_host), 205 agent_host_(agent_host) { 206 } 207 208 // content::DevToolsTarget implementation: 209 virtual std::string GetId() const OVERRIDE { 210 return agent_host_->GetId(); 211 } 212 213 virtual std::string GetType() const OVERRIDE { 214 switch (agent_host_->GetType()) { 215 case DevToolsAgentHost::TYPE_WEB_CONTENTS: 216 if (TabModelList::begin() == TabModelList::end()) { 217 // If there are no tab models we must be running in ChromeShell. 218 // Return the 'page' target type for backwards compatibility. 219 return kTargetTypePage; 220 } 221 break; 222 case DevToolsAgentHost::TYPE_SERVICE_WORKER: 223 return kTargetTypeServiceWorker; 224 default: 225 break; 226 } 227 return kTargetTypeOther; 228 } 229 230 virtual bool IsAttached() const OVERRIDE { 231 return agent_host_->IsAttached(); 232 } 233 234 virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const OVERRIDE { 235 return agent_host_; 236 } 237 238 virtual bool Activate() const OVERRIDE { 239 return agent_host_->Activate(); 240 } 241 242 virtual bool Close() const OVERRIDE { 243 return agent_host_->Close(); 244 } 245 246 private: 247 scoped_refptr<DevToolsAgentHost> agent_host_; 248}; 249 250} // namespace 251 252DevToolsManagerDelegateAndroid::DevToolsManagerDelegateAndroid() 253 : network_protocol_handler_(new DevToolsNetworkProtocolHandler()) { 254} 255 256DevToolsManagerDelegateAndroid::~DevToolsManagerDelegateAndroid() { 257} 258 259void DevToolsManagerDelegateAndroid::Inspect( 260 content::BrowserContext* browser_context, 261 content::DevToolsAgentHost* agent_host) { 262} 263 264base::DictionaryValue* DevToolsManagerDelegateAndroid::HandleCommand( 265 content::DevToolsAgentHost* agent_host, 266 base::DictionaryValue* command_dict) { 267 return network_protocol_handler_->HandleCommand(agent_host, command_dict); 268} 269 270void DevToolsManagerDelegateAndroid::DevToolsAgentStateChanged( 271 content::DevToolsAgentHost* agent_host, 272 bool attached) { 273 network_protocol_handler_->DevToolsAgentStateChanged(agent_host, attached); 274} 275 276scoped_ptr<content::DevToolsTarget> 277 DevToolsManagerDelegateAndroid::CreateNewTarget(const GURL& url) { 278 if (TabModelList::empty()) 279 return scoped_ptr<content::DevToolsTarget>(); 280 281 TabModel* tab_model = TabModelList::get(0); 282 if (!tab_model) 283 return scoped_ptr<content::DevToolsTarget>(); 284 285 WebContents* web_contents = tab_model->CreateNewTabForDevTools(url); 286 if (!web_contents) 287 return scoped_ptr<content::DevToolsTarget>(); 288 289 TabAndroid* tab = TabAndroid::FromWebContents(web_contents); 290 if (!tab) 291 return scoped_ptr<content::DevToolsTarget>(); 292 293 return scoped_ptr<content::DevToolsTarget>( 294 TabTarget::CreateForWebContents(tab->GetAndroidId(), web_contents)); 295} 296 297void DevToolsManagerDelegateAndroid::EnumerateTargets(TargetCallback callback) { 298 TargetList targets; 299 300 // Enumerate existing tabs, including the ones with no WebContents. 301 std::set<WebContents*> tab_web_contents; 302 for (TabModelList::const_iterator iter = TabModelList::begin(); 303 iter != TabModelList::end(); ++iter) { 304 TabModel* model = *iter; 305 for (int i = 0; i < model->GetTabCount(); ++i) { 306 TabAndroid* tab = model->GetTabAt(i); 307 if (!tab) 308 continue; 309 310 WebContents* web_contents = model->GetWebContentsAt(i); 311 if (web_contents) { 312 tab_web_contents.insert(web_contents); 313 targets.push_back(TabTarget::CreateForWebContents(tab->GetAndroidId(), 314 web_contents)); 315 } else { 316 targets.push_back(TabTarget::CreateForUnloadedTab(tab->GetAndroidId(), 317 tab->GetTitle(), 318 tab->GetURL())); 319 } 320 } 321 } 322 323 // Add targets for WebContents not associated with any tabs. 324 DevToolsAgentHost::List agents = DevToolsAgentHost::GetOrCreateAll(); 325 for (DevToolsAgentHost::List::iterator it = agents.begin(); 326 it != agents.end(); ++it) { 327 if (WebContents* web_contents = (*it)->GetWebContents()) { 328 if (tab_web_contents.find(web_contents) != tab_web_contents.end()) 329 continue; 330 } 331 targets.push_back(new NonTabTarget(*it)); 332 } 333 334 callback.Run(targets); 335} 336 337std::string DevToolsManagerDelegateAndroid::GetPageThumbnailData( 338 const GURL& url) { 339 Profile* profile = ProfileManager::GetLastUsedProfile()->GetOriginalProfile(); 340 history::TopSites* top_sites = profile->GetTopSites(); 341 if (top_sites) { 342 scoped_refptr<base::RefCountedMemory> data; 343 if (top_sites->GetPageThumbnail(url, false, &data)) 344 return std::string(data->front_as<char>(), data->size()); 345 } 346 return std::string(); 347} 348