Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.media.ui; | 5 package org.chromium.chrome.browser.media.ui; |
| 6 | 6 |
| 7 import android.app.Notification; | 7 import android.app.Notification; |
| 8 import android.app.PendingIntent; | 8 import android.app.PendingIntent; |
| 9 import android.app.Service; | 9 import android.app.Service; |
| 10 import android.content.BroadcastReceiver; | 10 import android.content.BroadcastReceiver; |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 29 import android.support.v7.app.NotificationCompat; | 29 import android.support.v7.app.NotificationCompat; |
| 30 import android.support.v7.media.MediaRouter; | 30 import android.support.v7.media.MediaRouter; |
| 31 import android.text.TextUtils; | 31 import android.text.TextUtils; |
| 32 import android.util.SparseArray; | 32 import android.util.SparseArray; |
| 33 import android.view.KeyEvent; | 33 import android.view.KeyEvent; |
| 34 | 34 |
| 35 import org.chromium.base.SysUtils; | 35 import org.chromium.base.SysUtils; |
| 36 import org.chromium.base.VisibleForTesting; | 36 import org.chromium.base.VisibleForTesting; |
| 37 import org.chromium.blink.mojom.MediaSessionAction; | 37 import org.chromium.blink.mojom.MediaSessionAction; |
| 38 import org.chromium.chrome.R; | 38 import org.chromium.chrome.R; |
| 39 import org.chromium.chrome.browser.ChromeApplication; | |
| 40 import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder; | |
| 39 import org.chromium.chrome.browser.notifications.NotificationConstants; | 41 import org.chromium.chrome.browser.notifications.NotificationConstants; |
| 40 import org.chromium.content_public.common.MediaMetadata; | 42 import org.chromium.content_public.common.MediaMetadata; |
| 41 | 43 |
| 42 import java.util.ArrayList; | 44 import java.util.ArrayList; |
| 43 import java.util.HashSet; | 45 import java.util.HashSet; |
| 44 import java.util.List; | 46 import java.util.List; |
| 45 import java.util.Set; | 47 import java.util.Set; |
| 46 | 48 |
| 47 import javax.annotation.Nullable; | 49 import javax.annotation.Nullable; |
| 48 | 50 |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 77 // Maps the notification ids to their corresponding notification managers. | 79 // Maps the notification ids to their corresponding notification managers. |
| 78 private static SparseArray<MediaNotificationManager> sManagers; | 80 private static SparseArray<MediaNotificationManager> sManagers; |
| 79 | 81 |
| 80 private final Context mContext; | 82 private final Context mContext; |
| 81 | 83 |
| 82 // ListenerService running for the notification. Only non-null when showing. | 84 // ListenerService running for the notification. Only non-null when showing. |
| 83 private ListenerService mService; | 85 private ListenerService mService; |
| 84 | 86 |
| 85 private SparseArray<MediaButtonInfo> mActionToButtonInfo; | 87 private SparseArray<MediaButtonInfo> mActionToButtonInfo; |
| 86 | 88 |
| 87 private NotificationCompat.Builder mNotificationBuilder; | 89 private ChromeNotificationBuilder mNotificationBuilder; |
| 88 | 90 |
| 89 private Bitmap mDefaultNotificationLargeIcon; | 91 private Bitmap mDefaultNotificationLargeIcon; |
| 90 | 92 |
| 91 // |mMediaNotificationInfo| should be not null if and only if the notificati on is showing. | 93 // |mMediaNotificationInfo| should be not null if and only if the notificati on is showing. |
| 92 private MediaNotificationInfo mMediaNotificationInfo; | 94 private MediaNotificationInfo mMediaNotificationInfo; |
| 93 | 95 |
| 94 private MediaSessionCompat mMediaSession; | 96 private MediaSessionCompat mMediaSession; |
| 95 | 97 |
| 96 private final MediaSessionCompat.Callback mMediaSessionCallback = | 98 private final MediaSessionCompat.Callback mMediaSessionCallback = |
| 97 new MediaSessionCompat.Callback() { | 99 new MediaSessionCompat.Callback() { |
| (...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 531 return sManagers.get(notificationId); | 533 return sManagers.get(notificationId); |
| 532 } | 534 } |
| 533 | 535 |
| 534 @VisibleForTesting | 536 @VisibleForTesting |
| 535 static boolean hasManagerForTesting(int notificationId) { | 537 static boolean hasManagerForTesting(int notificationId) { |
| 536 return getManager(notificationId) != null; | 538 return getManager(notificationId) != null; |
| 537 } | 539 } |
| 538 | 540 |
| 539 @VisibleForTesting | 541 @VisibleForTesting |
| 540 @Nullable | 542 @Nullable |
| 541 static NotificationCompat.Builder getNotificationBuilderForTesting( | 543 static ChromeNotificationBuilder getNotificationBuilderForTesting(int notifi cationId) { |
| 542 int notificationId) { | |
| 543 MediaNotificationManager manager = getManager(notificationId); | 544 MediaNotificationManager manager = getManager(notificationId); |
| 544 if (manager == null) return null; | 545 if (manager == null) return null; |
| 545 | 546 |
| 546 return manager.mNotificationBuilder; | 547 return manager.mNotificationBuilder; |
| 547 } | 548 } |
| 548 | 549 |
| 549 @VisibleForTesting | 550 @VisibleForTesting |
| 550 @Nullable | 551 @Nullable |
| 551 static MediaNotificationInfo getMediaNotificationInfoForTesting( | 552 static MediaNotificationInfo getMediaNotificationInfoForTesting( |
| 552 int notificationId) { | 553 int notificationId) { |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 709 return metadataBuilder.build(); | 710 return metadataBuilder.build(); |
| 710 } | 711 } |
| 711 | 712 |
| 712 private void updateNotification() { | 713 private void updateNotification() { |
| 713 if (mService == null) return; | 714 if (mService == null) return; |
| 714 | 715 |
| 715 if (mMediaNotificationInfo == null) return; | 716 if (mMediaNotificationInfo == null) return; |
| 716 | 717 |
| 717 updateMediaSession(); | 718 updateMediaSession(); |
| 718 | 719 |
| 719 mNotificationBuilder = new NotificationCompat.Builder(mContext); | 720 mNotificationBuilder = |
| 721 ((ChromeApplication) mContext) | |
|
nyquist
2017/02/28 07:33:17
I think you need to do mContext.getApplicationCont
mlamouri (slow - plz ping)
2017/02/28 15:23:11
+1. The context you are getting here is probably n
awdf
2017/02/28 18:09:05
Done.
| |
| 722 .createChromeNotificationBuilder(true, | |
| 723 NotificationConstants.CATEGORY_ID_GENERAL, | |
|
mlamouri (slow - plz ping)
2017/02/28 15:23:11
Should this be media?
awdf
2017/02/28 18:09:05
As discussed, we're going with GENERAL for now.
| |
| 724 mContext.getString(R.string.notification_categor y_general)); | |
| 720 setMediaStyleLayoutForNotificationBuilder(mNotificationBuilder); | 725 setMediaStyleLayoutForNotificationBuilder(mNotificationBuilder); |
| 721 | 726 |
| 722 mNotificationBuilder.setSmallIcon(mMediaNotificationInfo.notificationSma llIcon); | 727 mNotificationBuilder.setSmallIcon(mMediaNotificationInfo.notificationSma llIcon); |
| 723 mNotificationBuilder.setAutoCancel(false); | 728 mNotificationBuilder.setAutoCancel(false); |
| 724 mNotificationBuilder.setLocalOnly(true); | 729 mNotificationBuilder.setLocalOnly(true); |
| 725 mNotificationBuilder.setGroup(getNotificationGroupName()); | 730 mNotificationBuilder.setGroup(getNotificationGroupName()); |
| 726 mNotificationBuilder.setGroupSummary(true); | 731 mNotificationBuilder.setGroupSummary(true); |
| 727 | 732 |
| 728 if (mMediaNotificationInfo.supportsSwipeAway()) { | 733 if (mMediaNotificationInfo.supportsSwipeAway()) { |
| 729 mNotificationBuilder.setOngoing(!mMediaNotificationInfo.isPaused); | 734 mNotificationBuilder.setOngoing(!mMediaNotificationInfo.isPaused); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 841 } | 846 } |
| 842 | 847 |
| 843 private void activateAndroidMediaSession(int tabId) { | 848 private void activateAndroidMediaSession(int tabId) { |
| 844 if (mMediaNotificationInfo == null) return; | 849 if (mMediaNotificationInfo == null) return; |
| 845 if (mMediaNotificationInfo.tabId != tabId) return; | 850 if (mMediaNotificationInfo.tabId != tabId) return; |
| 846 if (!mMediaNotificationInfo.supportsPlayPause() || mMediaNotificationInf o.isPaused) return; | 851 if (!mMediaNotificationInfo.supportsPlayPause() || mMediaNotificationInf o.isPaused) return; |
| 847 if (mMediaSession == null) return; | 852 if (mMediaSession == null) return; |
| 848 mMediaSession.setActive(true); | 853 mMediaSession.setActive(true); |
| 849 } | 854 } |
| 850 | 855 |
| 851 private void setMediaStyleLayoutForNotificationBuilder(NotificationCompat.Bu ilder builder) { | 856 private void setMediaStyleLayoutForNotificationBuilder(ChromeNotificationBui lder builder) { |
| 852 setMediaStyleNotificationText(builder); | 857 setMediaStyleNotificationText(builder); |
| 853 if (!mMediaNotificationInfo.supportsPlayPause()) { | 858 if (!mMediaNotificationInfo.supportsPlayPause()) { |
| 854 builder.setLargeIcon(null); | 859 builder.setLargeIcon(null); |
| 855 } else if (mMediaNotificationInfo.notificationLargeIcon != null) { | 860 } else if (mMediaNotificationInfo.notificationLargeIcon != null) { |
| 856 builder.setLargeIcon(mMediaNotificationInfo.notificationLargeIcon); | 861 builder.setLargeIcon(mMediaNotificationInfo.notificationLargeIcon); |
| 857 } else if (!isRunningN()) { | 862 } else if (!isRunningN()) { |
| 858 if (mDefaultNotificationLargeIcon == null) { | 863 if (mDefaultNotificationLargeIcon == null) { |
| 859 int resourceId = (mMediaNotificationInfo.defaultNotificationLarg eIcon != 0) | 864 int resourceId = (mMediaNotificationInfo.defaultNotificationLarg eIcon != 0) |
| 860 ? mMediaNotificationInfo.defaultNotificationLargeIcon | 865 ? mMediaNotificationInfo.defaultNotificationLargeIcon |
| 861 : R.drawable.audio_playing_square; | 866 : R.drawable.audio_playing_square; |
| 862 mDefaultNotificationLargeIcon = downscaleIconToIdealSize( | 867 mDefaultNotificationLargeIcon = downscaleIconToIdealSize( |
| 863 BitmapFactory.decodeResource(mContext.getResources(), resour ceId)); | 868 BitmapFactory.decodeResource(mContext.getResources(), resour ceId)); |
| 864 } | 869 } |
| 865 builder.setLargeIcon(mDefaultNotificationLargeIcon); | 870 builder.setLargeIcon(mDefaultNotificationLargeIcon); |
| 866 } | 871 } |
| 867 // TODO(zqzhang): It's weird that setShowWhen() don't work on K. Calling setWhen() to force | 872 // TODO(zqzhang): It's weird that setShowWhen() don't work on K. Calling setWhen() to force |
| 868 // removing the time. | 873 // removing the time. |
| 869 builder.setShowWhen(false).setWhen(0); | 874 builder.setShowWhen(false).setWhen(0); |
| 870 | 875 |
| 871 addNotificationButtons(builder); | 876 addNotificationButtons(builder); |
| 872 } | 877 } |
| 873 | 878 |
| 874 private void addNotificationButtons(NotificationCompat.Builder builder) { | 879 private void addNotificationButtons(ChromeNotificationBuilder builder) { |
| 875 Set<Integer> actions = new HashSet<>(); | 880 Set<Integer> actions = new HashSet<>(); |
| 876 | 881 |
| 877 // TODO(zqzhang): handle other actions when play/pause is not supported? See | 882 // TODO(zqzhang): handle other actions when play/pause is not supported? See |
| 878 // https://crbug.com/667500 | 883 // https://crbug.com/667500 |
| 879 if (mMediaNotificationInfo.supportsPlayPause()) { | 884 if (mMediaNotificationInfo.supportsPlayPause()) { |
| 880 actions.addAll(mMediaNotificationInfo.mediaSessionActions); | 885 actions.addAll(mMediaNotificationInfo.mediaSessionActions); |
| 881 if (mMediaNotificationInfo.isPaused) { | 886 if (mMediaNotificationInfo.isPaused) { |
| 882 actions.remove(MediaSessionAction.PAUSE); | 887 actions.remove(MediaSessionAction.PAUSE); |
| 883 actions.add(MediaSessionAction.PLAY); | 888 actions.add(MediaSessionAction.PLAY); |
| 884 } else { | 889 } else { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 895 | 900 |
| 896 for (int action : bigViewActions) { | 901 for (int action : bigViewActions) { |
| 897 MediaButtonInfo buttonInfo = mActionToButtonInfo.get(action); | 902 MediaButtonInfo buttonInfo = mActionToButtonInfo.get(action); |
| 898 builder.addAction(buttonInfo.iconResId, | 903 builder.addAction(buttonInfo.iconResId, |
| 899 mContext.getResources().getString(buttonInfo.descriptionResI d), | 904 mContext.getResources().getString(buttonInfo.descriptionResI d), |
| 900 createPendingIntent(buttonInfo.intentString)); | 905 createPendingIntent(buttonInfo.intentString)); |
| 901 } | 906 } |
| 902 | 907 |
| 903 // Only apply MediaStyle when NotificationInfo supports play/pause. | 908 // Only apply MediaStyle when NotificationInfo supports play/pause. |
| 904 if (mMediaNotificationInfo.supportsPlayPause()) { | 909 if (mMediaNotificationInfo.supportsPlayPause()) { |
| 905 NotificationCompat.MediaStyle style = new NotificationCompat.MediaSt yle(); | 910 builder.setMediaStyle(mMediaSession, computeCompactViewActionIndices (bigViewActions), |
| 906 style.setMediaSession(mMediaSession.getSessionToken()); | 911 createPendingIntent(ListenerService.ACTION_CANCEL), true); |
| 907 | |
| 908 int[] compactViewActionIndices = computeCompactViewActionIndices(big ViewActions); | |
| 909 | |
| 910 style.setShowActionsInCompactView(compactViewActionIndices); | |
| 911 style.setCancelButtonIntent(createPendingIntent(ListenerService.ACTI ON_CANCEL)); | |
| 912 style.setShowCancelButton(true); | |
| 913 builder.setStyle(style); | |
| 914 } | 912 } |
| 915 } | 913 } |
| 916 | 914 |
| 917 private Bitmap drawableToBitmap(Drawable drawable) { | 915 private Bitmap drawableToBitmap(Drawable drawable) { |
| 918 if (!(drawable instanceof BitmapDrawable)) return null; | 916 if (!(drawable instanceof BitmapDrawable)) return null; |
| 919 | 917 |
| 920 BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; | 918 BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; |
| 921 return bitmapDrawable.getBitmap(); | 919 return bitmapDrawable.getBitmap(); |
| 922 } | 920 } |
| 923 | 921 |
| 924 private void setMediaStyleNotificationText(NotificationCompat.Builder builde r) { | 922 private void setMediaStyleNotificationText(ChromeNotificationBuilder builder ) { |
| 925 builder.setContentTitle(mMediaNotificationInfo.metadata.getTitle()); | 923 builder.setContentTitle(mMediaNotificationInfo.metadata.getTitle()); |
| 926 String artistAndAlbumText = getArtistAndAlbumText(mMediaNotificationInfo .metadata); | 924 String artistAndAlbumText = getArtistAndAlbumText(mMediaNotificationInfo .metadata); |
| 927 if (isRunningN() || !artistAndAlbumText.isEmpty()) { | 925 if (isRunningN() || !artistAndAlbumText.isEmpty()) { |
| 928 builder.setContentText(artistAndAlbumText); | 926 builder.setContentText(artistAndAlbumText); |
| 929 builder.setSubText(mMediaNotificationInfo.origin); | 927 builder.setSubText(mMediaNotificationInfo.origin); |
| 930 } else { | 928 } else { |
| 931 // Leaving ContentText empty looks bad, so move origin up to the Con tentText. | 929 // Leaving ContentText empty looks bad, so move origin up to the Con tentText. |
| 932 builder.setContentText(mMediaNotificationInfo.origin); | 930 builder.setContentText(mMediaNotificationInfo.origin); |
| 933 } | 931 } |
| 934 } | 932 } |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1068 | 1066 |
| 1069 return actionsArray; | 1067 return actionsArray; |
| 1070 } | 1068 } |
| 1071 | 1069 |
| 1072 static int[] convertIntegerListToIntArray(List<Integer> intList) { | 1070 static int[] convertIntegerListToIntArray(List<Integer> intList) { |
| 1073 int[] intArray = new int[intList.size()]; | 1071 int[] intArray = new int[intList.size()]; |
| 1074 for (int i = 0; i < intList.size(); ++i) intArray[i] = i; | 1072 for (int i = 0; i < intList.size(); ++i) intArray[i] = i; |
| 1075 return intArray; | 1073 return intArray; |
| 1076 } | 1074 } |
| 1077 } | 1075 } |
| OLD | NEW |