[go: nahoru, domu]

1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.support.v7.app;
18
19import android.app.Notification;
20import android.app.PendingIntent;
21import android.content.Context;
22import android.os.Build;
23import android.support.v4.app.NotificationBuilderWithBuilderAccessor;
24import android.support.v4.media.session.MediaSessionCompat;
25
26/**
27 * An extension of {@link android.support.v4.app.NotificationCompat} which supports
28 * {@link android.support.v7.app.NotificationCompat.MediaStyle}. You should start using this variant
29 * if you need support for media styled notifications.
30 */
31public class NotificationCompat extends android.support.v4.app.NotificationCompat {
32
33    private static void addMediaStyleToBuilderLollipop(
34            NotificationBuilderWithBuilderAccessor builder, android.support.v4.app.NotificationCompat.Style style) {
35        if (style instanceof MediaStyle) {
36            MediaStyle mediaStyle = (MediaStyle) style;
37            NotificationCompatImpl21.addMediaStyle(builder,
38                    mediaStyle.mActionsToShowInCompact,
39                    mediaStyle.mToken != null ? mediaStyle.mToken.getToken() : null);
40        }
41    }
42
43    private static void addMediaStyleToBuilderIcs(NotificationBuilderWithBuilderAccessor builder,
44            android.support.v4.app.NotificationCompat.Builder b) {
45        if (b.mStyle instanceof MediaStyle) {
46            MediaStyle mediaStyle = (MediaStyle) b.mStyle;
47            NotificationCompatImplBase.overrideContentView(builder, b.mContext,
48                    b.mContentTitle,
49                    b.mContentText, b.mContentInfo, b.mNumber, b.mLargeIcon, b.mSubText,
50                    b.mUseChronometer, b.mNotification.when, b.mActions,
51                    mediaStyle.mActionsToShowInCompact, mediaStyle.mShowCancelButton,
52                    mediaStyle.mCancelButtonIntent);
53        }
54    }
55
56    private static void addBigMediaStyleToBuilderJellybean(Notification n,
57            android.support.v4.app.NotificationCompat.Builder b) {
58        if (b.mStyle instanceof MediaStyle) {
59            MediaStyle mediaStyle = (MediaStyle) b.mStyle;
60            NotificationCompatImplBase.overrideBigContentView(n, b.mContext,
61                    b.mContentTitle,
62                    b.mContentText, b.mContentInfo, b.mNumber, b.mLargeIcon, b.mSubText,
63                    b.mUseChronometer, b.mNotification.when, b.mActions,
64                    mediaStyle.mShowCancelButton, mediaStyle.mCancelButtonIntent);
65        }
66    }
67
68    /**
69     * See {@link android.support.v4.app.NotificationCompat}. In addition to the builder in v4, this
70     * builder also supports {@link MediaStyle}.
71     */
72    public static class Builder extends android.support.v4.app.NotificationCompat.Builder {
73
74        /**
75         * @inheritDoc
76         */
77        public Builder(Context context) {
78            super(context);
79        }
80
81        /**
82         * @hide
83         */
84        @Override
85        protected BuilderExtender getExtender() {
86            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
87                return new LollipopExtender();
88            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
89                return new JellybeanExtender();
90            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
91                return new IceCreamSandwichExtender();
92            } else {
93                return super.getExtender();
94            }
95        }
96    }
97
98    private static class IceCreamSandwichExtender extends BuilderExtender {
99
100        @Override
101        public Notification build(android.support.v4.app.NotificationCompat.Builder b,
102                NotificationBuilderWithBuilderAccessor builder) {
103            addMediaStyleToBuilderIcs(builder, b);
104            return builder.build();
105        }
106    }
107
108    private static class JellybeanExtender extends BuilderExtender {
109
110        @Override
111        public Notification build(android.support.v4.app.NotificationCompat.Builder b,
112                NotificationBuilderWithBuilderAccessor builder) {
113            addMediaStyleToBuilderIcs(builder, b);
114            Notification n = builder.build();
115            addBigMediaStyleToBuilderJellybean(n, b);
116            return n;
117        }
118    }
119
120    private static class LollipopExtender extends BuilderExtender {
121
122        @Override
123        public Notification build(android.support.v4.app.NotificationCompat.Builder b,
124                NotificationBuilderWithBuilderAccessor builder) {
125            addMediaStyleToBuilderLollipop(builder, b.mStyle);
126            return builder.build();
127        }
128    }
129
130    /**
131     * Notification style for media playback notifications.
132     *
133     * In the expanded form, {@link Notification#bigContentView}, up to 5
134     * {@link android.support.v4.app.NotificationCompat.Action}s specified with
135     * {@link NotificationCompat.Builder#addAction(int, CharSequence, PendingIntent) addAction} will
136     * be shown as icon-only pushbuttons, suitable for transport controls. The Bitmap given to
137     * {@link NotificationCompat.Builder#setLargeIcon(android.graphics.Bitmap) setLargeIcon()} will
138     * be treated as album artwork.
139     *
140     * Unlike the other styles provided here, MediaStyle can also modify the standard-size
141     * {@link Notification#contentView}; by providing action indices to
142     * {@link #setShowActionsInCompactView(int...)} you can promote up to 3 actions to be displayed
143     * in the standard view alongside the usual content.
144     *
145     * Notifications created with MediaStyle will have their category set to
146     * {@link Notification#CATEGORY_TRANSPORT CATEGORY_TRANSPORT} unless you set a different
147     * category using {@link NotificationCompat.Builder#setCategory(String) setCategory()}.
148     *
149     * Finally, if you attach a {@link android.media.session.MediaSession.Token} using
150     * {@link android.support.v7.app.NotificationCompat.MediaStyle#setMediaSession}, the System UI
151     * can identify this as a notification representing an active media session and respond
152     * accordingly (by showing album artwork in the lockscreen, for example).
153     *
154     * To use this style with your Notification, feed it to
155     * {@link NotificationCompat.Builder#setStyle} like so:
156     * <pre class="prettyprint">
157     * Notification noti = new NotificationCompat.Builder()
158     *     .setSmallIcon(R.drawable.ic_stat_player)
159     *     .setContentTitle(&quot;Track title&quot;)
160     *     .setContentText(&quot;Artist - Album&quot;)
161     *     .setLargeIcon(albumArtBitmap))
162     *     .setStyle(<b>new NotificationCompat.MediaStyle()</b>
163     *         .setMediaSession(mySession))
164     *     .build();
165     * </pre>
166     *
167     * @see Notification#bigContentView
168     */
169    public static class MediaStyle extends android.support.v4.app.NotificationCompat.Style {
170
171        int[] mActionsToShowInCompact = null;
172        MediaSessionCompat.Token mToken;
173        boolean mShowCancelButton;
174        PendingIntent mCancelButtonIntent;
175
176        public MediaStyle() {
177        }
178
179        public MediaStyle(android.support.v4.app.NotificationCompat.Builder builder) {
180            setBuilder(builder);
181        }
182
183        /**
184         * Request up to 3 actions (by index in the order of addition) to be shown in the compact
185         * notification view.
186         *
187         * @param actions the indices of the actions to show in the compact notification view
188         */
189        public MediaStyle setShowActionsInCompactView(int...actions) {
190            mActionsToShowInCompact = actions;
191            return this;
192        }
193
194        /**
195         * Attach a {@link MediaSessionCompat.Token} to this Notification
196         * to provide additional playback information and control to the SystemUI.
197         */
198        public MediaStyle setMediaSession(MediaSessionCompat.Token token) {
199            mToken = token;
200            return this;
201        }
202
203        /**
204         * Sets whether a cancel button at the top right should be shown in the notification on
205         * platforms before Lollipop.
206         *
207         * <p>Prior to Lollipop, there was a bug in the framework which prevented the developer to
208         * make a notification dismissable again after having used the same notification as the
209         * ongoing notification for a foreground service. When the notification was posted by
210         * {@link android.app.Service#startForeground}, but then the service exited foreground mode
211         * via {@link android.app.Service#stopForeground}, without removing the notification, the
212         * notification stayed ongoing, and thus not dismissable.
213         *
214         * <p>This is a common scenario for media notifications, as this is exactly the service
215         * lifecycle that happens when playing/pausing media. Thus, a workaround is provided by the
216         * support library: Instead of making the notification ongoing depending on the playback
217         * state, the support library provides the ability to add an explicit cancel button to the
218         * notification.
219         *
220         * <p>Note that the notification is enforced to be ongoing if a cancel button is shown to
221         * provide a consistent user experience.
222         *
223         * <p>Also note that this method is a no-op when running on Lollipop and later.
224         *
225         * @param show whether to show a cancel button
226         */
227        public MediaStyle setShowCancelButton(boolean show) {
228            mShowCancelButton = show;
229            return this;
230        }
231
232        /**
233         * Sets the pending intent to be sent when the cancel button is pressed. See {@link
234         * #setShowCancelButton}.
235         *
236         * @param pendingIntent the intent to be sent when the cancel button is pressed
237         */
238        public MediaStyle setCancelButtonIntent(PendingIntent pendingIntent) {
239            mCancelButtonIntent = pendingIntent;
240            return this;
241        }
242    }
243}
244