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/api/current.txt b/api/current.txt
index 1b67c95..04104be 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5136,6 +5136,11 @@
     ctor public Notification.DecoratedCustomViewStyle(android.app.Notification.Builder);
   }
 
+  public static class Notification.DecoratedMediaCustomViewStyle extends android.app.Notification.MediaStyle {
+    ctor public Notification.DecoratedMediaCustomViewStyle();
+    ctor public Notification.DecoratedMediaCustomViewStyle(android.app.Notification.Builder);
+  }
+
   public static abstract interface Notification.Extender {
     method public abstract android.app.Notification.Builder extend(android.app.Notification.Builder);
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index 55863d4..27e6ed3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5268,6 +5268,11 @@
     ctor public Notification.DecoratedCustomViewStyle(android.app.Notification.Builder);
   }
 
+  public static class Notification.DecoratedMediaCustomViewStyle extends android.app.Notification.MediaStyle {
+    ctor public Notification.DecoratedMediaCustomViewStyle();
+    ctor public Notification.DecoratedMediaCustomViewStyle(android.app.Notification.Builder);
+  }
+
   public static abstract interface Notification.Extender {
     method public abstract android.app.Notification.Builder extend(android.app.Notification.Builder);
   }
diff --git a/api/test-current.txt b/api/test-current.txt
index b1fca9e..9c192f3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5136,6 +5136,11 @@
     ctor public Notification.DecoratedCustomViewStyle(android.app.Notification.Builder);
   }
 
+  public static class Notification.DecoratedMediaCustomViewStyle extends android.app.Notification.MediaStyle {
+    ctor public Notification.DecoratedMediaCustomViewStyle();
+    ctor public Notification.DecoratedMediaCustomViewStyle(android.app.Notification.Builder);
+  }
+
   public static abstract interface Notification.Extender {
     method public abstract android.app.Notification.Builder extend(android.app.Notification.Builder);
   }
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.
 
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index aea9b44..cda0636 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -36,6 +36,7 @@
         android:tag="media"
         >
         <LinearLayout
+            android:id="@+id/notification_content_container"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_gravity="fill_vertical"
@@ -45,7 +46,6 @@
             android:orientation="vertical"
             >
             <include layout="@layout/notification_template_part_line1"/>
-            <include layout="@layout/notification_template_progress"/>
             <include layout="@layout/notification_template_text"/>
         </LinearLayout>
         <LinearLayout
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9113514..402ac19 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2517,6 +2517,8 @@
   <java-symbol type="layout" name="app_anr_dialog" />
   <java-symbol type="id" name="aerr_wait" />
 
+  <java-symbol type="id" name="notification_content_container" />
+
   <!-- Encryption notification while accounts are locked by credential encryption -->
   <java-symbol type="string" name="user_encrypted_title" />
   <java-symbol type="string" name="user_encrypted_message" />