| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.support.v7.app; |
| |
| import android.app.Notification; |
| import android.app.PendingIntent; |
| import android.content.Context; |
| import android.os.Build; |
| import android.support.v4.app.NotificationBuilderWithBuilderAccessor; |
| import android.support.v4.media.session.MediaSessionCompat; |
| |
| /** |
| * An extension of {@link android.support.v4.app.NotificationCompat} which supports |
| * {@link android.support.v7.app.NotificationCompat.MediaStyle}. You should start using this variant |
| * if you need support for media styled notifications. |
| */ |
| public class NotificationCompat extends android.support.v4.app.NotificationCompat { |
| |
| private static void addMediaStyleToBuilderLollipop( |
| NotificationBuilderWithBuilderAccessor builder, android.support.v4.app.NotificationCompat.Style style) { |
| if (style instanceof MediaStyle) { |
| MediaStyle mediaStyle = (MediaStyle) style; |
| NotificationCompatImpl21.addMediaStyle(builder, |
| mediaStyle.mActionsToShowInCompact, |
| mediaStyle.mToken != null ? mediaStyle.mToken.getToken() : null); |
| } |
| } |
| |
| private static void addMediaStyleToBuilderIcs(NotificationBuilderWithBuilderAccessor builder, |
| android.support.v4.app.NotificationCompat.Builder b) { |
| if (b.mStyle instanceof MediaStyle) { |
| MediaStyle mediaStyle = (MediaStyle) b.mStyle; |
| NotificationCompatImplBase.overrideContentView(builder, b.mContext, |
| b.mContentTitle, |
| b.mContentText, b.mContentInfo, b.mNumber, b.mLargeIcon, b.mSubText, |
| b.mUseChronometer, b.mNotification.when, b.mActions, |
| mediaStyle.mActionsToShowInCompact, mediaStyle.mShowCancelButton, |
| mediaStyle.mCancelButtonIntent); |
| } |
| } |
| |
| private static void addBigMediaStyleToBuilderJellybean(Notification n, |
| android.support.v4.app.NotificationCompat.Builder b) { |
| if (b.mStyle instanceof MediaStyle) { |
| MediaStyle mediaStyle = (MediaStyle) b.mStyle; |
| NotificationCompatImplBase.overrideBigContentView(n, b.mContext, |
| b.mContentTitle, |
| b.mContentText, b.mContentInfo, b.mNumber, b.mLargeIcon, b.mSubText, |
| b.mUseChronometer, b.mNotification.when, b.mActions, |
| mediaStyle.mShowCancelButton, mediaStyle.mCancelButtonIntent); |
| } |
| } |
| |
| /** |
| * See {@link android.support.v4.app.NotificationCompat}. In addition to the builder in v4, this |
| * builder also supports {@link MediaStyle}. |
| */ |
| public static class Builder extends android.support.v4.app.NotificationCompat.Builder { |
| |
| /** |
| * @inheritDoc |
| */ |
| public Builder(Context context) { |
| super(context); |
| } |
| |
| @Override |
| protected BuilderExtender getExtender() { |
| if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
| return new LollipopExtender(); |
| } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { |
| return new JellybeanExtender(); |
| } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { |
| return new IceCreamSandwichExtender(); |
| } else { |
| return super.getExtender(); |
| } |
| } |
| } |
| |
| private static class IceCreamSandwichExtender extends BuilderExtender { |
| |
| @Override |
| public Notification build(android.support.v4.app.NotificationCompat.Builder b, |
| NotificationBuilderWithBuilderAccessor builder) { |
| addMediaStyleToBuilderIcs(builder, b); |
| return builder.build(); |
| } |
| } |
| |
| private static class JellybeanExtender extends BuilderExtender { |
| |
| @Override |
| public Notification build(android.support.v4.app.NotificationCompat.Builder b, |
| NotificationBuilderWithBuilderAccessor builder) { |
| addMediaStyleToBuilderIcs(builder, b); |
| Notification n = builder.build(); |
| addBigMediaStyleToBuilderJellybean(n, b); |
| return n; |
| } |
| } |
| |
| private static class LollipopExtender extends BuilderExtender { |
| |
| @Override |
| public Notification build(android.support.v4.app.NotificationCompat.Builder b, |
| NotificationBuilderWithBuilderAccessor builder) { |
| addMediaStyleToBuilderLollipop(builder, b.mStyle); |
| return builder.build(); |
| } |
| } |
| |
| /** |
| * Notification style for media playback notifications. |
| * |
| * In the expanded form, {@link Notification#bigContentView}, up to 5 |
| * {@link android.support.v4.app.NotificationCompat.Action}s specified with |
| * {@link NotificationCompat.Builder#addAction(int, CharSequence, PendingIntent) addAction} will |
| * be shown as icon-only pushbuttons, suitable for transport controls. The Bitmap given to |
| * {@link NotificationCompat.Builder#setLargeIcon(android.graphics.Bitmap) setLargeIcon()} will |
| * be treated as album artwork. |
| * |
| * Unlike the other styles provided here, MediaStyle can also modify the standard-size |
| * {@link Notification#contentView}; by providing action indices to |
| * {@link #setShowActionsInCompactView(int...)} you can promote up to 3 actions to be displayed |
| * in the standard view alongside the usual content. |
| * |
| * Notifications created with MediaStyle will have their category set to |
| * {@link Notification#CATEGORY_TRANSPORT CATEGORY_TRANSPORT} unless you set a different |
| * category using {@link NotificationCompat.Builder#setCategory(String) setCategory()}. |
| * |
| * Finally, if you attach a {@link android.media.session.MediaSession.Token} using |
| * {@link android.support.v7.app.NotificationCompat.MediaStyle#setMediaSession}, the System UI |
| * can identify this as a notification representing an active media session and respond |
| * accordingly (by showing album artwork in the lockscreen, for example). |
| * |
| * To use this style with your Notification, feed it to |
| * {@link NotificationCompat.Builder#setStyle} like so: |
| * <pre class="prettyprint"> |
| * Notification noti = new NotificationCompat.Builder() |
| * .setSmallIcon(R.drawable.ic_stat_player) |
| * .setContentTitle("Track title") |
| * .setContentText("Artist - Album") |
| * .setLargeIcon(albumArtBitmap)) |
| * .setStyle(<b>new NotificationCompat.MediaStyle()</b> |
| * .setMediaSession(mySession)) |
| * .build(); |
| * </pre> |
| * |
| * @see Notification#bigContentView |
| */ |
| public static class MediaStyle extends android.support.v4.app.NotificationCompat.Style { |
| |
| int[] mActionsToShowInCompact = null; |
| MediaSessionCompat.Token mToken; |
| boolean mShowCancelButton; |
| PendingIntent mCancelButtonIntent; |
| |
| public MediaStyle() { |
| } |
| |
| public MediaStyle(android.support.v4.app.NotificationCompat.Builder builder) { |
| setBuilder(builder); |
| } |
| |
| /** |
| * Request up to 3 actions (by index in the order of addition) to be shown in the compact |
| * notification view. |
| * |
| * @param actions the indices of the actions to show in the compact notification view |
| */ |
| public MediaStyle setShowActionsInCompactView(int...actions) { |
| mActionsToShowInCompact = actions; |
| return this; |
| } |
| |
| /** |
| * Attach a {@link MediaSessionCompat.Token} to this Notification |
| * to provide additional playback information and control to the SystemUI. |
| */ |
| public MediaStyle setMediaSession(MediaSessionCompat.Token token) { |
| mToken = token; |
| return this; |
| } |
| |
| /** |
| * Sets whether a cancel button at the top right should be shown in the notification on |
| * platforms before Lollipop. |
| * |
| * <p>Prior to Lollipop, there was a bug in the framework which prevented the developer to |
| * make a notification dismissable again after having used the same notification as the |
| * ongoing notification for a foreground service. When the notification was posted by |
| * {@link android.app.Service#startForeground}, but then the service exited foreground mode |
| * via {@link android.app.Service#stopForeground}, without removing the notification, the |
| * notification stayed ongoing, and thus not dismissable. |
| * |
| * <p>This is a common scenario for media notifications, as this is exactly the service |
| * lifecycle that happens when playing/pausing media. Thus, a workaround is provided by the |
| * support library: Instead of making the notification ongoing depending on the playback |
| * state, the support library provides the ability to add an explicit cancel button to the |
| * notification. |
| * |
| * <p>Note that the notification is enforced to be ongoing if a cancel button is shown to |
| * provide a consistent user experience. |
| * |
| * <p>Also note that this method is a no-op when running on Lollipop and later. |
| * |
| * @param show whether to show a cancel button |
| */ |
| public MediaStyle setShowCancelButton(boolean show) { |
| mShowCancelButton = show; |
| return this; |
| } |
| |
| /** |
| * Sets the pending intent to be sent when the cancel button is pressed. See {@link |
| * #setShowCancelButton}. |
| * |
| * @param pendingIntent the intent to be sent when the cancel button is pressed |
| */ |
| public MediaStyle setCancelButtonIntent(PendingIntent pendingIntent) { |
| mCancelButtonIntent = pendingIntent; |
| return this; |
| } |
| } |
| } |