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