EME test page application.
[chromium-blink-merge.git] / chrome / browser / extensions / bundle_installer.cc
blob5b8e07c484d72a43852279a2434068a618393849
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.
5 #include "chrome/browser/extensions/bundle_installer.h"
7 #include <algorithm>
8 #include <string>
9 #include <vector>
11 #include "base/command_line.h"
12 #include "base/i18n/rtl.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "chrome/browser/extensions/crx_installer.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/browser_finder.h"
19 #include "chrome/browser/ui/browser_list.h"
20 #include "chrome/browser/ui/tabs/tab_strip_model.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "content/public/browser/web_contents.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/permissions/permission_set.h"
25 #include "extensions/common/permissions/permissions_data.h"
26 #include "grit/generated_resources.h"
27 #include "ui/base/l10n/l10n_util.h"
29 namespace extensions {
31 namespace {
33 enum AutoApproveForTest {
34 DO_NOT_SKIP = 0,
35 PROCEED,
36 ABORT
39 AutoApproveForTest g_auto_approve_for_test = DO_NOT_SKIP;
41 // Creates a dummy extension and sets the manifest's name to the item's
42 // localized name.
43 scoped_refptr<Extension> CreateDummyExtension(const BundleInstaller::Item& item,
44 base::DictionaryValue* manifest) {
45 // We require localized names so we can have nice error messages when we can't
46 // parse an extension manifest.
47 CHECK(!item.localized_name.empty());
49 std::string error;
50 return Extension::Create(base::FilePath(),
51 Manifest::INTERNAL,
52 *manifest,
53 Extension::NO_FLAGS,
54 item.id,
55 &error);
58 bool IsAppPredicate(scoped_refptr<const Extension> extension) {
59 return extension->is_app();
62 struct MatchIdFunctor {
63 explicit MatchIdFunctor(const std::string& id) : id(id) {}
64 bool operator()(scoped_refptr<const Extension> extension) {
65 return extension->id() == id;
67 std::string id;
70 // Holds the message IDs for BundleInstaller::GetHeadingTextFor.
71 const int kHeadingIds[3][4] = {
74 IDS_EXTENSION_BUNDLE_INSTALL_PROMPT_HEADING_EXTENSIONS,
75 IDS_EXTENSION_BUNDLE_INSTALL_PROMPT_HEADING_APPS,
76 IDS_EXTENSION_BUNDLE_INSTALL_PROMPT_HEADING_EXTENSION_APPS
80 IDS_EXTENSION_BUNDLE_INSTALLED_HEADING_EXTENSIONS,
81 IDS_EXTENSION_BUNDLE_INSTALLED_HEADING_APPS,
82 IDS_EXTENSION_BUNDLE_INSTALLED_HEADING_EXTENSION_APPS
86 } // namespace
88 // static
89 void BundleInstaller::SetAutoApproveForTesting(bool auto_approve) {
90 CHECK(CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType));
91 g_auto_approve_for_test = auto_approve ? PROCEED : ABORT;
94 BundleInstaller::Item::Item() : state(STATE_PENDING) {}
96 base::string16 BundleInstaller::Item::GetNameForDisplay() {
97 base::string16 name = base::UTF8ToUTF16(localized_name);
98 base::i18n::AdjustStringForLocaleDirection(&name);
99 return l10n_util::GetStringFUTF16(IDS_EXTENSION_PERMISSION_LINE, name);
102 BundleInstaller::BundleInstaller(Browser* browser,
103 const BundleInstaller::ItemList& items)
104 : approved_(false),
105 browser_(browser),
106 host_desktop_type_(browser->host_desktop_type()),
107 profile_(browser->profile()),
108 delegate_(NULL) {
109 BrowserList::AddObserver(this);
110 for (size_t i = 0; i < items.size(); ++i) {
111 items_[items[i].id] = items[i];
112 items_[items[i].id].state = Item::STATE_PENDING;
116 BundleInstaller::ItemList BundleInstaller::GetItemsWithState(
117 Item::State state) const {
118 ItemList list;
120 for (ItemMap::const_iterator i = items_.begin(); i != items_.end(); ++i) {
121 if (i->second.state == state)
122 list.push_back(i->second);
125 return list;
128 void BundleInstaller::PromptForApproval(Delegate* delegate) {
129 delegate_ = delegate;
131 AddRef(); // Balanced in ReportApproved() and ReportCanceled().
133 ParseManifests();
136 void BundleInstaller::CompleteInstall(content::WebContents* web_contents,
137 Delegate* delegate) {
138 CHECK(approved_);
140 delegate_ = delegate;
142 AddRef(); // Balanced in ReportComplete();
144 if (GetItemsWithState(Item::STATE_PENDING).empty()) {
145 ReportComplete();
146 return;
149 // Start each WebstoreInstaller.
150 for (ItemMap::iterator i = items_.begin(); i != items_.end(); ++i) {
151 if (i->second.state != Item::STATE_PENDING)
152 continue;
154 // Since we've already confirmed the permissions, create an approval that
155 // lets CrxInstaller bypass the prompt.
156 scoped_ptr<WebstoreInstaller::Approval> approval(
157 WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
158 profile_,
159 i->first,
160 scoped_ptr<base::DictionaryValue>(
161 parsed_manifests_[i->first]->DeepCopy()), true));
162 approval->use_app_installed_bubble = false;
163 approval->skip_post_install_ui = true;
165 scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
166 profile_,
167 this,
168 web_contents,
169 i->first,
170 approval.Pass(),
171 WebstoreInstaller::INSTALL_SOURCE_OTHER);
172 installer->Start();
176 base::string16 BundleInstaller::GetHeadingTextFor(Item::State state) const {
177 // For STATE_FAILED, we can't tell if the items were apps or extensions
178 // so we always show the same message.
179 if (state == Item::STATE_FAILED) {
180 if (GetItemsWithState(state).size())
181 return l10n_util::GetStringUTF16(IDS_EXTENSION_BUNDLE_ERROR_HEADING);
182 return base::string16();
185 size_t total = GetItemsWithState(state).size();
186 size_t apps = std::count_if(
187 dummy_extensions_.begin(), dummy_extensions_.end(), &IsAppPredicate);
189 bool has_apps = apps > 0;
190 bool has_extensions = apps < total;
191 size_t index = (has_extensions << 0) + (has_apps << 1);
193 CHECK_LT(static_cast<size_t>(state), arraysize(kHeadingIds));
194 CHECK_LT(index, arraysize(kHeadingIds[state]));
196 int msg_id = kHeadingIds[state][index];
197 if (!msg_id)
198 return base::string16();
200 return l10n_util::GetStringUTF16(msg_id);
203 BundleInstaller::~BundleInstaller() {
204 BrowserList::RemoveObserver(this);
207 void BundleInstaller::ParseManifests() {
208 if (items_.empty()) {
209 ReportCanceled(false);
210 return;
213 for (ItemMap::iterator i = items_.begin(); i != items_.end(); ++i) {
214 scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper(
215 this, i->first, i->second.manifest, std::string(), GURL(), NULL);
216 helper->Start();
220 void BundleInstaller::ReportApproved() {
221 if (delegate_)
222 delegate_->OnBundleInstallApproved();
224 Release(); // Balanced in PromptForApproval().
227 void BundleInstaller::ReportCanceled(bool user_initiated) {
228 if (delegate_)
229 delegate_->OnBundleInstallCanceled(user_initiated);
231 Release(); // Balanced in PromptForApproval().
234 void BundleInstaller::ReportComplete() {
235 if (delegate_)
236 delegate_->OnBundleInstallCompleted();
238 Release(); // Balanced in CompleteInstall().
241 void BundleInstaller::ShowPromptIfDoneParsing() {
242 // We don't prompt until all the manifests have been parsed.
243 ItemList pending_items = GetItemsWithState(Item::STATE_PENDING);
244 if (pending_items.size() != dummy_extensions_.size())
245 return;
247 ShowPrompt();
250 void BundleInstaller::ShowPrompt() {
251 // Abort if we couldn't create any Extensions out of the manifests.
252 if (dummy_extensions_.empty()) {
253 ReportCanceled(false);
254 return;
257 scoped_refptr<PermissionSet> permissions;
258 for (size_t i = 0; i < dummy_extensions_.size(); ++i) {
259 permissions = PermissionSet::CreateUnion(
260 permissions.get(),
261 PermissionsData::GetRequiredPermissions(dummy_extensions_[i].get()));
264 if (g_auto_approve_for_test == PROCEED) {
265 InstallUIProceed();
266 } else if (g_auto_approve_for_test == ABORT) {
267 InstallUIAbort(true);
268 } else {
269 Browser* browser = browser_;
270 if (!browser) {
271 // The browser that we got initially could have gone away during our
272 // thread hopping.
273 browser = chrome::FindLastActiveWithProfile(profile_, host_desktop_type_);
275 content::WebContents* web_contents = NULL;
276 if (browser)
277 web_contents = browser->tab_strip_model()->GetActiveWebContents();
278 install_ui_.reset(new ExtensionInstallPrompt(web_contents));
279 install_ui_->ConfirmBundleInstall(this, permissions.get());
283 void BundleInstaller::ShowInstalledBubbleIfDone() {
284 // We're ready to show the installed bubble when no items are pending.
285 if (!GetItemsWithState(Item::STATE_PENDING).empty())
286 return;
288 if (browser_)
289 ShowInstalledBubble(this, browser_);
291 ReportComplete();
294 void BundleInstaller::OnWebstoreParseSuccess(
295 const std::string& id,
296 const SkBitmap& icon,
297 base::DictionaryValue* manifest) {
298 dummy_extensions_.push_back(CreateDummyExtension(items_[id], manifest));
299 parsed_manifests_[id] = linked_ptr<base::DictionaryValue>(manifest);
301 ShowPromptIfDoneParsing();
304 void BundleInstaller::OnWebstoreParseFailure(
305 const std::string& id,
306 WebstoreInstallHelper::Delegate::InstallHelperResultCode result_code,
307 const std::string& error_message) {
308 items_[id].state = Item::STATE_FAILED;
310 ShowPromptIfDoneParsing();
313 void BundleInstaller::InstallUIProceed() {
314 approved_ = true;
315 ReportApproved();
318 void BundleInstaller::InstallUIAbort(bool user_initiated) {
319 for (ItemMap::iterator i = items_.begin(); i != items_.end(); ++i)
320 i->second.state = Item::STATE_FAILED;
322 ReportCanceled(user_initiated);
325 void BundleInstaller::OnExtensionInstallSuccess(const std::string& id) {
326 items_[id].state = Item::STATE_INSTALLED;
328 ShowInstalledBubbleIfDone();
331 void BundleInstaller::OnExtensionInstallFailure(
332 const std::string& id,
333 const std::string& error,
334 WebstoreInstaller::FailureReason reason) {
335 items_[id].state = Item::STATE_FAILED;
337 ExtensionList::iterator i = std::find_if(
338 dummy_extensions_.begin(), dummy_extensions_.end(), MatchIdFunctor(id));
339 CHECK(dummy_extensions_.end() != i);
340 dummy_extensions_.erase(i);
342 ShowInstalledBubbleIfDone();
345 void BundleInstaller::OnBrowserAdded(Browser* browser) {}
347 void BundleInstaller::OnBrowserRemoved(Browser* browser) {
348 if (browser_ == browser)
349 browser_ = NULL;
352 void BundleInstaller::OnBrowserSetLastActive(Browser* browser) {}
354 } // namespace extensions