| Index: chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java | 
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java | 
| index 56e26b285f0398969b2b19491324df1a23e8e505..04d3061dbddddf48b5cb4477b99387f510113d4f 100644 | 
| --- a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java | 
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java | 
| @@ -5,12 +5,15 @@ | 
| package org.chromium.chrome.browser.media.ui; | 
|  | 
| import android.app.Activity; | 
| +import android.graphics.Bitmap; | 
| import android.media.AudioManager; | 
| +import android.os.Build; | 
| import android.text.TextUtils; | 
|  | 
| import org.chromium.base.ApplicationStatus; | 
| import org.chromium.base.Log; | 
| import org.chromium.chrome.R; | 
| +import org.chromium.chrome.browser.ChromeFeatureList; | 
| import org.chromium.chrome.browser.metrics.MediaSessionUMA; | 
| import org.chromium.chrome.browser.tab.EmptyTabObserver; | 
| import org.chromium.chrome.browser.tab.Tab; | 
| @@ -34,6 +37,8 @@ public class MediaSessionTabHelper { | 
| private static final String UNICODE_PLAY_CHARACTER = "\u25B6"; | 
|  | 
| private Tab mTab; | 
| +    private Bitmap mFavicon = null; | 
| +    private String mOrigin = null; | 
| private WebContents mWebContents; | 
| private WebContentsObserver mWebContentsObserver; | 
| private int mPreviousVolumeControlStream = AudioManager.USE_DEFAULT_STREAM_TYPE; | 
| @@ -93,13 +98,6 @@ public class MediaSessionTabHelper { | 
| hideNotification(); | 
| return; | 
| } | 
| -                String origin = mTab.getUrl(); | 
| -                try { | 
| -                    origin = UrlUtilities.formatUrlForSecurityDisplay(new URI(origin), true); | 
| -                } catch (URISyntaxException e) { | 
| -                    Log.e(TAG, "Unable to parse the origin from the URL. " | 
| -                            + "Showing the full URL instead."); | 
| -                } | 
|  | 
| mFallbackMetadata = null; | 
|  | 
| @@ -113,18 +111,20 @@ public class MediaSessionTabHelper { | 
| metadata = mFallbackMetadata; | 
| } | 
|  | 
| -                mNotificationInfoBuilder = new MediaNotificationInfo.Builder() | 
| -                        .setMetadata(metadata) | 
| -                        .setPaused(isPaused) | 
| -                        .setOrigin(origin) | 
| -                        .setTabId(mTab.getId()) | 
| -                        .setPrivate(mTab.isIncognito()) | 
| -                        .setIcon(R.drawable.audio_playing) | 
| -                        .setActions(MediaNotificationInfo.ACTION_PLAY_PAUSE | 
| -                                | MediaNotificationInfo.ACTION_SWIPEAWAY) | 
| -                        .setContentIntent(Tab.createBringTabToFrontIntent(mTab.getId())) | 
| -                        .setId(R.id.media_playback_notification) | 
| -                        .setListener(mControlsListener); | 
| +                mNotificationInfoBuilder = | 
| +                        new MediaNotificationInfo.Builder() | 
| +                                .setMetadata(metadata) | 
| +                                .setPaused(isPaused) | 
| +                                .setOrigin(mOrigin) | 
| +                                .setTabId(mTab.getId()) | 
| +                                .setPrivate(mTab.isIncognito()) | 
| +                                .setIcon(R.drawable.audio_playing) | 
| +                                .setLargeIcon(mFavicon) | 
| +                                .setActions(MediaNotificationInfo.ACTION_PLAY_PAUSE | 
| +                                        | MediaNotificationInfo.ACTION_SWIPEAWAY) | 
| +                                .setContentIntent(Tab.createBringTabToFrontIntent(mTab.getId())) | 
| +                                .setId(R.id.media_playback_notification) | 
| +                                .setListener(mControlsListener); | 
|  | 
| MediaNotificationManager.show(ApplicationStatus.getApplicationContext(), | 
| mNotificationInfoBuilder.build()); | 
| @@ -159,6 +159,46 @@ public class MediaSessionTabHelper { | 
| } | 
|  | 
| @Override | 
| +        public void onFaviconUpdated(Tab tab, Bitmap icon) { | 
| +            assert tab == mTab; | 
| +            // Don't update the large icon if using customized notification. Otherwise, the | 
| +            // lockscreen art will be the favicon. | 
| +            if (!ChromeFeatureList.isEnabled(ChromeFeatureList.MEDIA_STYLE_NOTIFICATION)) return; | 
| + | 
| +            if (!updateFavicon(icon)) return; | 
| + | 
| +            if (mNotificationInfoBuilder == null) return; | 
| + | 
| +            mNotificationInfoBuilder.setLargeIcon(mFavicon); | 
| +            MediaNotificationManager.show( | 
| +                    ApplicationStatus.getApplicationContext(), mNotificationInfoBuilder.build()); | 
| +        } | 
| + | 
| +        @Override | 
| +        public void onUrlUpdated(Tab tab) { | 
| +            assert tab == mTab; | 
| + | 
| +            String origin = mTab.getUrl(); | 
| +            try { | 
| +                origin = UrlUtilities.formatUrlForSecurityDisplay(new URI(origin), true); | 
| +            } catch (URISyntaxException e) { | 
| +                Log.e(TAG, "Unable to parse the origin from the URL. " | 
| +                                + "Using the full URL instead."); | 
| +            } | 
| + | 
| +            if (mOrigin != null && mOrigin.equals(origin)) return; | 
| +            mOrigin = origin; | 
| +            mFavicon = null; | 
| + | 
| +            if (mNotificationInfoBuilder == null) return; | 
| + | 
| +            mNotificationInfoBuilder.setOrigin(mOrigin); | 
| +            mNotificationInfoBuilder.setLargeIcon(mFavicon); | 
| +            MediaNotificationManager.show( | 
| +                    ApplicationStatus.getApplicationContext(), mNotificationInfoBuilder.build()); | 
| +        } | 
| + | 
| +        @Override | 
| public void onTitleUpdated(Tab tab) { | 
| assert tab == mTab; | 
| if (mNotificationInfoBuilder == null || mFallbackMetadata == null) return; | 
| @@ -240,4 +280,31 @@ public class MediaSessionTabHelper { | 
|  | 
| return windowAndroid.getActivity().get(); | 
| } | 
| + | 
| +    /** | 
| +     * Updates the best favicon if the given icon is better. | 
| +     * @return whether the best favicon is updated. | 
| +     */ | 
| +    private boolean updateFavicon(Bitmap icon) { | 
| +        if (icon == null) return false; | 
| + | 
| +        int largeIconSizeInDp = 0; | 
| +        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) { | 
| +            largeIconSizeInDp = 128; | 
| +        } else { | 
| +            // TODO(zqzhang): Get this value via Resource.getDimension() if N has a resource id. | 
| +            largeIconSizeInDp = 96; | 
| +        } | 
| +        int minimalIconSizeInPx = Math.round(largeIconSizeInDp * 0.75f); | 
| + | 
| +        if (icon.getWidth() < minimalIconSizeInPx || icon.getHeight() < minimalIconSizeInPx) { | 
| +            return false; | 
| +        } | 
| +        if (mFavicon != null && (icon.getWidth() < mFavicon.getWidth() | 
| +                                        || icon.getHeight() < mFavicon.getHeight())) { | 
| +            return false; | 
| +        } | 
| +        mFavicon = icon; | 
| +        return true; | 
| +    } | 
| } | 
|  |