diff options
author | kkimlabs@chromium.org <kkimlabs@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-23 04:15:45 +0000 |
---|---|---|
committer | kkimlabs@chromium.org <kkimlabs@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-23 04:15:45 +0000 |
commit | f961a0fedd9bfae93284d6d0d989f42da3caac7b (patch) | |
tree | 770a1f9679799f8e50decff35ecc27cad4d89f8a | |
parent | d34e683c837a2e48a19c576b768ea516b2dfca1f (diff) | |
download | chromium_src-f961a0fedd9bfae93284d6d0d989f42da3caac7b.zip chromium_src-f961a0fedd9bfae93284d6d0d989f42da3caac7b.tar.gz chromium_src-f961a0fedd9bfae93284d6d0d989f42da3caac7b.tar.bz2 |
[Android] EME permission on/off pref and infobar UI.
For protected media identifier access permission,
add global on/off preference setting and infobar permission gate UI.
BUG=281576
Review URL: https://chromiumcodereview.appspot.com/23531021
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@224650 0039d316-1c4b-4281-b951-d872f2087c98
48 files changed, 839 insertions, 50 deletions
diff --git a/android_webview/native/aw_web_contents_delegate.cc b/android_webview/native/aw_web_contents_delegate.cc index 0acbbb4..d7435b0 100644 --- a/android_webview/native/aw_web_contents_delegate.cc +++ b/android_webview/native/aw_web_contents_delegate.cc @@ -176,6 +176,13 @@ void AwWebContentsDelegate::ActivateContents(WebContents* contents) { } } +void AwWebContentsDelegate::RequestProtectedMediaIdentifierPermission( + const content::WebContents* web_contents, + const GURL& frame_url, + const base::Callback<void(bool)>& callback) { + NOTIMPLEMENTED(); +} + static void FilesSelectedInChooser( JNIEnv* env, jclass clazz, jint process_id, jint render_id, jint mode_flags, diff --git a/android_webview/native/aw_web_contents_delegate.h b/android_webview/native/aw_web_contents_delegate.h index 8dc50ef..8f7a7bc 100644 --- a/android_webview/native/aw_web_contents_delegate.h +++ b/android_webview/native/aw_web_contents_delegate.h @@ -42,6 +42,10 @@ class AwWebContentsDelegate bool* was_blocked) OVERRIDE; virtual void CloseContents(content::WebContents* source) OVERRIDE; virtual void ActivateContents(content::WebContents* contents) OVERRIDE; + virtual void RequestProtectedMediaIdentifierPermission( + const content::WebContents* web_contents, + const GURL& frame_url, + const base::Callback<void(bool)>& callback) OVERRIDE; }; bool RegisterAwWebContentsDelegate(JNIEnv* env); diff --git a/chrome/android/java/res/drawable-xhdpi/infobar_protected_media_identifier.png b/chrome/android/java/res/drawable-xhdpi/infobar_protected_media_identifier.png Binary files differnew file mode 100644 index 0000000..b93ea6a --- /dev/null +++ b/chrome/android/java/res/drawable-xhdpi/infobar_protected_media_identifier.png diff --git a/chrome/android/java/res/drawable/infobar_protected_media_identifier.png b/chrome/android/java/res/drawable/infobar_protected_media_identifier.png Binary files differnew file mode 100644 index 0000000..b762b4a --- /dev/null +++ b/chrome/android/java/res/drawable/infobar_protected_media_identifier.png diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 6eafee3..2e26670 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -13846,6 +13846,22 @@ Some features may be unavailable. Please check that the profile exists and you New camera and microphone settings will take effect after reloading the page. </message> + <!-- Proteced media identifier permission infobar --> + <if expr="is_android"> + <message name="IDS_PROTECTED_MEDIA_IDENTIFIER_INFOBAR_QUESTION" desc="Question asked on the infobar whenever URL wants to access protected media identifier. It shows the origin of the URL."> + @<ph name="URL">$1<ex>https://www.youtube.com</ex></ph> needs to uniquely identify your device to play premium content. + </message> + <message name="IDS_PROTECTED_MEDIA_IDENTIFIER_ALLOW_BUTTON" desc="A button in the protected media identifier infobar for allowing access to a protected media identifier for a given origin."> + Allow + </message> + <message name="IDS_PROTECTED_MEDIA_IDENTIFIER_DENY_BUTTON" desc="A button in the protected media identifier infobar for denying access to a protected media identifier for a given origin."> + Deny + </message> + <message name="IDS_PROTECTED_MEDIA_IDENTIFIER_SETTINGS_LINK" desc="Link on in the protected media identifier infobar to open up its settings page."> + Settings + </message> + </if> + <message name="IDS_SAVE_PASSWORD" desc="The status text that is used as tooltip text for the save password icon and as status text of the save password bubble when a password can be saved."> Would you like to save this password? </message> diff --git a/chrome/app/theme/default_100_percent/common/infobar_protected_media_identifier.png b/chrome/app/theme/default_100_percent/common/infobar_protected_media_identifier.png Binary files differnew file mode 100644 index 0000000..b762b4a --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/infobar_protected_media_identifier.png diff --git a/chrome/app/theme/default_100_percent/infobar_protected_media_identifier.png b/chrome/app/theme/default_100_percent/infobar_protected_media_identifier.png Binary files differnew file mode 100644 index 0000000..b762b4a --- /dev/null +++ b/chrome/app/theme/default_100_percent/infobar_protected_media_identifier.png diff --git a/chrome/app/theme/default_200_percent/common/infobar_protected_media_identifier.png b/chrome/app/theme/default_200_percent/common/infobar_protected_media_identifier.png Binary files differnew file mode 100644 index 0000000..b93ea6a --- /dev/null +++ b/chrome/app/theme/default_200_percent/common/infobar_protected_media_identifier.png diff --git a/chrome/app/theme/default_200_percent/infobar_protected_media_identifier.png b/chrome/app/theme/default_200_percent/infobar_protected_media_identifier.png Binary files differnew file mode 100644 index 0000000..b93ea6a --- /dev/null +++ b/chrome/app/theme/default_200_percent/infobar_protected_media_identifier.png diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index 3965cd8..3967fd9 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd @@ -233,6 +233,9 @@ <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_PROGRESS_BACKGROUND_32" file="download_progress_background32.png" /> <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_PROGRESS_FOREGROUND_16" file="download_progress_foreground16.png" /> <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_PROGRESS_FOREGROUND_32" file="download_progress_foreground32.png" /> + <if expr="is_android"> + <structure type="chrome_scaled_image" name="IDR_PROTECTED_MEDIA_IDENTIFIER_INFOBAR_ICON" file="infobar_protected_media_identifier.png" /> + </if> <if expr="pp_ifdef('chromeos')"> <structure type="chrome_scaled_image" name="IDR_ENROLL_FAILURE" file="enroll_failure.png" /> <structure type="chrome_scaled_image" name="IDR_ENROLL_SUCCESS" file="enroll_success.png" /> diff --git a/chrome/browser/android/chrome_web_contents_delegate_android.cc b/chrome/browser/android/chrome_web_contents_delegate_android.cc index 0334acf..560a505 100644 --- a/chrome/browser/android/chrome_web_contents_delegate_android.cc +++ b/chrome/browser/android/chrome_web_contents_delegate_android.cc @@ -10,6 +10,8 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/file_select_helper.h" #include "chrome/browser/media/media_capture_devices_dispatcher.h" +#include "chrome/browser/media/protected_media_identifier_permission_context.h" +#include "chrome/browser/media/protected_media_identifier_permission_context_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.h" #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h" @@ -20,6 +22,7 @@ #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" +#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" #include "content/public/common/file_chooser_params.h" @@ -301,5 +304,20 @@ void ChromeWebContentsDelegateAndroid::AddNewContents( delete new_contents; } +void +ChromeWebContentsDelegateAndroid::RequestProtectedMediaIdentifierPermission( + const WebContents* web_contents, + const GURL& frame_url, + const base::Callback<void(bool)>& callback) { + Profile* profile = + Profile::FromBrowserContext(web_contents->GetBrowserContext()); + ProtectedMediaIdentifierPermissionContextFactory::GetForProfile(profile)-> + RequestProtectedMediaIdentifierPermission( + web_contents->GetRenderProcessHost()->GetID(), + web_contents->GetRenderViewHost()->GetRoutingID(), + frame_url, + callback); +} + } // namespace android } // namespace chrome diff --git a/chrome/browser/android/chrome_web_contents_delegate_android.h b/chrome/browser/android/chrome_web_contents_delegate_android.h index 9c22997..06c84eb 100644 --- a/chrome/browser/android/chrome_web_contents_delegate_android.h +++ b/chrome/browser/android/chrome_web_contents_delegate_android.h @@ -71,6 +71,10 @@ class ChromeWebContentsDelegateAndroid const gfx::Rect& initial_pos, bool user_gesture, bool* was_blocked) OVERRIDE; + virtual void RequestProtectedMediaIdentifierPermission( + const content::WebContents* web_contents, + const GURL& frame_url, + const base::Callback<void(bool)>& callback) OVERRIDE; private: // NotificationObserver implementation. diff --git a/chrome/browser/android/resource_id.h b/chrome/browser/android/resource_id.h index 3393724..bc414b4 100644 --- a/chrome/browser/android/resource_id.h +++ b/chrome/browser/android/resource_id.h @@ -14,6 +14,8 @@ DEFINE_RESOURCE_ID(0, 0) // InfoBar resources. +DEFINE_RESOURCE_ID(IDR_PROTECTED_MEDIA_IDENTIFIER_INFOBAR_ICON, + R.drawable.infobar_protected_media_identifier) DEFINE_RESOURCE_ID(IDR_GEOLOCATION_INFOBAR_ICON, R.drawable.infobar_geolocation) DEFINE_RESOURCE_ID(IDR_INFOBAR_ALT_NAV_URL, R.drawable.infobar_didyoumean) DEFINE_RESOURCE_ID(IDR_INFOBAR_AUTOFILL, R.drawable.infobar_autofill) diff --git a/chrome/browser/content_settings/content_settings_default_provider.cc b/chrome/browser/content_settings/content_settings_default_provider.cc index 3a7c891..96f07fe 100644 --- a/chrome/browser/content_settings/content_settings_default_provider.cc +++ b/chrome/browser/content_settings/content_settings_default_provider.cc @@ -51,10 +51,12 @@ const ContentSetting kDefaultSettings[] = { CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_PPAPI_BROKER CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_MIDI_SYSEX + CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_SAVE_PASSWORD #if defined(OS_WIN) CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP +#elif defined(OS_ANDROID) + CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER #endif - CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_SAVE_PASSWORD }; COMPILE_ASSERT(arraysize(kDefaultSettings) == CONTENT_SETTINGS_NUM_TYPES, default_settings_incorrect_size); diff --git a/chrome/browser/content_settings/content_settings_policy_provider.cc b/chrome/browser/content_settings/content_settings_policy_provider.cc index b2dcdea..3858cc3 100644 --- a/chrome/browser/content_settings/content_settings_policy_provider.cc +++ b/chrome/browser/content_settings/content_settings_policy_provider.cc @@ -44,10 +44,12 @@ const char* kPrefToManageType[] = { NULL, // No policy for default value of PPAPI broker NULL, // No policy for default value of multiple automatic downloads NULL, // No policy for default value of MIDI system exclusive requests + NULL, // No policy for default value of save password #if defined(OS_WIN) NULL, // No policy for default value of "switch to desktop" +#elif defined(OS_ANDROID) + NULL, // No policy for default value of protected media identifier #endif - NULL, // No policy for default value of save password }; COMPILE_ASSERT(arraysize(kPrefToManageType) == CONTENT_SETTINGS_NUM_TYPES, managed_content_settings_pref_names_array_size_incorrect); diff --git a/chrome/browser/content_settings/content_settings_utils.cc b/chrome/browser/content_settings/content_settings_utils.cc index c95b907..5da1ec4 100644 --- a/chrome/browser/content_settings/content_settings_utils.cc +++ b/chrome/browser/content_settings/content_settings_utils.cc @@ -41,10 +41,12 @@ const char* kTypeNames[] = { "ppapi-broker", "multiple-automatic-downloads", "midi-sysex", + "save-password", #if defined(OS_WIN) "metro-switch-to-desktop", +#elif defined(OS_ANDROID) + "protected-media-identifier", #endif - "save-password", }; COMPILE_ASSERT(arraysize(kTypeNames) == CONTENT_SETTINGS_NUM_TYPES, type_names_incorrect_size); diff --git a/chrome/browser/content_settings/permission_queue_controller.cc b/chrome/browser/content_settings/permission_queue_controller.cc index 4da7228..cd2c5ac 100644 --- a/chrome/browser/content_settings/permission_queue_controller.cc +++ b/chrome/browser/content_settings/permission_queue_controller.cc @@ -21,6 +21,9 @@ #include "content/public/browser/notification_types.h" #include "content/public/browser/web_contents.h" +#if defined(OS_ANDROID) +#include "chrome/browser/media/protected_media_identifier_infobar_delegate.h" +#endif namespace { @@ -110,6 +113,13 @@ void PermissionQueueController::PendingInfoBarRequest::CreateInfoBar( GetInfoBarService(id_), controller, id_, requesting_frame_, display_languages); break; +#if defined(OS_ANDROID) + case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER: + infobar_ = ProtectedMediaIdentifierInfoBarDelegate::Create( + GetInfoBarService(id_), controller, id_, requesting_frame_, + display_languages); + break; +#endif default: NOTREACHED(); break; diff --git a/chrome/browser/content_settings/tab_specific_content_settings.cc b/chrome/browser/content_settings/tab_specific_content_settings.cc index ef49b78..733eb96 100644 --- a/chrome/browser/content_settings/tab_specific_content_settings.cc +++ b/chrome/browser/content_settings/tab_specific_content_settings.cc @@ -278,11 +278,18 @@ void TabSpecificContentSettings::OnContentBlocked( // Media is different from other content setting types since it allows new // setting to kick in without reloading the page, and the UI for media is // always reflecting the newest permission setting. - if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC || - type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) - content_allowed_[type] = false; - else - content_allowed_[type] = true; + switch (type) { + case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC: + case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA: +#if defined(OS_ANDROID) + case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER: +#endif + content_allowed_[type] = false; + break; + default: + content_allowed_[type] = true; + break; + } // Unless UI for resource content settings is enabled, ignore the resource // identifier. @@ -296,7 +303,7 @@ void TabSpecificContentSettings::OnContentBlocked( if (!identifier.empty()) AddBlockedResource(type, identifier); -#if defined (OS_ANDROID) +#if defined(OS_ANDROID) if (type == CONTENT_SETTINGS_TYPE_POPUPS) { // For Android we do not have a persistent button that will always be // visible for blocked popups. Instead we have info bars which could be @@ -321,14 +328,21 @@ void TabSpecificContentSettings::OnContentAllowed(ContentSettingsType type) { DCHECK(type != CONTENT_SETTINGS_TYPE_GEOLOCATION) << "Geolocation settings handled by OnGeolocationPermissionSet"; bool access_changed = false; - if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC || - type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) { - // The setting for media is overwritten here because media does not need to - // reload the page to have the new setting kick in. See issue/175993. - if (content_blocked_[type]) { - content_blocked_[type] = false; - access_changed = true; - } + switch (type) { + case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC: + case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA: +#if defined(OS_ANDROID) + case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER: +#endif + // The setting for media is overwritten here because media does not need + // to reload the page to have the new setting kick in. See issue/175993. + if (content_blocked_[type]) { + content_blocked_[type] = false; + access_changed = true; + } + break; + default: + break; } if (!content_allowed_[type]) { @@ -462,6 +476,19 @@ void TabSpecificContentSettings::OnGeolocationPermissionSet( content::NotificationService::NoDetails()); } +#if defined(OS_ANDROID) +void TabSpecificContentSettings::OnProtectedMediaIdentifierPermissionSet( + const GURL& requesting_origin, + bool allowed) { + if (allowed) { + OnContentAllowed(CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER); + } else { + OnContentBlocked(CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER, + std::string()); + } +} +#endif + void TabSpecificContentSettings::OnPasswordSubmitted( PasswordFormManager* form_manager) { form_manager_.reset(form_manager); diff --git a/chrome/browser/content_settings/tab_specific_content_settings.h b/chrome/browser/content_settings/tab_specific_content_settings.h index e9b06f3..5090166 100644 --- a/chrome/browser/content_settings/tab_specific_content_settings.h +++ b/chrome/browser/content_settings/tab_specific_content_settings.h @@ -337,6 +337,10 @@ class TabSpecificContentSettings bool blocked_by_policy); void OnGeolocationPermissionSet(const GURL& requesting_frame, bool allowed); +#if defined(OS_ANDROID) + void OnProtectedMediaIdentifierPermissionSet(const GURL& requesting_frame, + bool allowed); +#endif // This method is called to update the status about the microphone and // camera stream access. |request_permissions| contains a list of requested diff --git a/chrome/browser/media/protected_media_identifier_infobar_delegate.cc b/chrome/browser/media/protected_media_identifier_infobar_delegate.cc new file mode 100644 index 0000000..bde3fbf --- /dev/null +++ b/chrome/browser/media/protected_media_identifier_infobar_delegate.cc @@ -0,0 +1,108 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/media/protected_media_identifier_infobar_delegate.h" + +#include "chrome/browser/content_settings/permission_queue_controller.h" +#include "content/public/browser/navigation_details.h" +#include "content/public/browser/navigation_entry.h" +#include "grit/generated_resources.h" +#include "grit/theme_resources.h" +#include "net/base/net_util.h" +#include "ui/base/l10n/l10n_util.h" + +// static +InfoBarDelegate* ProtectedMediaIdentifierInfoBarDelegate::Create( + InfoBarService* infobar_service, + PermissionQueueController* controller, + const PermissionRequestID& id, + const GURL& requesting_frame, + const std::string& display_languages) { + const content::NavigationEntry* committed_entry = + infobar_service->web_contents()->GetController().GetLastCommittedEntry(); + return infobar_service->AddInfoBar( + scoped_ptr<InfoBarDelegate>(new ProtectedMediaIdentifierInfoBarDelegate( + infobar_service, + controller, + id, + requesting_frame, + committed_entry ? committed_entry->GetUniqueID() : 0, + display_languages))); +} + + +ProtectedMediaIdentifierInfoBarDelegate:: + ProtectedMediaIdentifierInfoBarDelegate( + InfoBarService* infobar_service, + PermissionQueueController* controller, + const PermissionRequestID& id, + const GURL& requesting_frame, + int contents_unique_id, + const std::string& display_languages) + : ConfirmInfoBarDelegate(infobar_service), + controller_(controller), + id_(id), + requesting_frame_(requesting_frame), + contents_unique_id_(contents_unique_id), + display_languages_(display_languages) {} + +ProtectedMediaIdentifierInfoBarDelegate:: + ~ProtectedMediaIdentifierInfoBarDelegate() {} + +bool ProtectedMediaIdentifierInfoBarDelegate::Accept() { + SetPermission(true, true); + return true; +} + +void ProtectedMediaIdentifierInfoBarDelegate::SetPermission( + bool update_content_setting, + bool allowed) { + controller_->OnPermissionSet(id_, + requesting_frame_, + web_contents()->GetLastCommittedURL(), + update_content_setting, + allowed); +} + +void ProtectedMediaIdentifierInfoBarDelegate::InfoBarDismissed() { + SetPermission(false, false); +} + +int ProtectedMediaIdentifierInfoBarDelegate::GetIconID() const { + return IDR_PROTECTED_MEDIA_IDENTIFIER_INFOBAR_ICON; +} + +InfoBarDelegate::Type ProtectedMediaIdentifierInfoBarDelegate::GetInfoBarType() + const { + return PAGE_ACTION_TYPE; +} + +bool ProtectedMediaIdentifierInfoBarDelegate::ShouldExpireInternal( + const content::LoadCommittedDetails& details) const { + // This implementation matches InfoBarDelegate::ShouldExpireInternal(), but + // uses the unique ID we set in the constructor instead of that stored in the + // base class. + return (contents_unique_id_ != details.entry->GetUniqueID()) || + (content::PageTransitionStripQualifier( + details.entry->GetTransitionType()) == + content::PAGE_TRANSITION_RELOAD); +} + +string16 ProtectedMediaIdentifierInfoBarDelegate::GetMessageText() const { + return l10n_util::GetStringFUTF16( + IDS_PROTECTED_MEDIA_IDENTIFIER_INFOBAR_QUESTION, + net::FormatUrl(requesting_frame_.GetOrigin(), display_languages_)); +} + +string16 ProtectedMediaIdentifierInfoBarDelegate::GetButtonLabel( + InfoBarButton button) const { + return l10n_util::GetStringUTF16( + (button == BUTTON_OK) ? IDS_PROTECTED_MEDIA_IDENTIFIER_ALLOW_BUTTON + : IDS_PROTECTED_MEDIA_IDENTIFIER_DENY_BUTTON); +} + +bool ProtectedMediaIdentifierInfoBarDelegate::Cancel() { + SetPermission(true, false); + return true; +} diff --git a/chrome/browser/media/protected_media_identifier_infobar_delegate.h b/chrome/browser/media/protected_media_identifier_infobar_delegate.h new file mode 100644 index 0000000..9510772 --- /dev/null +++ b/chrome/browser/media/protected_media_identifier_infobar_delegate.h @@ -0,0 +1,60 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_MEDIA_PROTECTED_MEDIA_IDENTIFIER_INFOBAR_DELEGATE_H_ +#define CHROME_BROWSER_MEDIA_PROTECTED_MEDIA_IDENTIFIER_INFOBAR_DELEGATE_H_ + +#include <string> + +#include "chrome/browser/content_settings/permission_request_id.h" +#include "chrome/browser/infobars/confirm_infobar_delegate.h" +#include "url/gurl.h" + +class PermissionQueueController; +class InfoBarService; + +class ProtectedMediaIdentifierInfoBarDelegate : public ConfirmInfoBarDelegate { + public: + // Creates a protected media identifier infobar delegate and adds it to + // |infobar_service|. + // Returns the delegate if it was successfully added. + static InfoBarDelegate* Create(InfoBarService* infobar_service, + PermissionQueueController* controller, + const PermissionRequestID& id, + const GURL& requesting_frame, + const std::string& display_languages); + protected: + ProtectedMediaIdentifierInfoBarDelegate(InfoBarService* infobar_service, + PermissionQueueController* controller, + const PermissionRequestID& id, + const GURL& requesting_frame, + int contents_unique_id, + const std::string& display_languages); + virtual ~ProtectedMediaIdentifierInfoBarDelegate(); + + // Call back to the controller, to inform of the user's decision. + void SetPermission(bool update_content_setting, bool allowed); + + private: + // ConfirmInfoBarDelegate: + virtual void InfoBarDismissed() OVERRIDE; + virtual int GetIconID() const OVERRIDE; + virtual Type GetInfoBarType() const OVERRIDE; + virtual bool ShouldExpireInternal( + const content::LoadCommittedDetails& details) const OVERRIDE; + virtual string16 GetMessageText() const OVERRIDE; + virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE; + virtual bool Accept() OVERRIDE; + virtual bool Cancel() OVERRIDE; + + PermissionQueueController* controller_; + const PermissionRequestID id_; + GURL requesting_frame_; + int contents_unique_id_; + std::string display_languages_; + + DISALLOW_COPY_AND_ASSIGN(ProtectedMediaIdentifierInfoBarDelegate); +}; + +#endif // CHROME_BROWSER_MEDIA_PROTECTED_MEDIA_IDENTIFIER_INFOBAR_DELEGATE_H_ diff --git a/chrome/browser/media/protected_media_identifier_permission_context.cc b/chrome/browser/media/protected_media_identifier_permission_context.cc new file mode 100644 index 0000000..6f01795 --- /dev/null +++ b/chrome/browser/media/protected_media_identifier_permission_context.cc @@ -0,0 +1,202 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/media/protected_media_identifier_permission_context.h" + +#include <functional> +#include <string> +#include <vector> + +#include "base/bind.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/content_settings/host_content_settings_map.h" +#include "chrome/browser/content_settings/permission_request_id.h" +#include "chrome/browser/content_settings/tab_specific_content_settings.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_system.h" +#include "chrome/browser/extensions/suggest_permission_util.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/tab_contents/tab_util.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/pref_names.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" +#include "extensions/browser/view_type_utils.h" + +using extensions::APIPermission; + +ProtectedMediaIdentifierPermissionContext:: + ProtectedMediaIdentifierPermissionContext(Profile* profile) + : profile_(profile), shutting_down_(false) {} + +ProtectedMediaIdentifierPermissionContext:: + ~ProtectedMediaIdentifierPermissionContext() { + // ProtectedMediaIdentifierPermissionContext may be destroyed on either + // the UI thread or the IO thread, but the PermissionQueueController must have + // been destroyed on the UI thread. + DCHECK(!permission_queue_controller_.get()); +} + +void ProtectedMediaIdentifierPermissionContext:: + RequestProtectedMediaIdentifierPermission( + int render_process_id, + int render_view_id, + const GURL& requesting_frame, + const base::Callback<void(bool)>& callback) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (shutting_down_) + return; + + content::WebContents* web_contents = + tab_util::GetWebContentsByID(render_process_id, render_view_id); + const PermissionRequestID id(render_process_id, render_view_id, 0); + + if (extensions::GetViewType(web_contents) != + extensions::VIEW_TYPE_TAB_CONTENTS) { + // The tab may have gone away, or the request may not be from a tab at all. + LOG(WARNING) + << "Attempt to use protected media identifier in tabless renderer: " + << id.ToString() + << " (can't prompt user without a visible tab)"; + NotifyPermissionSet(id, requesting_frame, callback, false); + return; + } + + GURL embedder = web_contents->GetLastCommittedURL(); + if (!requesting_frame.is_valid() || !embedder.is_valid()) { + LOG(WARNING) + << "Attempt to use protected media identifier from an invalid URL: " + << requesting_frame << "," << embedder + << " (proteced media identifier is not supported in popups)"; + NotifyPermissionSet(id, requesting_frame, callback, false); + return; + } + + DecidePermission(id, requesting_frame, embedder, callback); +} + +void ProtectedMediaIdentifierPermissionContext:: + CancelProtectedMediaIdentifierPermissionRequest( + int render_process_id, + int render_view_id, + const GURL& requesting_frame) { + CancelPendingInfoBarRequest( + PermissionRequestID(render_process_id, render_view_id, 0)); +} + +void ProtectedMediaIdentifierPermissionContext::DecidePermission( + const PermissionRequestID& id, + const GURL& requesting_frame, + const GURL& embedder, + const base::Callback<void(bool)>& callback) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + +#if defined(OS_ANDROID) + // Check if the protected media identifier master switch is disabled. + if (!profile()->GetPrefs()->GetBoolean( + prefs::kProtectedMediaIdentifierEnabled)) { + PermissionDecided(id, requesting_frame, embedder, callback, false); + return; + } +#endif + + ContentSetting content_setting = + profile_->GetHostContentSettingsMap()->GetContentSetting( + requesting_frame, + embedder, + CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER, + std::string()); + switch (content_setting) { + case CONTENT_SETTING_BLOCK: + PermissionDecided(id, requesting_frame, embedder, callback, false); + break; + case CONTENT_SETTING_ALLOW: + PermissionDecided(id, requesting_frame, embedder, callback, true); + break; + case CONTENT_SETTING_ASK: + QueueController()->CreateInfoBarRequest( + id, + requesting_frame, + embedder, + base::Bind(&ProtectedMediaIdentifierPermissionContext:: + NotifyPermissionSet, + base::Unretained(this), + id, + requesting_frame, + callback)); + break; + default: + NOTREACHED(); + } +} + +void ProtectedMediaIdentifierPermissionContext::ShutdownOnUIThread() { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + permission_queue_controller_.reset(); + shutting_down_ = true; +} + +void ProtectedMediaIdentifierPermissionContext::PermissionDecided( + const PermissionRequestID& id, + const GURL& requesting_frame, + const GURL& embedder, + const base::Callback<void(bool)>& callback, + bool allowed) { + NotifyPermissionSet(id, requesting_frame, callback, allowed); +} + +void ProtectedMediaIdentifierPermissionContext::NotifyPermissionSet( + const PermissionRequestID& id, + const GURL& requesting_frame, + const base::Callback<void(bool)>& callback, + bool allowed) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + + // WebContents may have gone away. + TabSpecificContentSettings* content_settings = + TabSpecificContentSettings::Get(id.render_process_id(), + id.render_view_id()); + if (content_settings) { + content_settings->OnProtectedMediaIdentifierPermissionSet( + requesting_frame.GetOrigin(), allowed); + } + + callback.Run(allowed); +} + +PermissionQueueController* + ProtectedMediaIdentifierPermissionContext::QueueController() { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + DCHECK(!shutting_down_); + if (!permission_queue_controller_) + permission_queue_controller_.reset(CreateQueueController()); + return permission_queue_controller_.get(); +} + +PermissionQueueController* + ProtectedMediaIdentifierPermissionContext::CreateQueueController() { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + return new PermissionQueueController( + profile(), CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER); +} + +void +ProtectedMediaIdentifierPermissionContext::CancelPendingInfoBarRequest( + const PermissionRequestID& id) { + if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { + content::BrowserThread::PostTask( + content::BrowserThread::UI, + FROM_HERE, + base::Bind(&ProtectedMediaIdentifierPermissionContext:: + CancelPendingInfoBarRequest, + this, + id)); + return; + } + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (shutting_down_) + return; + QueueController()->CancelInfoBarRequest(id); +} diff --git a/chrome/browser/media/protected_media_identifier_permission_context.h b/chrome/browser/media/protected_media_identifier_permission_context.h new file mode 100644 index 0000000..b30fc236d --- /dev/null +++ b/chrome/browser/media/protected_media_identifier_permission_context.h @@ -0,0 +1,90 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_MEDIA_PROTECTED_MEDIA_IDENTIFIER_PERMISSION_CONTEXT_H_ +#define CHROME_BROWSER_MEDIA_PROTECTED_MEDIA_IDENTIFIER_PERMISSION_CONTEXT_H_ + +#include <string> + +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/content_settings/permission_queue_controller.h" + +class PermissionRequestID; +class Profile; + +// Manages protected media identifier permissions flow, and delegates UI +// handling via PermissionQueueController. +class ProtectedMediaIdentifierPermissionContext + : public base::RefCountedThreadSafe< + ProtectedMediaIdentifierPermissionContext> { + public: + explicit ProtectedMediaIdentifierPermissionContext(Profile* profile); + + void RequestProtectedMediaIdentifierPermission( + int render_process_id, + int render_view_id, + const GURL& requesting_frame, + const base::Callback<void(bool)>& callback); + void CancelProtectedMediaIdentifierPermissionRequest( + int render_process_id, + int render_view_id, + const GURL& requesting_frame); + + // Called on the UI thread when the profile is about to be destroyed. + void ShutdownOnUIThread(); + + private: + friend class base::RefCountedThreadSafe< + ProtectedMediaIdentifierPermissionContext>; + ~ProtectedMediaIdentifierPermissionContext(); + + Profile* profile() const { return profile_; } + + // Return an instance of the infobar queue controller, creating it + // if necessary. + PermissionQueueController* QueueController(); + + // Notifies whether or not the corresponding bridge is allowed to use + // protected media identifier via + // SetProtectedMediaIdentifierPermissionResponse(). Called on the UI thread. + void NotifyPermissionSet(const PermissionRequestID& id, + const GURL& requesting_frame, + const base::Callback<void(bool)>& callback, + bool allowed); + + // Decide whether the protected media identifier permission should be granted. + // Calls PermissionDecided if permission can be decided non-interactively, + // or NotifyPermissionSet if permission decided by presenting an + // infobar to the user. Called on the UI thread. + void DecidePermission(const PermissionRequestID& id, + const GURL& requesting_frame, + const GURL& embedder, + const base::Callback<void(bool)>& callback); + + // Called when permission is granted without interactively asking + // the user. Can be overridden to introduce additional UI flow. + // Should ultimately ensure that NotifyPermissionSet is called. + // Called on the UI thread. + void PermissionDecided(const PermissionRequestID& id, + const GURL& requesting_frame, + const GURL& embedder, + const base::Callback<void(bool)>& callback, + bool allowed); + + // Create an PermissionQueueController. overridden in derived classes to + // provide additional UI flow. Called on the UI thread. + PermissionQueueController* CreateQueueController(); + + // Removes any pending InfoBar request. + void CancelPendingInfoBarRequest(const PermissionRequestID& id); + + // These must only be accessed from the UI thread. + Profile* const profile_; + bool shutting_down_; + scoped_ptr<PermissionQueueController> permission_queue_controller_; + + DISALLOW_COPY_AND_ASSIGN(ProtectedMediaIdentifierPermissionContext); +}; + +#endif // CHROME_BROWSER_MEDIA_PROTECTED_MEDIA_IDENTIFIER_PERMISSION_CONTEXT_H_ diff --git a/chrome/browser/media/protected_media_identifier_permission_context_factory.cc b/chrome/browser/media/protected_media_identifier_permission_context_factory.cc new file mode 100644 index 0000000..b4a2f47 --- /dev/null +++ b/chrome/browser/media/protected_media_identifier_permission_context_factory.cc @@ -0,0 +1,83 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/media/protected_media_identifier_permission_context_factory.h" + +#include "chrome/browser/media/protected_media_identifier_permission_context.h" +#include "chrome/browser/profiles/incognito_helpers.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/pref_names.h" +#include "components/browser_context_keyed_service/browser_context_dependency_manager.h" +#include "components/user_prefs/pref_registry_syncable.h" + +namespace { + +class Service : public BrowserContextKeyedService { + public: + explicit Service(Profile* profile) { + context_ = new ProtectedMediaIdentifierPermissionContext(profile); + } + + ProtectedMediaIdentifierPermissionContext* context() { + return context_.get(); + } + + virtual void Shutdown() OVERRIDE { + context()->ShutdownOnUIThread(); + } + + private: + scoped_refptr<ProtectedMediaIdentifierPermissionContext> context_; + + DISALLOW_COPY_AND_ASSIGN(Service); +}; + +} // namespace + +// static +ProtectedMediaIdentifierPermissionContext* +ProtectedMediaIdentifierPermissionContextFactory::GetForProfile( + Profile* profile) { + return static_cast<Service*>( + GetInstance()->GetServiceForBrowserContext(profile, true))->context(); +} + +// static +ProtectedMediaIdentifierPermissionContextFactory* +ProtectedMediaIdentifierPermissionContextFactory::GetInstance() { + return Singleton< + ProtectedMediaIdentifierPermissionContextFactory>::get(); +} + +ProtectedMediaIdentifierPermissionContextFactory:: +ProtectedMediaIdentifierPermissionContextFactory() + : BrowserContextKeyedServiceFactory( + "ProtectedMediaIdentifierPermissionContext", + BrowserContextDependencyManager::GetInstance()) { +} + +ProtectedMediaIdentifierPermissionContextFactory:: +~ProtectedMediaIdentifierPermissionContextFactory() { +} + +BrowserContextKeyedService* +ProtectedMediaIdentifierPermissionContextFactory::BuildServiceInstanceFor( + content::BrowserContext* profile) const { + return new Service(static_cast<Profile*>(profile)); +} + +void +ProtectedMediaIdentifierPermissionContextFactory::RegisterProfilePrefs( + user_prefs::PrefRegistrySyncable* registry) { + registry->RegisterBooleanPref( + prefs::kProtectedMediaIdentifierEnabled, + true, + user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); +} + +content::BrowserContext* +ProtectedMediaIdentifierPermissionContextFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return chrome::GetBrowserContextOwnInstanceInIncognito(context); +} diff --git a/chrome/browser/media/protected_media_identifier_permission_context_factory.h b/chrome/browser/media/protected_media_identifier_permission_context_factory.h new file mode 100644 index 0000000..a6f85fe --- /dev/null +++ b/chrome/browser/media/protected_media_identifier_permission_context_factory.h @@ -0,0 +1,41 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_MEDIA_PROTECTED_MEDIA_IDENTIFIER_PERMISSION_CONTEXT_FACTORY_H_ +#define CHROME_BROWSER_MEDIA_PROTECTED_MEDIA_IDENTIFIER_PERMISSION_CONTEXT_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h" + +class ProtectedMediaIdentifierPermissionContext; +class Profile; + +class ProtectedMediaIdentifierPermissionContextFactory + : public BrowserContextKeyedServiceFactory { + public: + static ProtectedMediaIdentifierPermissionContext* GetForProfile( + Profile* profile); + + static ProtectedMediaIdentifierPermissionContextFactory* GetInstance(); + + private: + friend struct DefaultSingletonTraits< + ProtectedMediaIdentifierPermissionContextFactory>; + + ProtectedMediaIdentifierPermissionContextFactory(); + virtual ~ProtectedMediaIdentifierPermissionContextFactory(); + + // BrowserContextKeyedBaseFactory methods: + virtual BrowserContextKeyedService* BuildServiceInstanceFor( + content::BrowserContext* profile) const OVERRIDE; + virtual void RegisterProfilePrefs( + user_prefs::PrefRegistrySyncable* registry) OVERRIDE; + virtual content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const OVERRIDE; + + DISALLOW_COPY_AND_ASSIGN( + ProtectedMediaIdentifierPermissionContextFactory); +}; + +#endif // CHROME_BROWSER_MEDIA_PROTECTED_MEDIA_IDENTIFIER_PERMISSION_CONTEXT_FACTORY_H_ diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc index 7dc3f10..edfb33a 100644 --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc @@ -134,7 +134,9 @@ #include "chrome/browser/ui/gesture_prefs_observer_factory_aura.h" #endif -#if !defined(OS_ANDROID) +#if defined(OS_ANDROID) +#include "chrome/browser/media/protected_media_identifier_permission_context_factory.h" +#else #include "chrome/browser/media_galleries/media_galleries_preferences_factory.h" #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h" #endif @@ -185,6 +187,9 @@ EnsureBrowserContextKeyedServiceFactoriesBuilt() { captive_portal::CaptivePortalServiceFactory::GetInstance(); #endif ChromeGeolocationPermissionContextFactory::GetInstance(); +#if defined(OS_ANDROID) + ProtectedMediaIdentifierPermissionContextFactory::GetInstance(); +#endif #if defined(OS_CHROMEOS) chromeos::NetworkingPrivateEventRouterFactory::GetInstance(); #endif diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 14801cf..5264c97 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -3111,6 +3111,12 @@ 'browser/ssl/ssl_add_certificate_android.cc', 'browser/web_resource/notification_promo_mobile_ntp.cc', 'browser/web_resource/notification_promo_mobile_ntp.h', + 'browser/media/protected_media_identifier_infobar_delegate.cc', + 'browser/media/protected_media_identifier_infobar_delegate.h', + 'browser/media/protected_media_identifier_permission_context.cc', + 'browser/media/protected_media_identifier_permission_context.h', + 'browser/media/protected_media_identifier_permission_context_factory.cc', + 'browser/media/protected_media_identifier_permission_context_factory.h', ], 'sources!': [ # Bookmark export/import are handled via the BookmarkColumns diff --git a/chrome/common/content_settings_types.h b/chrome/common/content_settings_types.h index c1b03a5..cf091fe 100644 --- a/chrome/common/content_settings_types.h +++ b/chrome/common/content_settings_types.h @@ -32,6 +32,8 @@ enum ContentSettingsType { CONTENT_SETTINGS_TYPE_SAVE_PASSWORD, #if defined(OS_WIN) CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP, +#elif defined(OS_ANDROID) + CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER, #endif CONTENT_SETTINGS_NUM_TYPES, }; diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 8654db1..86984b3 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -2057,6 +2057,12 @@ const char kVideoCaptureAllowed[] = "hardware.video_capture_enabled"; // TODO(tommi): Update comment when this is supported for all modes. const char kVideoCaptureAllowedUrls[] = "hardware.video_capture_allowed_urls"; +#if defined(OS_ANDROID) +// Boolean that controls the global enabled-state of protected media identifier. +const char kProtectedMediaIdentifierEnabled[] = + "protected_media_identifier.enabled"; +#endif + #if defined(OS_CHROMEOS) // Dictionary for transient storage of settings that should go into device // settings storage before owner has been assigned. diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index f1a7f1a..4fb4ae4 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -736,6 +736,10 @@ extern const char kAudioCaptureAllowedUrls[]; extern const char kVideoCaptureAllowed[]; extern const char kVideoCaptureAllowedUrls[]; +#if defined(OS_ANDROID) +extern const char kProtectedMediaIdentifierEnabled[]; +#endif + #if defined(OS_CHROMEOS) extern const char kDeviceSettingsCache[]; extern const char kHardwareKeyboardLayout[]; diff --git a/content/browser/media/android/browser_media_player_manager.cc b/content/browser/media/android/browser_media_player_manager.cc index ffff16c..75498b9 100644 --- a/content/browser/media/android/browser_media_player_manager.cc +++ b/content/browser/media/android/browser_media_player_manager.cc @@ -8,6 +8,7 @@ #include "content/browser/android/content_view_core_impl.h" #include "content/browser/media/android/browser_demuxer_android.h" #include "content/browser/media/android/media_resource_getter_impl.h" +#include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_view_android.h" #include "content/common/media/media_player_messages_android.h" #include "content/public/browser/browser_context.h" @@ -15,6 +16,7 @@ #include "content/public/browser/render_view_host.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_delegate.h" #include "media/base/android/media_drm_bridge.h" #include "media/base/android/media_player_bridge.h" #include "media/base/android/media_source_player.h" @@ -81,7 +83,8 @@ BrowserMediaPlayerManager::BrowserMediaPlayerManager( RenderViewHost* render_view_host) : RenderViewHostObserver(render_view_host), fullscreen_player_id_(-1), - web_contents_(WebContents::FromRenderViewHost(render_view_host)) { + web_contents_(WebContents::FromRenderViewHost(render_view_host)), + weak_ptr_factory_(this) { } BrowserMediaPlayerManager::~BrowserMediaPlayerManager() {} @@ -455,8 +458,9 @@ void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) { void BrowserMediaPlayerManager::OnInitializeCDM( int media_keys_id, - const std::vector<uint8>& uuid) { - AddDrmBridge(media_keys_id, uuid); + const std::vector<uint8>& uuid, + const GURL& frame_url) { + AddDrmBridge(media_keys_id, uuid, frame_url); // In EME v0.1b MediaKeys lives in the media element. So the |media_keys_id| // is the same as the |player_id|. OnSetMediaKeys(media_keys_id, media_keys_id); @@ -466,9 +470,16 @@ void BrowserMediaPlayerManager::OnGenerateKeyRequest( int media_keys_id, const std::string& type, const std::vector<uint8>& init_data) { - MediaDrmBridge* drm_bridge = GetDrmBridge(media_keys_id); - if (drm_bridge) - drm_bridge->GenerateKeyRequest(type, &init_data[0], init_data.size()); + WebContents* web_contents = + WebContents::FromRenderViewHost(render_view_host()); + web_contents->GetDelegate()->RequestProtectedMediaIdentifierPermission( + web_contents, + GetDrmBridge(media_keys_id)->frame_url(), + base::Bind(&BrowserMediaPlayerManager::GenerateKeyIfAllowed, + weak_ptr_factory_.GetWeakPtr(), + media_keys_id, + type, + init_data)); } void BrowserMediaPlayerManager::OnAddKey(int media_keys_id, @@ -528,7 +539,8 @@ scoped_ptr<media::MediaPlayerAndroid> BrowserMediaPlayerManager::SwapPlayer( } void BrowserMediaPlayerManager::AddDrmBridge(int media_keys_id, - const std::vector<uint8>& uuid) { + const std::vector<uint8>& uuid, + const GURL& frame_url) { DCHECK(!GetDrmBridge(media_keys_id)); // TODO(xhwang/ddorwin): Pass the security level from key system. std::string security_level = "L3"; @@ -537,8 +549,8 @@ void BrowserMediaPlayerManager::AddDrmBridge(int media_keys_id, security_level = "L1"; } - scoped_ptr<MediaDrmBridge> drm_bridge( - MediaDrmBridge::Create(media_keys_id, uuid, security_level, this)); + scoped_ptr<MediaDrmBridge> drm_bridge(MediaDrmBridge::Create( + media_keys_id, uuid, frame_url, security_level, this)); if (!drm_bridge) { DVLOG(1) << "failed to create drm bridge."; OnKeyError(media_keys_id, "", media::MediaKeys::kUnknownError, 0); @@ -571,4 +583,17 @@ void BrowserMediaPlayerManager::OnSetMediaKeys(int player_id, player->SetDrmBridge(drm_bridge); } +void BrowserMediaPlayerManager::GenerateKeyIfAllowed( + int media_keys_id, + const std::string& type, + const std::vector<uint8>& init_data, + bool allowed) { + if (!allowed) + return; + + MediaDrmBridge* drm_bridge = GetDrmBridge(media_keys_id); + if (drm_bridge) + drm_bridge->GenerateKeyRequest(type, &init_data[0], init_data.size()); +} + } // namespace content diff --git a/content/browser/media/android/browser_media_player_manager.h b/content/browser/media/android/browser_media_player_manager.h index 61834cc..a26e182 100644 --- a/content/browser/media/android/browser_media_player_manager.h +++ b/content/browser/media/android/browser_media_player_manager.h @@ -119,7 +119,9 @@ class CONTENT_EXPORT BrowserMediaPlayerManager virtual void OnSetVolume(int player_id, double volume); virtual void OnReleaseResources(int player_id); virtual void OnDestroyPlayer(int player_id); - void OnInitializeCDM(int media_keys_id, const std::vector<uint8>& uuid); + void OnInitializeCDM(int media_keys_id, + const std::vector<uint8>& uuid, + const GURL& frame_url); void OnGenerateKeyRequest(int media_keys_id, const std::string& type, const std::vector<uint8>& init_data); @@ -148,13 +150,21 @@ class CONTENT_EXPORT BrowserMediaPlayerManager int player_id, media::MediaPlayerAndroid* player); - // Add a new MediaDrmBridge for the given |uuid| and |media_keys_id|. - void AddDrmBridge(int media_keys_id, const std::vector<uint8>& uuid); + // Add a new MediaDrmBridge for the given |uuid|, |media_keys_id|, and + // |frame_url|. + void AddDrmBridge(int media_keys_id, + const std::vector<uint8>& uuid, + const GURL& frame_url); // Removes the DRM bridge with the specified id. void RemoveDrmBridge(int media_keys_id); private: + void GenerateKeyIfAllowed(int media_keys_id, + const std::string& type, + const std::vector<uint8>& init_data, + bool allowed); + // Constructs a MediaPlayerAndroid object. Declared static to permit embedders // to override functionality. // @@ -190,6 +200,8 @@ class CONTENT_EXPORT BrowserMediaPlayerManager // Object for retrieving resources media players. scoped_ptr<media::MediaResourceGetter> media_resource_getter_; + base::WeakPtrFactory<BrowserMediaPlayerManager> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(BrowserMediaPlayerManager); }; diff --git a/content/browser/media/android/media_drm_credential_manager.cc b/content/browser/media/android/media_drm_credential_manager.cc index 74e21d8..6545a70 100644 --- a/content/browser/media/android/media_drm_credential_manager.cc +++ b/content/browser/media/android/media_drm_credential_manager.cc @@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "media/base/android/media_drm_bridge.h" +#include "url/gurl.h" namespace content { @@ -50,7 +51,7 @@ bool MediaDrmCredentialManager::ResetCredentialsInternal( const std::string& security_level) { std::vector<uint8> uuid(kWidevineUuid, kWidevineUuid + 16); media_drm_bridge_ = media::MediaDrmBridge::Create( - 0, uuid, security_level, NULL); + 0, uuid, GURL(), security_level, NULL); if (!media_drm_bridge_) return false; media_drm_bridge_->ResetDeviceCredentials( diff --git a/content/common/media/media_player_messages_android.h b/content/common/media/media_player_messages_android.h index fbae4ac..8e952d1 100644 --- a/content/common/media/media_player_messages_android.h +++ b/content/common/media/media_player_messages_android.h @@ -229,9 +229,10 @@ IPC_MESSAGE_ROUTED3(MediaPlayerHostMsg_NotifyExternalSurface, // Messages for encrypted media extensions API ------------------------------ // TODO(xhwang): Move the following messages to a separate file. -IPC_MESSAGE_ROUTED2(MediaKeysHostMsg_InitializeCDM, +IPC_MESSAGE_ROUTED3(MediaKeysHostMsg_InitializeCDM, int /* media_keys_id */, - std::vector<uint8> /* uuid */) + std::vector<uint8> /* uuid */, + GURL /* frame url */) IPC_MESSAGE_ROUTED3(MediaKeysHostMsg_GenerateKeyRequest, int /* media_keys_id */, diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h index f4a889c..c660b2a 100644 --- a/content/public/browser/web_contents_delegate.h +++ b/content/public/browser/web_contents_delegate.h @@ -393,6 +393,13 @@ class CONTENT_EXPORT WebContentsDelegate { int version, const std::vector<gfx::RectF>& rects, const gfx::RectF& active_rect) {} + + // Request permission to access protected media identifier. The callback will + // tell whether it's allowed. + virtual void RequestProtectedMediaIdentifierPermission( + const WebContents* web_contents, + const GURL& frame_url, + const base::Callback<void(bool)>& callback) {} #endif // Invoked when the preferred size of the contents has been changed. diff --git a/content/renderer/media/android/proxy_media_keys.cc b/content/renderer/media/android/proxy_media_keys.cc index a012f67..2beb66a 100644 --- a/content/renderer/media/android/proxy_media_keys.cc +++ b/content/renderer/media/android/proxy_media_keys.cc @@ -19,13 +19,14 @@ ProxyMediaKeys::ProxyMediaKeys(WebMediaPlayerProxyAndroid* proxy, DCHECK(proxy_); } -void ProxyMediaKeys::InitializeCDM(const std::string& key_system) { +void ProxyMediaKeys::InitializeCDM(const std::string& key_system, + const GURL& frame_url) { #if defined(ENABLE_PEPPER_CDMS) NOTIMPLEMENTED(); #elif defined(OS_ANDROID) std::vector<uint8> uuid = GetUUID(key_system); DCHECK(!uuid.empty()); - proxy_->InitializeCDM(media_keys_id_, uuid); + proxy_->InitializeCDM(media_keys_id_, uuid, frame_url); #endif } diff --git a/content/renderer/media/android/proxy_media_keys.h b/content/renderer/media/android/proxy_media_keys.h index ca13279..847a782 100644 --- a/content/renderer/media/android/proxy_media_keys.h +++ b/content/renderer/media/android/proxy_media_keys.h @@ -8,6 +8,8 @@ #include "base/basictypes.h" #include "media/base/media_keys.h" +class GURL; + namespace content { class WebMediaPlayerProxyAndroid; @@ -20,7 +22,7 @@ class ProxyMediaKeys : public media::MediaKeys { public: ProxyMediaKeys(WebMediaPlayerProxyAndroid* proxy, int media_keys_id); - void InitializeCDM(const std::string& key_system); + void InitializeCDM(const std::string& key_system, const GURL& frame_url); // MediaKeys implementation. virtual bool GenerateKeyRequest(const std::string& type, diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc index 575ca17..ba505fc 100644 --- a/content/renderer/media/android/webmediaplayer_android.cc +++ b/content/renderer/media/android/webmediaplayer_android.cc @@ -1017,7 +1017,7 @@ WebMediaPlayerAndroid::GenerateKeyRequestInternal( // We do not support run-time switching between key systems for now. if (current_key_system_.isEmpty()) { - if (!decryptor_->InitializeCDM(key_system.utf8())) + if (!decryptor_->InitializeCDM(key_system.utf8(), frame_->document().url())) return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; current_key_system_ = key_system; } else if (key_system != current_key_system_) { diff --git a/content/renderer/media/android/webmediaplayer_proxy_android.cc b/content/renderer/media/android/webmediaplayer_proxy_android.cc index d290edb..39e87a0 100644 --- a/content/renderer/media/android/webmediaplayer_proxy_android.cc +++ b/content/renderer/media/android/webmediaplayer_proxy_android.cc @@ -200,8 +200,10 @@ void WebMediaPlayerProxyAndroid::DidCommitCompositorFrame() { #endif void WebMediaPlayerProxyAndroid::InitializeCDM(int media_keys_id, - const std::vector<uint8>& uuid) { - Send(new MediaKeysHostMsg_InitializeCDM(routing_id(), media_keys_id, uuid)); + const std::vector<uint8>& uuid, + const GURL& frame_url) { + Send(new MediaKeysHostMsg_InitializeCDM( + routing_id(), media_keys_id, uuid, frame_url)); } void WebMediaPlayerProxyAndroid::GenerateKeyRequest( diff --git a/content/renderer/media/android/webmediaplayer_proxy_android.h b/content/renderer/media/android/webmediaplayer_proxy_android.h index 209f8d2..76d2d43 100644 --- a/content/renderer/media/android/webmediaplayer_proxy_android.h +++ b/content/renderer/media/android/webmediaplayer_proxy_android.h @@ -84,7 +84,9 @@ class WebMediaPlayerProxyAndroid : public RenderViewObserver { #endif // Encrypted media related methods. - void InitializeCDM(int media_keys_id, const std::vector<uint8>& uuid); + void InitializeCDM(int media_keys_id, + const std::vector<uint8>& uuid, + const GURL& frame_url); void GenerateKeyRequest(int media_keys_id, const std::string& type, const std::vector<uint8>& init_data); diff --git a/content/renderer/media/crypto/content_decryption_module_factory.cc b/content/renderer/media/crypto/content_decryption_module_factory.cc index 1e33528..e53fa17 100644 --- a/content/renderer/media/crypto/content_decryption_module_factory.cc +++ b/content/renderer/media/crypto/content_decryption_module_factory.cc @@ -96,6 +96,7 @@ scoped_ptr<media::MediaKeys> ContentDecryptionModuleFactory::Create( #elif defined(OS_ANDROID) WebMediaPlayerProxyAndroid* proxy, int media_keys_id, + const GURL& frame_url, #endif // defined(ENABLE_PEPPER_CDMS) const media::KeyAddedCB& key_added_cb, const media::KeyErrorCB& key_error_cb, @@ -117,7 +118,7 @@ scoped_ptr<media::MediaKeys> ContentDecryptionModuleFactory::Create( #elif defined(OS_ANDROID) scoped_ptr<ProxyMediaKeys> proxy_media_keys( new ProxyMediaKeys(proxy, media_keys_id)); - proxy_media_keys->InitializeCDM(key_system); + proxy_media_keys->InitializeCDM(key_system, frame_url); return proxy_media_keys.PassAs<media::MediaKeys>(); #else return scoped_ptr<media::MediaKeys>(); diff --git a/content/renderer/media/crypto/content_decryption_module_factory.h b/content/renderer/media/crypto/content_decryption_module_factory.h index cb435cd..01ab731 100644 --- a/content/renderer/media/crypto/content_decryption_module_factory.h +++ b/content/renderer/media/crypto/content_decryption_module_factory.h @@ -10,6 +10,8 @@ #include "base/memory/scoped_ptr.h" #include "media/base/media_keys.h" +class GURL; + #if defined(ENABLE_PEPPER_CDMS) namespace WebKit { class WebFrame; @@ -33,6 +35,7 @@ class ContentDecryptionModuleFactory { #elif defined(OS_ANDROID) WebMediaPlayerProxyAndroid* proxy, int media_keys_id, + const GURL& frame_url, #endif // defined(ENABLE_PEPPER_CDMS) const media::KeyAddedCB& key_added_cb, const media::KeyErrorCB& key_error_cb, diff --git a/content/renderer/media/crypto/proxy_decryptor.cc b/content/renderer/media/crypto/proxy_decryptor.cc index 53fae47..c50080f 100644 --- a/content/renderer/media/crypto/proxy_decryptor.cc +++ b/content/renderer/media/crypto/proxy_decryptor.cc @@ -75,13 +75,14 @@ void ProxyDecryptor::SetDecryptorReadyCB( decryptor_ready_cb_ = decryptor_ready_cb; } -bool ProxyDecryptor::InitializeCDM(const std::string& key_system) { +bool ProxyDecryptor::InitializeCDM(const std::string& key_system, + const GURL& frame_url) { DVLOG(1) << "InitializeCDM: key_system = " << key_system; base::AutoLock auto_lock(lock_); DCHECK(!media_keys_); - media_keys_ = CreateMediaKeys(key_system); + media_keys_ = CreateMediaKeys(key_system, frame_url); return media_keys_ != NULL; } @@ -119,7 +120,8 @@ void ProxyDecryptor::CancelKeyRequest(const std::string& session_id) { } scoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys( - const std::string& key_system) { + const std::string& key_system, + const GURL& frame_url) { return ContentDecryptionModuleFactory::Create( key_system, #if defined(ENABLE_PEPPER_CDMS) @@ -130,6 +132,7 @@ scoped_ptr<media::MediaKeys> ProxyDecryptor::CreateMediaKeys( #elif defined(OS_ANDROID) proxy_, media_keys_id_, + frame_url, #endif // defined(ENABLE_PEPPER_CDMS) base::Bind(&ProxyDecryptor::KeyAdded, weak_ptr_factory_.GetWeakPtr()), base::Bind(&ProxyDecryptor::KeyError, weak_ptr_factory_.GetWeakPtr()), diff --git a/content/renderer/media/crypto/proxy_decryptor.h b/content/renderer/media/crypto/proxy_decryptor.h index 399665f..0202721 100644 --- a/content/renderer/media/crypto/proxy_decryptor.h +++ b/content/renderer/media/crypto/proxy_decryptor.h @@ -15,6 +15,8 @@ #include "media/base/decryptor.h" #include "media/base/media_keys.h" +class GURL; + namespace WebKit { #if defined(ENABLE_PEPPER_CDMS) class WebFrame; @@ -48,7 +50,7 @@ class ProxyDecryptor : public media::MediaKeys { virtual ~ProxyDecryptor(); // Only call this once. - bool InitializeCDM(const std::string& key_system); + bool InitializeCDM(const std::string& key_system, const GURL& frame_url); // Requests the ProxyDecryptor to notify the decryptor when it's ready through // the |decryptor_ready_cb| provided. @@ -68,7 +70,8 @@ class ProxyDecryptor : public media::MediaKeys { private: // Helper function to create MediaKeys to handle the given |key_system|. - scoped_ptr<media::MediaKeys> CreateMediaKeys(const std::string& key_system); + scoped_ptr<media::MediaKeys> CreateMediaKeys(const std::string& key_system, + const GURL& frame_url); // Callbacks for firing key events. void KeyAdded(const std::string& session_id); diff --git a/content/renderer/media/webcontentdecryptionmodule_impl.cc b/content/renderer/media/webcontentdecryptionmodule_impl.cc index 0a430ad..a70ad2a 100644 --- a/content/renderer/media/webcontentdecryptionmodule_impl.cc +++ b/content/renderer/media/webcontentdecryptionmodule_impl.cc @@ -16,6 +16,7 @@ #include "content/renderer/media/crypto/content_decryption_module_factory.h" #include "content/renderer/media/webcontentdecryptionmodulesession_impl.h" #include "media/base/media_keys.h" +#include "url/gurl.h" namespace content { @@ -87,6 +88,8 @@ bool SessionIdAdapter::Initialize(const std::string& key_system, // TODO(xhwang): Support Android. NULL, 0, + // TODO(ddorwin): Get the URL for the frame containing the MediaKeys. + GURL(), #endif // defined(ENABLE_PEPPER_CDMS) base::Bind(&SessionIdAdapter::KeyAdded, weak_this), base::Bind(&SessionIdAdapter::KeyError, weak_this), diff --git a/content/renderer/media/webmediaplayer_impl.cc b/content/renderer/media/webmediaplayer_impl.cc index a99c3ae..9710b90 100644 --- a/content/renderer/media/webmediaplayer_impl.cc +++ b/content/renderer/media/webmediaplayer_impl.cc @@ -53,6 +53,7 @@ #include "third_party/WebKit/public/platform/WebSize.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebURL.h" +#include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebRuntimeFeatures.h" #include "third_party/WebKit/public/web/WebView.h" #include "v8/include/v8.h" @@ -728,7 +729,7 @@ WebMediaPlayerImpl::GenerateKeyRequestInternal( // We do not support run-time switching between key systems for now. if (current_key_system_.isEmpty()) { - if (!decryptor_->InitializeCDM(key_system.utf8())) + if (!decryptor_->InitializeCDM(key_system.utf8(), frame_->document().url())) return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; current_key_system_ = key_system; } diff --git a/media/base/android/media_drm_bridge.cc b/media/base/android/media_drm_bridge.cc index 4badaf1..95f38ed 100644 --- a/media/base/android/media_drm_bridge.cc +++ b/media/base/android/media_drm_bridge.cc @@ -157,14 +157,15 @@ static MediaDrmBridge::SecurityLevel GetSecurityLevelFromString( scoped_ptr<MediaDrmBridge> MediaDrmBridge::Create( int media_keys_id, const std::vector<uint8>& scheme_uuid, + const GURL& frame_url, const std::string& security_level, MediaPlayerManager* manager) { scoped_ptr<MediaDrmBridge> media_drm_bridge; if (IsAvailable() && !scheme_uuid.empty()) { // TODO(qinmin): check whether the uuid is valid. - media_drm_bridge.reset( - new MediaDrmBridge(media_keys_id, scheme_uuid, security_level, manager)); + media_drm_bridge.reset(new MediaDrmBridge( + media_keys_id, scheme_uuid, frame_url, security_level, manager)); if (media_drm_bridge->j_media_drm_.is_null()) media_drm_bridge.reset(); } @@ -190,7 +191,8 @@ bool MediaDrmBridge::IsSecurityLevelSupported( const std::string& security_level) { // Pass 0 as |media_keys_id| and NULL as |manager| as they are not used in // creation time of MediaDrmBridge. - return MediaDrmBridge::Create(0, scheme_uuid, security_level, NULL) != NULL; + return MediaDrmBridge::Create(0, scheme_uuid, GURL(), security_level, NULL) != + NULL; } bool MediaDrmBridge::IsCryptoSchemeSupported( @@ -211,10 +213,12 @@ bool MediaDrmBridge::RegisterMediaDrmBridge(JNIEnv* env) { MediaDrmBridge::MediaDrmBridge(int media_keys_id, const std::vector<uint8>& scheme_uuid, + const GURL& frame_url, const std::string& security_level, MediaPlayerManager* manager) : media_keys_id_(media_keys_id), scheme_uuid_(scheme_uuid), + frame_url_(frame_url), manager_(manager) { JNIEnv* env = AttachCurrentThread(); CHECK(env); diff --git a/media/base/android/media_drm_bridge.h b/media/base/android/media_drm_bridge.h index 3ca94f3..0399beb 100644 --- a/media/base/android/media_drm_bridge.h +++ b/media/base/android/media_drm_bridge.h @@ -14,6 +14,9 @@ #include "base/memory/scoped_ptr.h" #include "media/base/media_export.h" #include "media/base/media_keys.h" +#include "url/gurl.h" + +class GURL; namespace media { @@ -38,6 +41,7 @@ class MEDIA_EXPORT MediaDrmBridge : public MediaKeys { static scoped_ptr<MediaDrmBridge> Create( int media_keys_id, const std::vector<uint8>& scheme_uuid, + const GURL& frame_url, const std::string& security_level, MediaPlayerManager* manager); @@ -96,6 +100,8 @@ class MEDIA_EXPORT MediaDrmBridge : public MediaKeys { int media_keys_id() const { return media_keys_id_; } + GURL frame_url() const { return frame_url_; } + static void set_can_use_media_drm(bool can_use_media_drm) { can_use_media_drm_ = can_use_media_drm; } @@ -107,6 +113,7 @@ class MEDIA_EXPORT MediaDrmBridge : public MediaKeys { MediaDrmBridge(int media_keys_id, const std::vector<uint8>& scheme_uuid, + const GURL& frame_url, const std::string& security_level, MediaPlayerManager* manager); @@ -119,6 +126,9 @@ class MEDIA_EXPORT MediaDrmBridge : public MediaKeys { // UUID of the key system. std::vector<uint8> scheme_uuid_; + // media stream's frame URL. + const GURL frame_url_; + // Java MediaDrm instance. base::android::ScopedJavaGlobalRef<jobject> j_media_drm_; |