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/saved_files_service.h" 12 #include "base/files/file_path.h" 13 #include "chrome/grit/generated_resources.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 "ui/base/l10n/l10n_util.h" 18 #include "ui/views/controls/button/label_button.h" 19 #include "ui/views/controls/label.h" 20 #include "ui/views/layout/box_layout.h" 21 #include "ui/views/layout/grid_layout.h" 22 #include "ui/views/layout/layout_constants.h" 23 #include "ui/views/view.h" 24 #include "ui/views/widget/widget.h" 25 26 AppInfoPermissionsPanel::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 50 AppInfoPermissionsPanel::~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. 57 views::View* AppInfoPermissionsPanel::CreateBulletedListView( 58 const std::vector<base::string16>& messages, 59 bool allow_multiline, 60 gfx::ElideBehavior elide_behavior) { 61 const int kSpacingBetweenBulletAndStartOfText = 5; 62 63 views::View* list_view = new views::View(); 64 views::GridLayout* layout = new views::GridLayout(list_view); 65 list_view->SetLayoutManager(layout); 66 67 // Create 2 columns: one for the bullet, one for the bullet text. 68 static const int kColumnSetId = 1; 69 views::ColumnSet* column_set = layout->AddColumnSet(kColumnSetId); 70 column_set->AddColumn(views::GridLayout::FILL, 71 views::GridLayout::LEADING, 72 0, 73 views::GridLayout::USE_PREF, 74 0, 75 0); 76 column_set->AddPaddingColumn(0, kSpacingBetweenBulletAndStartOfText); 77 column_set->AddColumn(views::GridLayout::FILL, 78 views::GridLayout::LEADING, 79 1, 80 views::GridLayout::USE_PREF, 81 0, 82 0); 83 84 for (std::vector<base::string16>::const_iterator it = messages.begin(); 85 it != messages.end(); 86 ++it) { 87 views::Label* permission_label = new views::Label(*it); 88 permission_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 89 90 if (allow_multiline) 91 permission_label->SetMultiLine(true); 92 else 93 permission_label->SetElideBehavior(elide_behavior); 94 95 // Extract only the bullet from the IDS_EXTENSION_PERMISSION_LINE text. 96 views::Label* bullet_label = new views::Label(l10n_util::GetStringFUTF16( 97 IDS_EXTENSION_PERMISSION_LINE, base::string16())); 98 99 // Add a padding row before every item except the first 100 if (it != messages.begin()) 101 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 102 103 layout->StartRow(1, kColumnSetId); 104 layout->AddView(bullet_label); 105 layout->AddView(permission_label); 106 } 107 108 return list_view; 109 } 110 111 void AppInfoPermissionsPanel::CreateActivePermissionsControl() { 112 std::vector<base::string16> permission_strings = 113 GetActivePermissionMessages(); 114 if (permission_strings.empty()) { 115 views::Label* no_permissions_text = new views::Label( 116 l10n_util::GetStringUTF16(IDS_APPLICATION_INFO_NO_PERMISSIONS_TEXT)); 117 no_permissions_text->SetHorizontalAlignment(gfx::ALIGN_LEFT); 118 active_permissions_list_ = no_permissions_text; 119 } else { 120 active_permissions_heading_ = CreateHeading(l10n_util::GetStringUTF16( 121 IDS_APPLICATION_INFO_ACTIVE_PERMISSIONS_TEXT)); 122 active_permissions_list_ = 123 CreateBulletedListView(permission_strings, true, gfx::NO_ELIDE); 124 } 125 } 126 127 void AppInfoPermissionsPanel::CreateRetainedFilesControl() { 128 const std::vector<base::string16> retained_file_permission_messages = 129 GetRetainedFilePaths(); 130 131 if (!retained_file_permission_messages.empty()) { 132 revoke_file_permissions_button_ = new views::LabelButton( 133 this, 134 l10n_util::GetStringUTF16( 135 IDS_APPLICATION_INFO_REVOKE_RETAINED_FILE_PERMISSIONS_BUTTON_TEXT)); 136 revoke_file_permissions_button_->SetStyle(views::Button::STYLE_BUTTON); 137 138 retained_files_heading_ = CreateHeading(l10n_util::GetStringUTF16( 139 IDS_APPLICATION_INFO_RETAINED_FILE_PERMISSIONS_TEXT)); 140 retained_files_list_ = CreateBulletedListView( 141 retained_file_permission_messages, false, gfx::ELIDE_MIDDLE); 142 } 143 } 144 145 void AppInfoPermissionsPanel::LayoutActivePermissionsControl() { 146 if (active_permissions_list_) { 147 views::View* vertical_stack = CreateVerticalStack(); 148 if (active_permissions_heading_) 149 vertical_stack->AddChildView(active_permissions_heading_); 150 vertical_stack->AddChildView(active_permissions_list_); 151 152 AddChildView(vertical_stack); 153 } 154 } 155 156 void AppInfoPermissionsPanel::LayoutRetainedFilesControl() { 157 if (retained_files_list_) { 158 DCHECK(retained_files_heading_); 159 DCHECK(revoke_file_permissions_button_); 160 161 // Add a sub-view so the revoke button is right-aligned. 162 views::View* right_aligned_button = new views::View(); 163 views::BoxLayout* right_aligned_horizontal_layout = 164 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); 165 right_aligned_horizontal_layout->set_main_axis_alignment( 166 views::BoxLayout::MAIN_AXIS_ALIGNMENT_END); 167 right_aligned_button->SetLayoutManager(right_aligned_horizontal_layout); 168 right_aligned_button->AddChildView(revoke_file_permissions_button_); 169 170 views::View* vertical_stack = CreateVerticalStack(); 171 vertical_stack->AddChildView(retained_files_heading_); 172 vertical_stack->AddChildView(retained_files_list_); 173 vertical_stack->AddChildView(right_aligned_button); 174 175 AddChildView(vertical_stack); 176 } 177 } 178 179 void AppInfoPermissionsPanel::ButtonPressed(views::Button* sender, 180 const ui::Event& event) { 181 if (sender == revoke_file_permissions_button_) { 182 RevokeFilePermissions(); 183 } else { 184 NOTREACHED(); 185 } 186 } 187 188 const std::vector<base::string16> 189 AppInfoPermissionsPanel::GetActivePermissionMessages() const { 190 return app_->permissions_data()->GetPermissionMessageStrings(); 191 } 192 193 const std::vector<base::string16> 194 AppInfoPermissionsPanel::GetRetainedFilePaths() const { 195 std::vector<base::string16> retained_file_paths; 196 if (app_->permissions_data()->HasAPIPermission( 197 extensions::APIPermission::kFileSystem)) { 198 std::vector<apps::SavedFileEntry> retained_file_entries = 199 apps::SavedFilesService::Get(profile_)->GetAllFileEntries(app_->id()); 200 for (std::vector<apps::SavedFileEntry>::const_iterator it = 201 retained_file_entries.begin(); 202 it != retained_file_entries.end(); 203 ++it) { 204 retained_file_paths.push_back(it->path.LossyDisplayName()); 205 } 206 } 207 return retained_file_paths; 208 } 209 210 void AppInfoPermissionsPanel::RevokeFilePermissions() { 211 apps::SavedFilesService::Get(profile_)->ClearQueue(app_); 212 apps::AppLoadService::Get(profile_)->RestartApplicationIfRunning(app_->id()); 213 214 GetWidget()->Close(); 215 } 216