app_info_permissions_panel.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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/ui/views/apps/app_info_dialog/app_info_permissions_panel.h"
6
7#include <string>
8#include <vector>
9
10#include "apps/app_load_service.h"
11#include "apps/app_restore_service.h"
12#include "apps/saved_files_service.h"
13#include "base/files/file_path.h"
14#include "extensions/common/extension.h"
15#include "extensions/common/permissions/api_permission.h"
16#include "extensions/common/permissions/permissions_data.h"
17#include "grit/generated_resources.h"
18#include "ui/base/l10n/l10n_util.h"
19#include "ui/views/controls/button/label_button.h"
20#include "ui/views/controls/label.h"
21#include "ui/views/layout/box_layout.h"
22#include "ui/views/layout/layout_constants.h"
23#include "ui/views/view.h"
24#include "ui/views/widget/widget.h"
25
26AppInfoPermissionsPanel::AppInfoPermissionsPanel(
27    Profile* profile,
28    const extensions::Extension* app)
29    : AppInfoPanel(profile, app),
30      active_permissions_heading_(NULL),
31      active_permissions_list_(NULL),
32      retained_files_heading_(NULL),
33      retained_files_list_(NULL),
34      revoke_file_permissions_button_(NULL) {
35  // Create UI elements.
36  CreateActivePermissionsControl();
37  CreateRetainedFilesControl();
38
39  // Layout elements.
40  SetLayoutManager(
41      new views::BoxLayout(views::BoxLayout::kVertical,
42                           0,
43                           0,
44                           views::kUnrelatedControlVerticalSpacing));
45
46  LayoutActivePermissionsControl();
47  LayoutRetainedFilesControl();
48}
49
50AppInfoPermissionsPanel::~AppInfoPermissionsPanel() {
51  // Destroy view children before their models.
52  RemoveAllChildViews(true);
53}
54
55// Given a list of strings, returns a view containing a list of these strings
56// as bulleted items.
57views::View* AppInfoPermissionsPanel::CreateBulletedListView(
58    const std::vector<base::string16>& messages) {
59  const int kSpacingBetweenBulletAndStartOfText = 5;
60  views::View* list_view = CreateVerticalStack();
61
62  for (std::vector<base::string16>::const_iterator it = messages.begin();
63       it != messages.end();
64       ++it) {
65    views::Label* permission_label = new views::Label(*it);
66    permission_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
67    permission_label->SetMultiLine(true);
68
69    // Extract only the bullet from the IDS_EXTENSION_PERMISSION_LINE text, and
70    // place it in it's own view so it doesn't align vertically with the
71    // multilined permissions text.
72    views::Label* bullet_label = new views::Label(l10n_util::GetStringFUTF16(
73        IDS_EXTENSION_PERMISSION_LINE, base::string16()));
74    views::View* bullet_label_top_aligned = CreateVerticalStack();
75    bullet_label_top_aligned->AddChildView(bullet_label);
76
77    // Place the bullet and the text so all permissions line up at the bullet.
78    views::View* bulleted_list_item = new views::View();
79    bulleted_list_item->SetLayoutManager(
80        new views::BoxLayout(views::BoxLayout::kHorizontal,
81                             0,
82                             0,
83                             kSpacingBetweenBulletAndStartOfText));
84    bulleted_list_item->AddChildView(bullet_label_top_aligned);
85    bulleted_list_item->AddChildView(permission_label);
86
87    list_view->AddChildView(bulleted_list_item);
88  }
89
90  return list_view;
91}
92
93void AppInfoPermissionsPanel::CreateActivePermissionsControl() {
94  std::vector<base::string16> permission_strings =
95      GetActivePermissionMessages();
96  if (permission_strings.empty()) {
97    views::Label* no_permissions_text = new views::Label(
98        l10n_util::GetStringUTF16(IDS_APPLICATION_INFO_NO_PERMISSIONS_TEXT));
99    no_permissions_text->SetHorizontalAlignment(gfx::ALIGN_LEFT);
100    active_permissions_list_ = no_permissions_text;
101  } else {
102    active_permissions_heading_ = CreateHeading(l10n_util::GetStringUTF16(
103        IDS_APPLICATION_INFO_ACTIVE_PERMISSIONS_TEXT));
104    active_permissions_list_ = CreateBulletedListView(permission_strings);
105  }
106}
107
108void AppInfoPermissionsPanel::CreateRetainedFilesControl() {
109  const std::vector<base::string16> retained_file_permission_messages =
110      GetRetainedFilePaths();
111
112  if (!retained_file_permission_messages.empty()) {
113    revoke_file_permissions_button_ = new views::LabelButton(
114        this,
115        l10n_util::GetStringUTF16(
116            IDS_APPLICATION_INFO_REVOKE_RETAINED_FILE_PERMISSIONS_BUTTON_TEXT));
117    revoke_file_permissions_button_->SetStyle(views::Button::STYLE_BUTTON);
118
119    retained_files_heading_ = CreateHeading(l10n_util::GetStringUTF16(
120        IDS_APPLICATION_INFO_RETAINED_FILE_PERMISSIONS_TEXT));
121    retained_files_list_ =
122        CreateBulletedListView(retained_file_permission_messages);
123  }
124}
125
126void AppInfoPermissionsPanel::LayoutActivePermissionsControl() {
127  if (active_permissions_list_) {
128    views::View* vertical_stack = CreateVerticalStack();
129    if (active_permissions_heading_)
130      vertical_stack->AddChildView(active_permissions_heading_);
131    vertical_stack->AddChildView(active_permissions_list_);
132
133    AddChildView(vertical_stack);
134  }
135}
136
137void AppInfoPermissionsPanel::LayoutRetainedFilesControl() {
138  if (retained_files_list_) {
139    DCHECK(retained_files_heading_);
140    DCHECK(revoke_file_permissions_button_);
141
142    // Add a sub-view so the revoke button is right-aligned.
143    views::View* right_aligned_button = new views::View();
144    views::BoxLayout* right_aligned_horizontal_layout =
145        new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0);
146    right_aligned_horizontal_layout->set_main_axis_alignment(
147        views::BoxLayout::MAIN_AXIS_ALIGNMENT_END);
148    right_aligned_button->SetLayoutManager(right_aligned_horizontal_layout);
149    right_aligned_button->AddChildView(revoke_file_permissions_button_);
150
151    views::View* vertical_stack = CreateVerticalStack();
152    vertical_stack->AddChildView(retained_files_heading_);
153    vertical_stack->AddChildView(retained_files_list_);
154    vertical_stack->AddChildView(right_aligned_button);
155
156    AddChildView(vertical_stack);
157  }
158}
159
160void AppInfoPermissionsPanel::ButtonPressed(views::Button* sender,
161                                            const ui::Event& event) {
162  if (sender == revoke_file_permissions_button_) {
163    RevokeFilePermissions();
164  } else {
165    NOTREACHED();
166  }
167}
168
169const std::vector<base::string16>
170AppInfoPermissionsPanel::GetActivePermissionMessages() const {
171  return app_->permissions_data()->GetPermissionMessageStrings();
172}
173
174const std::vector<base::string16>
175AppInfoPermissionsPanel::GetRetainedFilePaths() const {
176  std::vector<base::string16> retained_file_paths;
177  if (app_->permissions_data()->HasAPIPermission(
178          extensions::APIPermission::kFileSystem)) {
179    std::vector<apps::SavedFileEntry> retained_file_entries =
180        apps::SavedFilesService::Get(profile_)->GetAllFileEntries(app_->id());
181    for (std::vector<apps::SavedFileEntry>::const_iterator it =
182             retained_file_entries.begin();
183         it != retained_file_entries.end();
184         ++it) {
185      retained_file_paths.push_back(it->path.LossyDisplayName());
186    }
187  }
188  return retained_file_paths;
189}
190
191void AppInfoPermissionsPanel::RevokeFilePermissions() {
192  apps::SavedFilesService::Get(profile_)->ClearQueue(app_);
193
194  // TODO(benwells): Fix this to call something like
195  // AppLoadService::RestartApplicationIfRunning.
196  if (apps::AppRestoreService::Get(profile_)->IsAppRestorable(app_->id()))
197    apps::AppLoadService::Get(profile_)->RestartApplication(app_->id());
198
199  GetWidget()->Close();
200}
201