Add support for custom media notifications

Custom media notifications can now also be decorated by the system
instead of going fully custom.

Bug: 26961842
Change-Id: I1d85a652b93f10988939b471a14b372671acfaf1
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e290d3e..4f09e14 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3569,7 +3569,7 @@
         private static Class<? extends Style> getNotificationStyleClass(String templateClass) {
             Class<? extends Style>[] classes = new Class[] {
                     BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class,
-                    DecoratedCustomViewStyle.class };
+                    DecoratedCustomViewStyle.class, DecoratedMediaCustomViewStyle.class };
             for (Class<? extends Style> innerClass : classes) {
                 if (templateClass.equals(innerClass.getName())) {
                     return innerClass;
@@ -4588,6 +4588,103 @@
         }
     }
 
+    /**
+     * Notification style for media custom views that are decorated by the system
+     *
+     * <p>Instead of providing a media notification that is completely custom, a developer can set
+     * this style and still obtain system decorations like the notification header with the expand
+     * affordance and actions.
+     *
+     * <p>Use {@link android.app.Notification.Builder#setCustomContentView(RemoteViews)},
+     * {@link android.app.Notification.Builder#setCustomBigContentView(RemoteViews)} and
+     * {@link android.app.Notification.Builder#setCustomHeadsUpContentView(RemoteViews)} to set the
+     * corresponding custom views to display.
+     *
+     * To use this style with your Notification, feed it to
+     * {@link Notification.Builder#setStyle(android.app.Notification.Style)} like so:
+     * <pre class="prettyprint">
+     * Notification noti = new Notification.Builder()
+     *     .setSmallIcon(R.drawable.ic_stat_player)
+     *     .setLargeIcon(albumArtBitmap))
+     *     .setCustomContentView(contentView);
+     *     .setStyle(<b>new Notification.DecoratedMediaCustomViewStyle()</b>
+     *          .setMediaSession(mySession))
+     *     .build();
+     * </pre>
+     *
+     * @see android.app.Notification.DecoratedCustomViewStyle
+     * @see android.app.Notification.MediaStyle
+     */
+    public static class DecoratedMediaCustomViewStyle extends MediaStyle {
+
+        public DecoratedMediaCustomViewStyle() {
+        }
+
+        public DecoratedMediaCustomViewStyle(Builder builder) {
+            setBuilder(builder);
+        }
+
+        /**
+         * @hide
+         */
+        public boolean displayCustomViewInline() {
+            return true;
+        }
+
+        /**
+         * @hide
+         */
+        @Override
+        public RemoteViews makeContentView() {
+            RemoteViews remoteViews = super.makeContentView();
+            return buildIntoRemoteView(remoteViews, R.id.notification_content_container,
+                    mBuilder.mN.contentView);
+        }
+
+        /**
+         * @hide
+         */
+        @Override
+        public RemoteViews makeBigContentView() {
+            RemoteViews customRemoteView = mBuilder.mN.bigContentView != null
+                    ? mBuilder.mN.bigContentView
+                    : mBuilder.mN.contentView;
+            return makeBigContentViewWithCustomContent(customRemoteView);
+        }
+
+        private RemoteViews makeBigContentViewWithCustomContent(RemoteViews customRemoteView) {
+            RemoteViews remoteViews = super.makeBigContentView();
+            if (remoteViews != null) {
+                return buildIntoRemoteView(remoteViews, R.id.notification_main_column,
+                        customRemoteView);
+            } else if (customRemoteView != mBuilder.mN.contentView){
+                remoteViews = super.makeContentView();
+                return buildIntoRemoteView(remoteViews, R.id.notification_content_container,
+                        customRemoteView);
+            } else {
+                return null;
+            }
+        }
+
+        /**
+         * @hide
+         */
+        @Override
+        public RemoteViews makeHeadsUpContentView() {
+            RemoteViews customRemoteView = mBuilder.mN.headsUpContentView != null
+                    ? mBuilder.mN.headsUpContentView
+                    : mBuilder.mN.contentView;
+            return makeBigContentViewWithCustomContent(customRemoteView);
+        }
+
+        private RemoteViews buildIntoRemoteView(RemoteViews remoteViews, int id,
+                RemoteViews customContent) {
+            remoteViews.removeAllViews(id);
+            remoteViews.addView(id, customContent);
+            return remoteViews;
+        }
+    }
+
     // When adding a new Style subclass here, don't forget to update
     // Builder.getNotificationStyleClass.