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 434 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
532 return sManagers.get(notificationId); | 534 return sManagers.get(notificationId); |
533 } | 535 } |
534 | 536 |
535 @VisibleForTesting | 537 @VisibleForTesting |
536 static boolean hasManagerForTesting(int notificationId) { | 538 static boolean hasManagerForTesting(int notificationId) { |
537 return getManager(notificationId) != null; | 539 return getManager(notificationId) != null; |
538 } | 540 } |
539 | 541 |
540 @VisibleForTesting | 542 @VisibleForTesting |
541 @Nullable | 543 @Nullable |
542 static NotificationCompat.Builder getNotificationBuilderForTesting( | 544 static ChromeNotificationBuilder getNotificationBuilderForTesting(int notifi
cationId) { |
543 int notificationId) { | |
544 MediaNotificationManager manager = getManager(notificationId); | 545 MediaNotificationManager manager = getManager(notificationId); |
545 if (manager == null) return null; | 546 if (manager == null) return null; |
546 | 547 |
547 return manager.mNotificationBuilder; | 548 return manager.mNotificationBuilder; |
548 } | 549 } |
549 | 550 |
550 @VisibleForTesting | 551 @VisibleForTesting |
551 @Nullable | 552 @Nullable |
552 static MediaNotificationInfo getMediaNotificationInfoForTesting( | 553 static MediaNotificationInfo getMediaNotificationInfoForTesting( |
553 int notificationId) { | 554 int notificationId) { |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
714 return metadataBuilder.build(); | 715 return metadataBuilder.build(); |
715 } | 716 } |
716 | 717 |
717 private void updateNotification() { | 718 private void updateNotification() { |
718 if (mService == null) return; | 719 if (mService == null) return; |
719 | 720 |
720 if (mMediaNotificationInfo == null) return; | 721 if (mMediaNotificationInfo == null) return; |
721 | 722 |
722 updateMediaSession(); | 723 updateMediaSession(); |
723 | 724 |
724 mNotificationBuilder = new NotificationCompat.Builder(mContext); | 725 mNotificationBuilder = |
| 726 ((ChromeApplication) mContext.getApplicationContext()) |
| 727 .createChromeNotificationBuilder(true, |
| 728 NotificationConstants.CATEGORY_ID_BROWSER, |
| 729 mContext.getString( |
| 730 org.chromium.chrome.R.string.notificatio
n_category_browser), |
| 731 NotificationConstants.CATEGORY_GROUP_ID_GENERAL, |
| 732 mContext.getString(org.chromium.chrome.R.string |
| 733 .notification_categor
y_group_general)); |
725 setMediaStyleLayoutForNotificationBuilder(mNotificationBuilder); | 734 setMediaStyleLayoutForNotificationBuilder(mNotificationBuilder); |
726 | 735 |
727 mNotificationBuilder.setSmallIcon(mMediaNotificationInfo.notificationSma
llIcon); | 736 mNotificationBuilder.setSmallIcon(mMediaNotificationInfo.notificationSma
llIcon); |
728 mNotificationBuilder.setAutoCancel(false); | 737 mNotificationBuilder.setAutoCancel(false); |
729 mNotificationBuilder.setLocalOnly(true); | 738 mNotificationBuilder.setLocalOnly(true); |
730 mNotificationBuilder.setGroup(getNotificationGroupName()); | 739 mNotificationBuilder.setGroup(getNotificationGroupName()); |
731 mNotificationBuilder.setGroupSummary(true); | 740 mNotificationBuilder.setGroupSummary(true); |
732 | 741 |
733 if (mMediaNotificationInfo.supportsSwipeAway()) { | 742 if (mMediaNotificationInfo.supportsSwipeAway()) { |
734 mNotificationBuilder.setOngoing(!mMediaNotificationInfo.isPaused); | 743 mNotificationBuilder.setOngoing(!mMediaNotificationInfo.isPaused); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
846 } | 855 } |
847 | 856 |
848 private void activateAndroidMediaSession(int tabId) { | 857 private void activateAndroidMediaSession(int tabId) { |
849 if (mMediaNotificationInfo == null) return; | 858 if (mMediaNotificationInfo == null) return; |
850 if (mMediaNotificationInfo.tabId != tabId) return; | 859 if (mMediaNotificationInfo.tabId != tabId) return; |
851 if (!mMediaNotificationInfo.supportsPlayPause() || mMediaNotificationInf
o.isPaused) return; | 860 if (!mMediaNotificationInfo.supportsPlayPause() || mMediaNotificationInf
o.isPaused) return; |
852 if (mMediaSession == null) return; | 861 if (mMediaSession == null) return; |
853 mMediaSession.setActive(true); | 862 mMediaSession.setActive(true); |
854 } | 863 } |
855 | 864 |
856 private void setMediaStyleLayoutForNotificationBuilder(NotificationCompat.Bu
ilder builder) { | 865 private void setMediaStyleLayoutForNotificationBuilder(ChromeNotificationBui
lder builder) { |
857 setMediaStyleNotificationText(builder); | 866 setMediaStyleNotificationText(builder); |
858 if (!mMediaNotificationInfo.supportsPlayPause()) { | 867 if (!mMediaNotificationInfo.supportsPlayPause()) { |
859 builder.setLargeIcon(null); | 868 builder.setLargeIcon(null); |
860 } else if (mMediaNotificationInfo.notificationLargeIcon != null) { | 869 } else if (mMediaNotificationInfo.notificationLargeIcon != null) { |
861 builder.setLargeIcon(mMediaNotificationInfo.notificationLargeIcon); | 870 builder.setLargeIcon(mMediaNotificationInfo.notificationLargeIcon); |
862 } else if (!isRunningN()) { | 871 } else if (!isRunningN()) { |
863 if (mDefaultNotificationLargeIcon == null) { | 872 if (mDefaultNotificationLargeIcon == null) { |
864 int resourceId = (mMediaNotificationInfo.defaultNotificationLarg
eIcon != 0) | 873 int resourceId = (mMediaNotificationInfo.defaultNotificationLarg
eIcon != 0) |
865 ? mMediaNotificationInfo.defaultNotificationLargeIcon | 874 ? mMediaNotificationInfo.defaultNotificationLargeIcon |
866 : R.drawable.audio_playing_square; | 875 : R.drawable.audio_playing_square; |
867 mDefaultNotificationLargeIcon = downscaleIconToIdealSize( | 876 mDefaultNotificationLargeIcon = downscaleIconToIdealSize( |
868 BitmapFactory.decodeResource(mContext.getResources(), resour
ceId)); | 877 BitmapFactory.decodeResource(mContext.getResources(), resour
ceId)); |
869 } | 878 } |
870 builder.setLargeIcon(mDefaultNotificationLargeIcon); | 879 builder.setLargeIcon(mDefaultNotificationLargeIcon); |
871 } | 880 } |
872 // TODO(zqzhang): It's weird that setShowWhen() don't work on K. Calling
setWhen() to force | 881 // TODO(zqzhang): It's weird that setShowWhen() don't work on K. Calling
setWhen() to force |
873 // removing the time. | 882 // removing the time. |
874 builder.setShowWhen(false).setWhen(0); | 883 builder.setShowWhen(false).setWhen(0); |
875 | 884 |
876 addNotificationButtons(builder); | 885 addNotificationButtons(builder); |
877 } | 886 } |
878 | 887 |
879 private void addNotificationButtons(NotificationCompat.Builder builder) { | 888 private void addNotificationButtons(ChromeNotificationBuilder builder) { |
880 Set<Integer> actions = new HashSet<>(); | 889 Set<Integer> actions = new HashSet<>(); |
881 | 890 |
882 // TODO(zqzhang): handle other actions when play/pause is not supported?
See | 891 // TODO(zqzhang): handle other actions when play/pause is not supported?
See |
883 // https://crbug.com/667500 | 892 // https://crbug.com/667500 |
884 if (mMediaNotificationInfo.supportsPlayPause()) { | 893 if (mMediaNotificationInfo.supportsPlayPause()) { |
885 actions.addAll(mMediaNotificationInfo.mediaSessionActions); | 894 actions.addAll(mMediaNotificationInfo.mediaSessionActions); |
886 if (mMediaNotificationInfo.isPaused) { | 895 if (mMediaNotificationInfo.isPaused) { |
887 actions.remove(MediaSessionAction.PAUSE); | 896 actions.remove(MediaSessionAction.PAUSE); |
888 actions.add(MediaSessionAction.PLAY); | 897 actions.add(MediaSessionAction.PLAY); |
889 } else { | 898 } else { |
(...skipping 10 matching lines...) Expand all Loading... |
900 | 909 |
901 for (int action : bigViewActions) { | 910 for (int action : bigViewActions) { |
902 MediaButtonInfo buttonInfo = mActionToButtonInfo.get(action); | 911 MediaButtonInfo buttonInfo = mActionToButtonInfo.get(action); |
903 builder.addAction(buttonInfo.iconResId, | 912 builder.addAction(buttonInfo.iconResId, |
904 mContext.getResources().getString(buttonInfo.descriptionResI
d), | 913 mContext.getResources().getString(buttonInfo.descriptionResI
d), |
905 createPendingIntent(buttonInfo.intentString)); | 914 createPendingIntent(buttonInfo.intentString)); |
906 } | 915 } |
907 | 916 |
908 // Only apply MediaStyle when NotificationInfo supports play/pause. | 917 // Only apply MediaStyle when NotificationInfo supports play/pause. |
909 if (mMediaNotificationInfo.supportsPlayPause()) { | 918 if (mMediaNotificationInfo.supportsPlayPause()) { |
910 NotificationCompat.MediaStyle style = new NotificationCompat.MediaSt
yle(); | 919 builder.setMediaStyle(mMediaSession, computeCompactViewActionIndices
(bigViewActions), |
911 style.setMediaSession(mMediaSession.getSessionToken()); | 920 createPendingIntent(ListenerService.ACTION_CANCEL), true); |
912 | |
913 int[] compactViewActionIndices = computeCompactViewActionIndices(big
ViewActions); | |
914 | |
915 style.setShowActionsInCompactView(compactViewActionIndices); | |
916 style.setCancelButtonIntent(createPendingIntent(ListenerService.ACTI
ON_CANCEL)); | |
917 style.setShowCancelButton(true); | |
918 builder.setStyle(style); | |
919 } | 921 } |
920 } | 922 } |
921 | 923 |
922 private Bitmap drawableToBitmap(Drawable drawable) { | 924 private Bitmap drawableToBitmap(Drawable drawable) { |
923 if (!(drawable instanceof BitmapDrawable)) return null; | 925 if (!(drawable instanceof BitmapDrawable)) return null; |
924 | 926 |
925 BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; | 927 BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; |
926 return bitmapDrawable.getBitmap(); | 928 return bitmapDrawable.getBitmap(); |
927 } | 929 } |
928 | 930 |
929 private void setMediaStyleNotificationText(NotificationCompat.Builder builde
r) { | 931 private void setMediaStyleNotificationText(ChromeNotificationBuilder builder
) { |
930 builder.setContentTitle(mMediaNotificationInfo.metadata.getTitle()); | 932 builder.setContentTitle(mMediaNotificationInfo.metadata.getTitle()); |
931 String artistAndAlbumText = getArtistAndAlbumText(mMediaNotificationInfo
.metadata); | 933 String artistAndAlbumText = getArtistAndAlbumText(mMediaNotificationInfo
.metadata); |
932 if (isRunningN() || !artistAndAlbumText.isEmpty()) { | 934 if (isRunningN() || !artistAndAlbumText.isEmpty()) { |
933 builder.setContentText(artistAndAlbumText); | 935 builder.setContentText(artistAndAlbumText); |
934 builder.setSubText(mMediaNotificationInfo.origin); | 936 builder.setSubText(mMediaNotificationInfo.origin); |
935 } else { | 937 } else { |
936 // Leaving ContentText empty looks bad, so move origin up to the Con
tentText. | 938 // Leaving ContentText empty looks bad, so move origin up to the Con
tentText. |
937 builder.setContentText(mMediaNotificationInfo.origin); | 939 builder.setContentText(mMediaNotificationInfo.origin); |
938 } | 940 } |
939 } | 941 } |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1073 | 1075 |
1074 return actionsArray; | 1076 return actionsArray; |
1075 } | 1077 } |
1076 | 1078 |
1077 static int[] convertIntegerListToIntArray(List<Integer> intList) { | 1079 static int[] convertIntegerListToIntArray(List<Integer> intList) { |
1078 int[] intArray = new int[intList.size()]; | 1080 int[] intArray = new int[intList.size()]; |
1079 for (int i = 0; i < intList.size(); ++i) intArray[i] = i; | 1081 for (int i = 0; i < intList.size(); ++i) intArray[i] = i; |
1080 return intArray; | 1082 return intArray; |
1081 } | 1083 } |
1082 } | 1084 } |
OLD | NEW |