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.
5 #include "chrome/browser/media/protected_media_identifier_permission_context.h"
11 #include "base/bind.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/content_settings/host_content_settings_map.h"
14 #include "chrome/browser/content_settings/permission_request_id.h"
15 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
16 #include "chrome/browser/extensions/extension_service.h"
17 #include "chrome/browser/extensions/extension_system.h"
18 #include "chrome/browser/extensions/suggest_permission_util.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/tab_contents/tab_util.h"
21 #include "chrome/common/extensions/extension.h"
22 #include "chrome/common/pref_names.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/render_view_host.h"
25 #include "content/public/browser/web_contents.h"
26 #include "extensions/browser/view_type_utils.h"
28 using extensions::APIPermission;
30 ProtectedMediaIdentifierPermissionContext::
31 ProtectedMediaIdentifierPermissionContext(Profile* profile)
32 : profile_(profile), shutting_down_(false) {}
34 ProtectedMediaIdentifierPermissionContext::
35 ~ProtectedMediaIdentifierPermissionContext() {
36 // ProtectedMediaIdentifierPermissionContext may be destroyed on either
37 // the UI thread or the IO thread, but the PermissionQueueController must have
38 // been destroyed on the UI thread.
39 DCHECK(!permission_queue_controller_.get());
42 void ProtectedMediaIdentifierPermissionContext::
43 RequestProtectedMediaIdentifierPermission(
44 int render_process_id,
46 const GURL& requesting_frame,
47 const base::Callback<void(bool)>& callback) {
48 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
52 content::WebContents* web_contents =
53 tab_util::GetWebContentsByID(render_process_id, render_view_id);
54 const PermissionRequestID id(render_process_id, render_view_id, 0);
56 if (extensions::GetViewType(web_contents) !=
57 extensions::VIEW_TYPE_TAB_CONTENTS) {
58 // The tab may have gone away, or the request may not be from a tab at all.
60 << "Attempt to use protected media identifier in tabless renderer: "
62 << " (can't prompt user without a visible tab)";
63 NotifyPermissionSet(id, requesting_frame, callback, false);
67 GURL embedder = web_contents->GetLastCommittedURL();
68 if (!requesting_frame.is_valid() || !embedder.is_valid()) {
70 << "Attempt to use protected media identifier from an invalid URL: "
71 << requesting_frame << "," << embedder
72 << " (proteced media identifier is not supported in popups)";
73 NotifyPermissionSet(id, requesting_frame, callback, false);
77 content::RenderViewHost* rvh = web_contents->GetRenderViewHost();
78 DecidePermission(id, requesting_frame, embedder, rvh, callback);
81 void ProtectedMediaIdentifierPermissionContext::
82 CancelProtectedMediaIdentifierPermissionRequest(
83 int render_process_id,
85 const GURL& requesting_frame) {
86 CancelPendingInfoBarRequest(
87 PermissionRequestID(render_process_id, render_view_id, 0));
90 void ProtectedMediaIdentifierPermissionContext::DecidePermission(
91 const PermissionRequestID& id,
92 const GURL& requesting_frame,
94 content::RenderViewHost* rvh,
95 const base::Callback<void(bool)>& callback) {
96 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
98 #if defined(OS_ANDROID)
99 // Check if the protected media identifier master switch is disabled.
100 if (!profile()->GetPrefs()->GetBoolean(
101 prefs::kProtectedMediaIdentifierEnabled)) {
102 PermissionDecided(id, requesting_frame, embedder, callback, false);
107 ContentSetting content_setting =
108 profile_->GetHostContentSettingsMap()->GetContentSetting(
111 CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
113 switch (content_setting) {
114 case CONTENT_SETTING_BLOCK:
115 PermissionDecided(id, requesting_frame, embedder, callback, false);
117 case CONTENT_SETTING_ALLOW:
118 PermissionDecided(id, requesting_frame, embedder, callback, true);
120 case CONTENT_SETTING_ASK:
121 QueueController()->CreateInfoBarRequest(
125 base::Bind(&ProtectedMediaIdentifierPermissionContext::
127 base::Unretained(this),
131 rvh->DisableFullscreenEncryptedMediaPlayback();
138 void ProtectedMediaIdentifierPermissionContext::ShutdownOnUIThread() {
139 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
140 permission_queue_controller_.reset();
141 shutting_down_ = true;
144 void ProtectedMediaIdentifierPermissionContext::PermissionDecided(
145 const PermissionRequestID& id,
146 const GURL& requesting_frame,
147 const GURL& embedder,
148 const base::Callback<void(bool)>& callback,
150 NotifyPermissionSet(id, requesting_frame, callback, allowed);
153 void ProtectedMediaIdentifierPermissionContext::NotifyPermissionSet(
154 const PermissionRequestID& id,
155 const GURL& requesting_frame,
156 const base::Callback<void(bool)>& callback,
158 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
160 // WebContents may have gone away.
161 TabSpecificContentSettings* content_settings =
162 TabSpecificContentSettings::Get(id.render_process_id(),
163 id.render_view_id());
164 if (content_settings) {
165 content_settings->OnProtectedMediaIdentifierPermissionSet(
166 requesting_frame.GetOrigin(), allowed);
169 callback.Run(allowed);
172 PermissionQueueController*
173 ProtectedMediaIdentifierPermissionContext::QueueController() {
174 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
175 DCHECK(!shutting_down_);
176 if (!permission_queue_controller_)
177 permission_queue_controller_.reset(CreateQueueController());
178 return permission_queue_controller_.get();
181 PermissionQueueController*
182 ProtectedMediaIdentifierPermissionContext::CreateQueueController() {
183 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
184 return new PermissionQueueController(
185 profile(), CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER);
189 ProtectedMediaIdentifierPermissionContext::CancelPendingInfoBarRequest(
190 const PermissionRequestID& id) {
191 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
192 content::BrowserThread::PostTask(
193 content::BrowserThread::UI,
195 base::Bind(&ProtectedMediaIdentifierPermissionContext::
196 CancelPendingInfoBarRequest,
201 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
204 QueueController()->CancelInfoBarRequest(id);