app_list_view_delegate.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
1// Copyright (c) 2012 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/ui/app_list/app_list_view_delegate.h"
6
7#include <vector>
8
9#include "base/callback.h"
10#include "base/files/file_path.h"
11#include "base/stl_util.h"
12#include "chrome/browser/browser_process.h"
13#include "chrome/browser/chrome_notification_types.h"
14#include "chrome/browser/extensions/extension_service.h"
15#include "chrome/browser/feedback/feedback_util.h"
16#include "chrome/browser/profiles/profile_info_cache.h"
17#include "chrome/browser/profiles/profile_manager.h"
18#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
19#include "chrome/browser/ui/app_list/app_list_service.h"
20#include "chrome/browser/ui/app_list/app_list_syncable_service.h"
21#include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
22#include "chrome/browser/ui/app_list/search/search_controller.h"
23#include "chrome/browser/ui/app_list/start_page_service.h"
24#include "chrome/browser/ui/browser_finder.h"
25#include "chrome/browser/ui/chrome_pages.h"
26#include "chrome/browser/ui/host_desktop.h"
27#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
28#include "chrome/browser/ui/web_applications/web_app_ui.h"
29#include "chrome/browser/web_applications/web_app.h"
30#include "chrome/common/extensions/extension_constants.h"
31#include "chrome/common/url_constants.h"
32#include "content/public/browser/browser_thread.h"
33#include "content/public/browser/notification_service.h"
34#include "content/public/browser/notification_source.h"
35#include "content/public/browser/page_navigator.h"
36#include "content/public/browser/user_metrics.h"
37#include "ui/app_list/app_list_view_delegate_observer.h"
38#include "ui/app_list/search_box_model.h"
39#include "ui/app_list/speech_ui_model.h"
40
41#if defined(USE_ASH)
42#include "chrome/browser/ui/ash/app_list/app_sync_ui_state_watcher.h"
43#endif
44
45#if defined(OS_WIN)
46#include "chrome/browser/web_applications/web_app_win.h"
47#endif
48
49namespace {
50
51#if defined(OS_WIN)
52void CreateShortcutInWebAppDir(
53    const base::FilePath& app_data_dir,
54    base::Callback<void(const base::FilePath&)> callback,
55    const ShellIntegration::ShortcutInfo& info) {
56  content::BrowserThread::PostTaskAndReplyWithResult(
57      content::BrowserThread::FILE,
58      FROM_HERE,
59      base::Bind(web_app::CreateShortcutInWebAppDir, app_data_dir, info),
60      callback);
61}
62#endif
63
64void PopulateUsers(const ProfileInfoCache& profile_info,
65                   const base::FilePath& active_profile_path,
66                   app_list::AppListViewDelegate::Users* users) {
67  users->clear();
68  const size_t count = profile_info.GetNumberOfProfiles();
69  for (size_t i = 0; i < count; ++i) {
70    // Don't display managed users.
71    if (profile_info.ProfileIsManagedAtIndex(i))
72      continue;
73
74    app_list::AppListViewDelegate::User user;
75    user.name = profile_info.GetNameOfProfileAtIndex(i);
76    user.email = profile_info.GetUserNameOfProfileAtIndex(i);
77    user.profile_path = profile_info.GetPathOfProfileAtIndex(i);
78    user.active = active_profile_path == user.profile_path;
79    users->push_back(user);
80  }
81}
82
83}  // namespace
84
85AppListViewDelegate::AppListViewDelegate(Profile* profile,
86                                         AppListControllerDelegate* controller)
87    : controller_(controller),
88      profile_(profile),
89      model_(NULL) {
90  CHECK(controller_);
91  RegisterForNotifications();
92  g_browser_process->profile_manager()->GetProfileInfoCache().AddObserver(this);
93  OnProfileChanged();  // sets model_
94  app_list::StartPageService* service =
95      app_list::StartPageService::Get(profile_);
96  if (service)
97    service->AddObserver(this);
98}
99
100AppListViewDelegate::~AppListViewDelegate() {
101  app_list::StartPageService* service =
102      app_list::StartPageService::Get(profile_);
103  if (service)
104    service->RemoveObserver(this);
105  g_browser_process->
106      profile_manager()->GetProfileInfoCache().RemoveObserver(this);
107}
108
109void AppListViewDelegate::RegisterForNotifications() {
110  registrar_.RemoveAll();
111  DCHECK(profile_);
112
113  registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
114                 content::NotificationService::AllSources());
115  registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED,
116                 content::NotificationService::AllSources());
117  registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
118                 content::NotificationService::AllSources());
119}
120
121void AppListViewDelegate::OnProfileChanged() {
122  model_ = app_list::AppListSyncableServiceFactory::GetForProfile(
123      profile_)->model();
124
125  search_controller_.reset(new app_list::SearchController(
126      profile_, model_->search_box(), model_->results(), controller_));
127
128  signin_delegate_.SetProfile(profile_);
129
130#if defined(USE_ASH)
131  app_sync_ui_state_watcher_.reset(new AppSyncUIStateWatcher(profile_, model_));
132#endif
133
134  // Don't populate the app list users if we are on the ash desktop.
135  chrome::HostDesktopType desktop = chrome::GetHostDesktopTypeForNativeWindow(
136      controller_->GetAppListWindow());
137  if (desktop == chrome::HOST_DESKTOP_TYPE_ASH)
138    return;
139
140  // Populate the app list users.
141  PopulateUsers(g_browser_process->profile_manager()->GetProfileInfoCache(),
142                profile_->GetPath(), &users_);
143
144  FOR_EACH_OBSERVER(app_list::AppListViewDelegateObserver,
145                    observers_,
146                    OnProfilesChanged());
147}
148
149bool AppListViewDelegate::ForceNativeDesktop() const {
150  return controller_->ForceNativeDesktop();
151}
152
153void AppListViewDelegate::SetProfileByPath(const base::FilePath& profile_path) {
154  DCHECK(model_);
155
156  // The profile must be loaded before this is called.
157  profile_ =
158      g_browser_process->profile_manager()->GetProfileByPath(profile_path);
159  DCHECK(profile_);
160
161  RegisterForNotifications();
162
163  OnProfileChanged();
164
165  // Clear search query.
166  model_->search_box()->SetText(base::string16());
167}
168
169app_list::AppListModel* AppListViewDelegate::GetModel() {
170  return model_;
171}
172
173app_list::SigninDelegate* AppListViewDelegate::GetSigninDelegate() {
174  return &signin_delegate_;
175}
176
177app_list::SpeechUIModel* AppListViewDelegate::GetSpeechUI() {
178  return &speech_ui_;
179}
180
181void AppListViewDelegate::GetShortcutPathForApp(
182    const std::string& app_id,
183    const base::Callback<void(const base::FilePath&)>& callback) {
184#if defined(OS_WIN)
185  ExtensionService* service = profile_->GetExtensionService();
186  DCHECK(service);
187  const extensions::Extension* extension =
188      service->GetInstalledExtension(app_id);
189  if (!extension) {
190    callback.Run(base::FilePath());
191    return;
192  }
193
194  base::FilePath app_data_dir(
195      web_app::GetWebAppDataDirectory(profile_->GetPath(),
196                                      extension->id(),
197                                      GURL()));
198
199  web_app::UpdateShortcutInfoAndIconForApp(
200      *extension,
201      profile_,
202      base::Bind(CreateShortcutInWebAppDir, app_data_dir, callback));
203#else
204  callback.Run(base::FilePath());
205#endif
206}
207
208void AppListViewDelegate::StartSearch() {
209  if (search_controller_)
210    search_controller_->Start();
211}
212
213void AppListViewDelegate::StopSearch() {
214  if (search_controller_)
215    search_controller_->Stop();
216}
217
218void AppListViewDelegate::OpenSearchResult(
219    app_list::SearchResult* result,
220    int event_flags) {
221  search_controller_->OpenResult(result, event_flags);
222}
223
224void AppListViewDelegate::InvokeSearchResultAction(
225    app_list::SearchResult* result,
226    int action_index,
227    int event_flags) {
228  search_controller_->InvokeResultAction(result, action_index, event_flags);
229}
230
231void AppListViewDelegate::Dismiss()  {
232  controller_->DismissView();
233}
234
235void AppListViewDelegate::ViewClosing() {
236  controller_->ViewClosing();
237}
238
239gfx::ImageSkia AppListViewDelegate::GetWindowIcon() {
240  return controller_->GetWindowIcon();
241}
242
243void AppListViewDelegate::OpenSettings() {
244  ExtensionService* service = profile_->GetExtensionService();
245  DCHECK(service);
246  const extensions::Extension* extension = service->GetInstalledExtension(
247      extension_misc::kSettingsAppId);
248  DCHECK(extension);
249  controller_->ActivateApp(profile_,
250                           extension,
251                           AppListControllerDelegate::LAUNCH_FROM_UNKNOWN,
252                           0);
253}
254
255void AppListViewDelegate::OpenHelp() {
256  chrome::HostDesktopType desktop = chrome::GetHostDesktopTypeForNativeWindow(
257      controller_->GetAppListWindow());
258  chrome::ScopedTabbedBrowserDisplayer displayer(profile_, desktop);
259  content::OpenURLParams params(GURL(chrome::kAppLauncherHelpURL),
260                                content::Referrer(),
261                                NEW_FOREGROUND_TAB,
262                                content::PAGE_TRANSITION_LINK,
263                                false);
264  displayer.browser()->OpenURL(params);
265}
266
267void AppListViewDelegate::OpenFeedback() {
268  chrome::HostDesktopType desktop = chrome::GetHostDesktopTypeForNativeWindow(
269      controller_->GetAppListWindow());
270  Browser* browser = chrome::FindTabbedBrowser(profile_, false, desktop);
271  chrome::ShowFeedbackPage(browser, std::string(),
272                           chrome::kAppLauncherCategoryTag);
273}
274
275void AppListViewDelegate::ToggleSpeechRecognition() {
276  app_list::StartPageService* service =
277      app_list::StartPageService::Get(profile_);
278  if (service)
279    service->ToggleSpeechRecognition();
280}
281
282void AppListViewDelegate::ShowForProfileByPath(
283    const base::FilePath& profile_path) {
284  controller_->ShowForProfileByPath(profile_path);
285}
286
287void AppListViewDelegate::OnSpeechResult(const base::string16& result,
288                                         bool is_final) {
289  speech_ui_.SetSpeechResult(result, is_final);
290  if (is_final)
291    model_->search_box()->SetText(result);
292}
293
294void AppListViewDelegate::OnSpeechSoundLevelChanged(int16 level) {
295  speech_ui_.UpdateSoundLevel(level);
296}
297
298void AppListViewDelegate::OnSpeechRecognitionStateChanged(
299    app_list::SpeechRecognitionState new_state) {
300  speech_ui_.SetSpeechRecognitionState(new_state);
301}
302
303void AppListViewDelegate::Observe(
304    int type,
305    const content::NotificationSource& source,
306    const content::NotificationDetails& details) {
307  OnProfileChanged();
308}
309
310void AppListViewDelegate::OnProfileAdded(const base::FilePath& profile_path) {
311  OnProfileChanged();
312}
313
314void AppListViewDelegate::OnProfileWasRemoved(
315    const base::FilePath& profile_path, const base::string16& profile_name) {
316  OnProfileChanged();
317}
318
319void AppListViewDelegate::OnProfileNameChanged(
320    const base::FilePath& profile_path,
321    const base::string16& old_profile_name) {
322  OnProfileChanged();
323}
324
325content::WebContents* AppListViewDelegate::GetStartPageContents() {
326  app_list::StartPageService* service =
327      app_list::StartPageService::Get(profile_);
328  if (!service)
329    return NULL;
330
331  return service->contents();
332}
333
334const app_list::AppListViewDelegate::Users&
335AppListViewDelegate::GetUsers() const {
336  return users_;
337}
338
339void AppListViewDelegate::AddObserver(
340    app_list::AppListViewDelegateObserver* observer) {
341  observers_.AddObserver(observer);
342}
343
344void AppListViewDelegate::RemoveObserver(
345    app_list::AppListViewDelegateObserver* observer) {
346  observers_.RemoveObserver(observer);
347}
348