1 // Copyright 2013 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/search/app_result.h" 6 7 #include "chrome/browser/extensions/extension_service.h" 8 #include "chrome/browser/extensions/extension_util.h" 9 #include "chrome/browser/profiles/profile.h" 10 #include "chrome/browser/ui/app_list/app_context_menu.h" 11 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h" 12 #include "chrome/browser/ui/app_list/search/tokenized_string.h" 13 #include "chrome/browser/ui/app_list/search/tokenized_string_match.h" 14 #include "chrome/browser/ui/extensions/extension_enable_flow.h" 15 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h" 16 #include "content/public/browser/user_metrics.h" 17 #include "extensions/browser/extension_registry.h" 18 #include "extensions/browser/extension_system.h" 19 #include "extensions/browser/extension_system_provider.h" 20 #include "extensions/browser/extensions_browser_client.h" 21 #include "extensions/common/constants.h" 22 #include "extensions/common/extension.h" 23 #include "extensions/common/extension_icon_set.h" 24 #include "extensions/common/manifest_handlers/icons_handler.h" 25 #include "ui/gfx/color_utils.h" 26 #include "ui/gfx/image/image_skia_operations.h" 27 28 namespace app_list { 29 30 AppResult::AppResult(Profile* profile, 31 const std::string& app_id, 32 AppListControllerDelegate* controller) 33 : profile_(profile), 34 app_id_(app_id), 35 controller_(controller), 36 extension_registry_(NULL) { 37 set_id(extensions::Extension::GetBaseURLFromExtensionId(app_id_).spec()); 38 39 const extensions::Extension* extension = 40 extensions::ExtensionSystem::Get(profile_)->extension_service() 41 ->GetInstalledExtension(app_id_); 42 DCHECK(extension); 43 44 is_platform_app_ = extension->is_platform_app(); 45 46 icon_.reset(new extensions::IconImage( 47 profile_, 48 extension, 49 extensions::IconsInfo::GetIcons(extension), 50 extension_misc::EXTENSION_ICON_SMALL, 51 extensions::util::GetDefaultAppIcon(), 52 this)); 53 UpdateIcon(); 54 55 StartObservingExtensionRegistry(); 56 } 57 58 AppResult::~AppResult() { 59 StopObservingExtensionRegistry(); 60 } 61 62 void AppResult::UpdateFromMatch(const TokenizedString& title, 63 const TokenizedStringMatch& match) { 64 const TokenizedStringMatch::Hits& hits = match.hits(); 65 66 Tags tags; 67 tags.reserve(hits.size()); 68 for (size_t i = 0; i < hits.size(); ++i) 69 tags.push_back(Tag(Tag::MATCH, hits[i].start(), hits[i].end())); 70 71 set_title(title.text()); 72 set_title_tags(tags); 73 set_relevance(match.relevance()); 74 } 75 76 void AppResult::Open(int event_flags) { 77 const extensions::Extension* extension = 78 extensions::ExtensionSystem::Get(profile_)->extension_service() 79 ->GetInstalledExtension(app_id_); 80 if (!extension) 81 return; 82 83 // Check if enable flow is already running or should be started 84 if (RunExtensionEnableFlow()) 85 return; 86 87 CoreAppLauncherHandler::RecordAppListSearchLaunch(extension); 88 content::RecordAction( 89 base::UserMetricsAction("AppList_ClickOnAppFromSearch")); 90 91 controller_->ActivateApp( 92 profile_, 93 extension, 94 AppListControllerDelegate::LAUNCH_FROM_APP_LIST_SEARCH, 95 event_flags); 96 } 97 98 void AppResult::InvokeAction(int action_index, int event_flags) {} 99 100 scoped_ptr<ChromeSearchResult> AppResult::Duplicate() { 101 scoped_ptr<ChromeSearchResult> copy( 102 new AppResult(profile_, app_id_, controller_)); 103 copy->set_title(title()); 104 copy->set_title_tags(title_tags()); 105 106 return copy.Pass(); 107 } 108 109 ChromeSearchResultType AppResult::GetType() { 110 return APP_SEARCH_RESULT; 111 } 112 113 ui::MenuModel* AppResult::GetContextMenuModel() { 114 if (!context_menu_) { 115 context_menu_.reset(new AppContextMenu( 116 this, profile_, app_id_, controller_)); 117 context_menu_->set_is_platform_app(is_platform_app_); 118 context_menu_->set_is_search_result(true); 119 } 120 121 return context_menu_->GetMenuModel(); 122 } 123 124 void AppResult::StartObservingExtensionRegistry() { 125 DCHECK(!extension_registry_); 126 127 extension_registry_ = extensions::ExtensionRegistry::Get(profile_); 128 extension_registry_->AddObserver(this); 129 } 130 131 void AppResult::StopObservingExtensionRegistry() { 132 if (extension_registry_) 133 extension_registry_->RemoveObserver(this); 134 extension_registry_ = NULL; 135 } 136 137 bool AppResult::RunExtensionEnableFlow() { 138 if (extensions::util::IsAppLaunchableWithoutEnabling(app_id_, profile_)) 139 return false; 140 141 if (!extension_enable_flow_) { 142 controller_->OnShowChildDialog(); 143 144 extension_enable_flow_.reset(new ExtensionEnableFlow( 145 profile_, app_id_, this)); 146 extension_enable_flow_->StartForNativeWindow( 147 controller_->GetAppListWindow()); 148 } 149 return true; 150 } 151 152 void AppResult::UpdateIcon() { 153 gfx::ImageSkia icon = icon_->image_skia(); 154 155 if (!extensions::util::IsAppLaunchable(app_id_, profile_)) { 156 const color_utils::HSL shift = {-1, 0, 0.6}; 157 icon = gfx::ImageSkiaOperations::CreateHSLShiftedImage(icon, shift); 158 } 159 160 SetIcon(icon); 161 } 162 163 void AppResult::OnExtensionIconImageChanged(extensions::IconImage* image) { 164 DCHECK_EQ(icon_.get(), image); 165 UpdateIcon(); 166 } 167 168 void AppResult::ExecuteLaunchCommand(int event_flags) { 169 Open(event_flags); 170 } 171 172 void AppResult::ExtensionEnableFlowFinished() { 173 extension_enable_flow_.reset(); 174 controller_->OnCloseChildDialog(); 175 176 // Automatically open app after enabling. 177 Open(ui::EF_NONE); 178 } 179 180 void AppResult::ExtensionEnableFlowAborted(bool user_initiated) { 181 extension_enable_flow_.reset(); 182 controller_->OnCloseChildDialog(); 183 } 184 185 void AppResult::OnExtensionLoaded(content::BrowserContext* browser_context, 186 const extensions::Extension* extension) { 187 UpdateIcon(); 188 } 189 190 void AppResult::OnExtensionUninstalled(content::BrowserContext* browser_context, 191 const extensions::Extension* extension) { 192 if (extension->id() != app_id_) 193 return; 194 195 NotifyItemUninstalled(); 196 } 197 198 void AppResult::OnShutdown(extensions::ExtensionRegistry* registry) { 199 DCHECK_EQ(extension_registry_, registry); 200 StopObservingExtensionRegistry(); 201 } 202 203 } // namespace app_list 204