Home | History | Annotate | Download | only in webui
      1 // Copyright (c) 2011 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/webui/mediaplayer_ui.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/logging.h"
      9 #include "base/memory/singleton.h"
     10 #include "base/memory/weak_ptr.h"
     11 #include "base/message_loop.h"
     12 #include "base/path_service.h"
     13 #include "base/string_piece.h"
     14 #include "base/string_util.h"
     15 #include "base/threading/thread.h"
     16 #include "base/time.h"
     17 #include "base/values.h"
     18 #include "chrome/browser/bookmarks/bookmark_model.h"
     19 #include "chrome/browser/download/download_manager.h"
     20 #include "chrome/browser/download/download_util.h"
     21 #include "chrome/browser/extensions/file_manager_util.h"
     22 #include "chrome/browser/history/history_types.h"
     23 #include "chrome/browser/metrics/user_metrics.h"
     24 #include "chrome/browser/profiles/profile.h"
     25 #include "chrome/browser/tabs/tab_strip_model.h"
     26 #include "chrome/browser/ui/browser.h"
     27 #include "chrome/browser/ui/browser_list.h"
     28 #include "chrome/browser/ui/browser_window.h"
     29 #include "chrome/browser/ui/webui/favicon_source.h"
     30 #include "chrome/common/chrome_paths.h"
     31 #include "chrome/common/chrome_switches.h"
     32 #include "chrome/common/jstemplate_builder.h"
     33 #include "chrome/common/net/url_fetcher.h"
     34 #include "chrome/common/time_format.h"
     35 #include "chrome/common/url_constants.h"
     36 #include "content/browser/browser_thread.h"
     37 #include "content/browser/tab_contents/tab_contents.h"
     38 #include "grit/browser_resources.h"
     39 #include "grit/chromium_strings.h"
     40 #include "grit/generated_resources.h"
     41 #include "grit/locale_settings.h"
     42 #include "net/base/escape.h"
     43 #include "net/base/load_flags.h"
     44 #include "net/url_request/url_request_job.h"
     45 #include "ui/base/resource/resource_bundle.h"
     46 
     47 #if defined(OS_CHROMEOS)
     48 #include "chrome/browser/chromeos/frame/panel_browser_view.h"
     49 #endif
     50 
     51 static const char kPropertyPath[] = "path";
     52 static const char kPropertyForce[] = "force";
     53 static const char kPropertyOffset[] = "currentOffset";
     54 static const char kPropertyError[] = "error";
     55 
     56 static const char* kMediaplayerURL = "chrome://mediaplayer";
     57 static const char* kMediaplayerPlaylistURL = "chrome://mediaplayer#playlist";
     58 static const int kPopupLeft = 0;
     59 static const int kPopupTop = 0;
     60 static const int kPopupWidth = 350;
     61 static const int kPopupHeight = 300;
     62 
     63 class MediaplayerUIHTMLSource : public ChromeURLDataManager::DataSource {
     64  public:
     65   explicit MediaplayerUIHTMLSource(bool is_playlist);
     66 
     67   // Called when the network layer has requested a resource underneath
     68   // the path we registered.
     69   virtual void StartDataRequest(const std::string& path,
     70                                 bool is_incognito,
     71                                 int request_id);
     72   virtual std::string GetMimeType(const std::string&) const {
     73     return "text/html";
     74   }
     75 
     76  private:
     77   ~MediaplayerUIHTMLSource() {}
     78   bool is_playlist_;
     79 
     80   DISALLOW_COPY_AND_ASSIGN(MediaplayerUIHTMLSource);
     81 };
     82 
     83 // The handler for Javascript messages related to the "mediaplayer" view.
     84 class MediaplayerHandler : public WebUIMessageHandler,
     85                            public base::SupportsWeakPtr<MediaplayerHandler> {
     86  public:
     87 
     88   struct MediaUrl {
     89     MediaUrl() {}
     90     explicit MediaUrl(const GURL& newurl)
     91         : url(newurl),
     92           haderror(false) {}
     93     GURL url;
     94     bool haderror;
     95   };
     96   typedef std::vector<MediaUrl> UrlVector;
     97 
     98   explicit MediaplayerHandler(bool is_playlist);
     99 
    100   virtual ~MediaplayerHandler();
    101 
    102   // Init work after Attach.
    103   void Init(bool is_playlist, TabContents* contents);
    104 
    105   // WebUIMessageHandler implementation.
    106   virtual WebUIMessageHandler* Attach(WebUI* web_ui);
    107   virtual void RegisterMessages();
    108 
    109   // Callback for the "currentOffsetChanged" message.
    110   void HandleCurrentOffsetChanged(const ListValue* args);
    111 
    112   void FirePlaylistChanged(const std::string& path,
    113                            bool force,
    114                            int offset);
    115 
    116   void PlaybackMediaFile(const GURL& url);
    117 
    118   void EnqueueMediaFileUrl(const GURL& url);
    119 
    120   void GetPlaylistValue(ListValue& args);
    121 
    122   // Callback for the "playbackError" message.
    123   void HandlePlaybackError(const ListValue* args);
    124 
    125   // Callback for the "getCurrentPlaylist" message.
    126   void HandleGetCurrentPlaylist(const ListValue* args);
    127 
    128   void HandleTogglePlaylist(const ListValue* args);
    129   void HandleShowPlaylist(const ListValue* args);
    130   void HandleSetCurrentPlaylistOffset(const ListValue* args);
    131   void HandleToggleFullscreen(const ListValue* args);
    132 
    133   const UrlVector& GetCurrentPlaylist();
    134 
    135   int GetCurrentPlaylistOffset();
    136   void SetCurrentPlaylistOffset(int offset);
    137   // Sets  the playlist for playlist views, since the playlist is
    138   // maintained by the mediaplayer itself.  Offset is the item in the
    139   // playlist which is either now playing, or should be played.
    140   void SetCurrentPlaylist(const UrlVector& playlist, int offset);
    141 
    142  private:
    143   // The current playlist of urls.
    144   UrlVector current_playlist_;
    145   // The offset into the current_playlist_ of the currently playing item.
    146   int current_offset_;
    147   // Indicator of if this handler is a playlist or a mediaplayer.
    148   bool is_playlist_;
    149   DISALLOW_COPY_AND_ASSIGN(MediaplayerHandler);
    150 };
    151 
    152 ////////////////////////////////////////////////////////////////////////////////
    153 //
    154 // MediaplayerHTMLSource
    155 //
    156 ////////////////////////////////////////////////////////////////////////////////
    157 
    158 MediaplayerUIHTMLSource::MediaplayerUIHTMLSource(bool is_playlist)
    159     : DataSource(chrome::kChromeUIMediaplayerHost, MessageLoop::current()) {
    160   is_playlist_ = is_playlist;
    161 }
    162 
    163 void MediaplayerUIHTMLSource::StartDataRequest(const std::string& path,
    164                                                bool is_incognito,
    165                                                int request_id) {
    166   DictionaryValue localized_strings;
    167   // TODO(dhg): Fix the strings that are currently hardcoded so they
    168   // use the localized versions.
    169   localized_strings.SetString("errorstring", "Error Playing Back");
    170 
    171   SetFontAndTextDirection(&localized_strings);
    172 
    173   std::string full_html;
    174 
    175   static const base::StringPiece mediaplayer_html(
    176       ResourceBundle::GetSharedInstance().GetRawDataResource(
    177           IDR_MEDIAPLAYER_HTML));
    178 
    179   static const base::StringPiece playlist_html(
    180       ResourceBundle::GetSharedInstance().GetRawDataResource(
    181           IDR_MEDIAPLAYERPLAYLIST_HTML));
    182 
    183   if (is_playlist_) {
    184     full_html = jstemplate_builder::GetI18nTemplateHtml(
    185         playlist_html, &localized_strings);
    186   } else {
    187     full_html = jstemplate_builder::GetI18nTemplateHtml(
    188         mediaplayer_html, &localized_strings);
    189   }
    190 
    191   scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
    192   html_bytes->data.resize(full_html.size());
    193   std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
    194 
    195   SendResponse(request_id, html_bytes);
    196 }
    197 
    198 ////////////////////////////////////////////////////////////////////////////////
    199 //
    200 // MediaplayerHandler
    201 //
    202 ////////////////////////////////////////////////////////////////////////////////
    203 MediaplayerHandler::MediaplayerHandler(bool is_playlist)
    204     : current_offset_(0),
    205       is_playlist_(is_playlist) {
    206 }
    207 
    208 MediaplayerHandler::~MediaplayerHandler() {
    209 }
    210 
    211 WebUIMessageHandler* MediaplayerHandler::Attach(WebUI* web_ui) {
    212   // Create our favicon data source.
    213   Profile* profile = web_ui->GetProfile();
    214   profile->GetChromeURLDataManager()->AddDataSource(
    215       new FaviconSource(profile));
    216 
    217   return WebUIMessageHandler::Attach(web_ui);
    218 }
    219 
    220 void MediaplayerHandler::Init(bool is_playlist, TabContents* contents) {
    221   MediaPlayer* player = MediaPlayer::GetInstance();
    222   if (!is_playlist) {
    223     player->SetNewHandler(this, contents);
    224   } else {
    225     player->RegisterNewPlaylistHandler(this, contents);
    226   }
    227 }
    228 
    229 void MediaplayerHandler::RegisterMessages() {
    230   web_ui_->RegisterMessageCallback("currentOffsetChanged",
    231       NewCallback(this, &MediaplayerHandler::HandleCurrentOffsetChanged));
    232   web_ui_->RegisterMessageCallback("playbackError",
    233       NewCallback(this, &MediaplayerHandler::HandlePlaybackError));
    234   web_ui_->RegisterMessageCallback("getCurrentPlaylist",
    235       NewCallback(this, &MediaplayerHandler::HandleGetCurrentPlaylist));
    236   web_ui_->RegisterMessageCallback("togglePlaylist",
    237       NewCallback(this, &MediaplayerHandler::HandleTogglePlaylist));
    238   web_ui_->RegisterMessageCallback("setCurrentPlaylistOffset",
    239       NewCallback(this, &MediaplayerHandler::HandleSetCurrentPlaylistOffset));
    240   web_ui_->RegisterMessageCallback("toggleFullscreen",
    241       NewCallback(this, &MediaplayerHandler::HandleToggleFullscreen));
    242   web_ui_->RegisterMessageCallback("showPlaylist",
    243       NewCallback(this, &MediaplayerHandler::HandleShowPlaylist));
    244 }
    245 
    246 void MediaplayerHandler::GetPlaylistValue(ListValue& urls) {
    247   for (size_t x = 0; x < current_playlist_.size(); x++) {
    248     DictionaryValue* url_value = new DictionaryValue();
    249     url_value->SetString(kPropertyPath, current_playlist_[x].url.spec());
    250     url_value->SetBoolean(kPropertyError, current_playlist_[x].haderror);
    251     urls.Append(url_value);
    252   }
    253 }
    254 
    255 void MediaplayerHandler::PlaybackMediaFile(const GURL& url) {
    256   current_playlist_.push_back(MediaplayerHandler::MediaUrl(url));
    257   FirePlaylistChanged(url.spec(), true, current_playlist_.size() - 1);
    258   MediaPlayer::GetInstance()->NotifyPlaylistChanged();
    259 }
    260 
    261 const MediaplayerHandler::UrlVector& MediaplayerHandler::GetCurrentPlaylist() {
    262   return current_playlist_;
    263 }
    264 
    265 int MediaplayerHandler::GetCurrentPlaylistOffset() {
    266   return current_offset_;
    267 }
    268 
    269 void MediaplayerHandler::HandleToggleFullscreen(const ListValue* args) {
    270   MediaPlayer::GetInstance()->ToggleFullscreen();
    271 }
    272 
    273 void MediaplayerHandler::HandleSetCurrentPlaylistOffset(const ListValue* args) {
    274   int id;
    275   CHECK(ExtractIntegerValue(args, &id));
    276   MediaPlayer::GetInstance()->SetPlaylistOffset(id);
    277 }
    278 
    279 void MediaplayerHandler::FirePlaylistChanged(const std::string& path,
    280                                              bool force,
    281                                              int offset) {
    282   DictionaryValue info_value;
    283   ListValue urls;
    284   GetPlaylistValue(urls);
    285   info_value.SetString(kPropertyPath, path);
    286   info_value.SetBoolean(kPropertyForce, force);
    287   info_value.SetInteger(kPropertyOffset, offset);
    288   web_ui_->CallJavascriptFunction("playlistChanged", info_value, urls);
    289 }
    290 
    291 void MediaplayerHandler::SetCurrentPlaylistOffset(int offset) {
    292   current_offset_ = offset;
    293   FirePlaylistChanged(std::string(), true, current_offset_);
    294 }
    295 
    296 void MediaplayerHandler::SetCurrentPlaylist(
    297     const MediaplayerHandler::UrlVector& playlist, int offset) {
    298   current_playlist_ = playlist;
    299   current_offset_ = offset;
    300   FirePlaylistChanged(std::string(), false, current_offset_);
    301 }
    302 
    303 void MediaplayerHandler::EnqueueMediaFileUrl(const GURL& url) {
    304   current_playlist_.push_back(MediaplayerHandler::MediaUrl(url));
    305   FirePlaylistChanged(url.spec(), false, current_offset_);
    306   MediaPlayer::GetInstance()->NotifyPlaylistChanged();
    307 }
    308 
    309 void MediaplayerHandler::HandleCurrentOffsetChanged(const ListValue* args) {
    310   CHECK(ExtractIntegerValue(args, &current_offset_));
    311   MediaPlayer::GetInstance()->NotifyPlaylistChanged();
    312 }
    313 
    314 void MediaplayerHandler::HandlePlaybackError(const ListValue* args) {
    315   std::string error;
    316   std::string url;
    317   // Get path string.
    318   if (args->GetString(0, &error))
    319     LOG(ERROR) << "Playback error" << error;
    320   if (args->GetString(1, &url)) {
    321     for (size_t x = 0; x < current_playlist_.size(); x++) {
    322       if (current_playlist_[x].url == GURL(url)) {
    323         current_playlist_[x].haderror = true;
    324       }
    325     }
    326     FirePlaylistChanged(std::string(), false, current_offset_);
    327   }
    328 }
    329 
    330 void MediaplayerHandler::HandleGetCurrentPlaylist(const ListValue* args) {
    331   FirePlaylistChanged(std::string(), false, current_offset_);
    332 }
    333 
    334 void MediaplayerHandler::HandleTogglePlaylist(const ListValue* args) {
    335   MediaPlayer::GetInstance()->TogglePlaylistWindowVisible();
    336 }
    337 
    338 void MediaplayerHandler::HandleShowPlaylist(const ListValue* args) {
    339   MediaPlayer::GetInstance()->ShowPlaylistWindow();
    340 }
    341 
    342 ////////////////////////////////////////////////////////////////////////////////
    343 //
    344 // Mediaplayer
    345 //
    346 ////////////////////////////////////////////////////////////////////////////////
    347 
    348 // Allows InvokeLater without adding refcounting. This class is a Singleton and
    349 // won't be deleted until it's last InvokeLater is run.
    350 DISABLE_RUNNABLE_METHOD_REFCOUNT(MediaPlayer);
    351 
    352 MediaPlayer::~MediaPlayer() {
    353 }
    354 
    355 // static
    356 MediaPlayer* MediaPlayer::GetInstance() {
    357   return Singleton<MediaPlayer>::get();
    358 }
    359 
    360 void MediaPlayer::EnqueueMediaFile(Profile* profile, const FilePath& file_path,
    361                                    Browser* creator) {
    362   static GURL origin_url(kMediaplayerURL);
    363   GURL url;
    364   if (!FileManagerUtil::ConvertFileToFileSystemUrl(profile, file_path,
    365                                                    origin_url, &url)) {
    366   }
    367   EnqueueMediaFileUrl(url, creator);
    368 }
    369 
    370 void MediaPlayer::EnqueueMediaFileUrl(const GURL& url, Browser* creator) {
    371   if (handler_ == NULL) {
    372     unhandled_urls_.push_back(url);
    373     PopupMediaPlayer(creator);
    374   } else {
    375     handler_->EnqueueMediaFileUrl(url);
    376   }
    377 }
    378 
    379 void MediaPlayer::ForcePlayMediaFile(Profile* profile,
    380                                      const FilePath& file_path,
    381                                      Browser* creator) {
    382   static GURL origin_url(kMediaplayerURL);
    383   GURL url;
    384   if (!FileManagerUtil::ConvertFileToFileSystemUrl(profile, file_path,
    385                                                    origin_url, &url)) {
    386   }
    387   ForcePlayMediaURL(url, creator);
    388 }
    389 
    390 void MediaPlayer::ForcePlayMediaURL(const GURL& url, Browser* creator) {
    391   if (handler_ == NULL) {
    392     unhandled_urls_.push_back(url);
    393     PopupMediaPlayer(creator);
    394   } else {
    395     handler_->PlaybackMediaFile(url);
    396   }
    397 }
    398 
    399 void MediaPlayer::TogglePlaylistWindowVisible() {
    400   if (playlist_browser_) {
    401     ClosePlaylistWindow();
    402   } else {
    403     ShowPlaylistWindow();
    404   }
    405 }
    406 
    407 void MediaPlayer::ShowPlaylistWindow() {
    408   if (playlist_browser_ == NULL) {
    409     PopupPlaylist(NULL);
    410   }
    411 }
    412 
    413 void MediaPlayer::ClosePlaylistWindow() {
    414   if (playlist_browser_ != NULL) {
    415     playlist_browser_->window()->Close();
    416   }
    417 }
    418 
    419 void MediaPlayer::SetPlaylistOffset(int offset) {
    420   if (handler_) {
    421     handler_->SetCurrentPlaylistOffset(offset);
    422   }
    423   if (playlist_) {
    424     playlist_->SetCurrentPlaylistOffset(offset);
    425   }
    426 }
    427 
    428 void MediaPlayer::SetNewHandler(MediaplayerHandler* handler,
    429                                 TabContents* contents) {
    430   handler_ = handler;
    431   mediaplayer_tab_ = contents;
    432   RegisterListeners();
    433   for (size_t x = 0; x < unhandled_urls_.size(); x++) {
    434     handler_->EnqueueMediaFileUrl(unhandled_urls_[x]);
    435   }
    436   unhandled_urls_.clear();
    437 }
    438 
    439 void MediaPlayer::RegisterListeners() {
    440   registrar_.RemoveAll();
    441   if (playlist_tab_) {
    442     registrar_.Add(this,
    443                    NotificationType::TAB_CONTENTS_DESTROYED,
    444                    Source<TabContents>(playlist_tab_));
    445   }
    446   if (mediaplayer_tab_) {
    447     registrar_.Add(this,
    448                    NotificationType::TAB_CONTENTS_DESTROYED,
    449                    Source<TabContents>(mediaplayer_tab_));
    450   }
    451 };
    452 
    453 void MediaPlayer::Observe(NotificationType type,
    454                           const NotificationSource& source,
    455                           const NotificationDetails& details) {
    456   DCHECK(type == NotificationType::TAB_CONTENTS_DESTROYED);
    457   if (Source<TabContents>(source).ptr() == mediaplayer_tab_) {
    458     RemoveHandler(handler_);
    459     RegisterListeners();
    460     ClosePlaylistWindow();
    461   } else if (Source<TabContents>(source).ptr() == playlist_tab_) {
    462     RemovePlaylistHandler(playlist_);
    463     RegisterListeners();
    464   }
    465 }
    466 
    467 void MediaPlayer::RegisterNewPlaylistHandler(MediaplayerHandler* handler,
    468                                              TabContents* contents) {
    469   playlist_ = handler;
    470   playlist_tab_ = contents;
    471   RegisterListeners();
    472   NotifyPlaylistChanged();
    473 }
    474 
    475 void MediaPlayer::RemovePlaylistHandler(MediaplayerHandler* handler) {
    476   if (handler == playlist_) {
    477     playlist_ = NULL;
    478     playlist_browser_ = NULL;
    479     playlist_tab_ = NULL;
    480   }
    481 }
    482 
    483 void MediaPlayer::NotifyPlaylistChanged() {
    484   if (handler_ && playlist_) {
    485     playlist_->SetCurrentPlaylist(handler_->GetCurrentPlaylist(),
    486                                   handler_->GetCurrentPlaylistOffset());
    487   }
    488 }
    489 
    490 void MediaPlayer::ToggleFullscreen() {
    491   if (handler_ && mediaplayer_browser_) {
    492     mediaplayer_browser_->ToggleFullscreenMode();
    493   }
    494 }
    495 
    496 void MediaPlayer::RemoveHandler(MediaplayerHandler* handler) {
    497   if (handler == handler_) {
    498     handler_ = NULL;
    499     mediaplayer_browser_ = NULL;
    500     mediaplayer_tab_ = NULL;
    501   }
    502 }
    503 
    504 void MediaPlayer::PopupPlaylist(Browser* creator) {
    505   Profile* profile = BrowserList::GetLastActive()->profile();
    506   playlist_browser_ = Browser::CreateForType(Browser::TYPE_APP_PANEL,
    507                                              profile);
    508   playlist_browser_->AddSelectedTabWithURL(GURL(kMediaplayerPlaylistURL),
    509                                            PageTransition::LINK);
    510   playlist_browser_->window()->SetBounds(gfx::Rect(kPopupLeft,
    511                                                    kPopupTop,
    512                                                    kPopupWidth,
    513                                                    kPopupHeight));
    514   playlist_browser_->window()->Show();
    515 }
    516 
    517 void MediaPlayer::PopupMediaPlayer(Browser* creator) {
    518   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    519     BrowserThread::PostTask(
    520         BrowserThread::UI, FROM_HERE,
    521         NewRunnableMethod(this, &MediaPlayer::PopupMediaPlayer,
    522                           static_cast<Browser*>(NULL)));
    523     return;
    524   }
    525   Profile* profile = BrowserList::GetLastActive()->profile();
    526   mediaplayer_browser_ = Browser::CreateForType(Browser::TYPE_APP_PANEL,
    527                                                 profile);
    528 #if defined(OS_CHROMEOS)
    529   // Since we are on chromeos, popups should be a PanelBrowserView,
    530   // so we can just cast it.
    531   if (creator) {
    532     chromeos::PanelBrowserView* creatorview =
    533         static_cast<chromeos::PanelBrowserView*>(creator->window());
    534     chromeos::PanelBrowserView* view =
    535         static_cast<chromeos::PanelBrowserView*>(
    536             mediaplayer_browser_->window());
    537     view->SetCreatorView(creatorview);
    538   }
    539 #endif
    540   mediaplayer_browser_->AddSelectedTabWithURL(GURL(kMediaplayerURL),
    541                                               PageTransition::LINK);
    542   mediaplayer_browser_->window()->SetBounds(gfx::Rect(kPopupLeft,
    543                                                       kPopupTop,
    544                                                       kPopupWidth,
    545                                                       kPopupHeight));
    546   mediaplayer_browser_->window()->Show();
    547 }
    548 
    549 net::URLRequestJob* MediaPlayer::MaybeIntercept(net::URLRequest* request) {
    550   // Don't attempt to intercept here as we want to wait until the mime
    551   // type is fully determined.
    552   return NULL;
    553 }
    554 
    555 // This is the list of mime types currently supported by the Google
    556 // Document Viewer.
    557 static const char* const supported_mime_type_list[] = {
    558   "audio/mpeg",
    559   "video/mp4",
    560   "audio/mp3"
    561 };
    562 
    563 net::URLRequestJob* MediaPlayer::MaybeInterceptResponse(
    564     net::URLRequest* request) {
    565   // Do not intercept this request if it is a download.
    566   if (request->load_flags() & net::LOAD_IS_DOWNLOAD) {
    567     return NULL;
    568   }
    569 
    570   std::string mime_type;
    571   request->GetMimeType(&mime_type);
    572   // If it is in our list of known URLs, enqueue the url then
    573   // Cancel the request so the mediaplayer can handle it when
    574   // it hits it in the playlist.
    575   if (supported_mime_types_.find(mime_type) != supported_mime_types_.end()) {
    576     if (request->referrer() != chrome::kChromeUIMediaplayerURL &&
    577         !request->referrer().empty()) {
    578       EnqueueMediaFileUrl(request->url(), NULL);
    579       request->Cancel();
    580     }
    581   }
    582   return NULL;
    583 }
    584 
    585 MediaPlayer::MediaPlayer()
    586     : handler_(NULL),
    587       playlist_(NULL),
    588       playlist_browser_(NULL),
    589       mediaplayer_browser_(NULL),
    590       mediaplayer_tab_(NULL),
    591       playlist_tab_(NULL) {
    592   for (size_t i = 0; i < arraysize(supported_mime_type_list); ++i) {
    593     supported_mime_types_.insert(supported_mime_type_list[i]);
    594   }
    595 };
    596 
    597 ////////////////////////////////////////////////////////////////////////////////
    598 //
    599 // MediaplayerUIContents
    600 //
    601 ////////////////////////////////////////////////////////////////////////////////
    602 
    603 MediaplayerUI::MediaplayerUI(TabContents* contents) : WebUI(contents) {
    604   const GURL& url = contents->GetURL();
    605   bool is_playlist = (url.ref() == "playlist");
    606   MediaplayerHandler* handler = new MediaplayerHandler(is_playlist);
    607   AddMessageHandler(handler->Attach(this));
    608   if (is_playlist) {
    609     handler->Init(true, contents);
    610   } else {
    611     handler->Init(false, contents);
    612   }
    613 
    614   MediaplayerUIHTMLSource* html_source =
    615       new MediaplayerUIHTMLSource(is_playlist);
    616 
    617   // Set up the chrome://mediaplayer/ source.
    618   contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
    619 }
    620