Updates BannerMessagePreference to new style

Updates the style of the BannerMessagePreference in v31 and adds support
for the following new functionality (all optional):
- Use one of three attention level themes: high, medium, and low
(default: high)
- Add an icon (default: alert icon)
- Subtitle (default: hidden)
- Dismiss button (default: hidden)

Icon, subtitle, and theme can also be set via xml attrs.

Adds support for creating a BannerMessage without a title.

Test: make -j80 RunSettingsLibRoboTests
Test: Manually tested all configurations
Bug: 181764215

Change-Id: I73bfc5225d83057e423b6a9d77a6277a656d3b90
diff --git a/packages/SettingsLib/BannerMessagePreference/Android.bp b/packages/SettingsLib/BannerMessagePreference/Android.bp
index 82e837b..c6a9562 100644
--- a/packages/SettingsLib/BannerMessagePreference/Android.bp
+++ b/packages/SettingsLib/BannerMessagePreference/Android.bp
@@ -14,9 +14,10 @@
     resource_dirs: ["res"],
 
     static_libs: [
-          "androidx.preference_preference",
+        "androidx.preference_preference",
+        "SettingsLibSettingsTheme",
     ],
 
     sdk_version: "system_current",
-    min_sdk_version: "21",
+    min_sdk_version: "28",
 }
diff --git a/packages/SettingsLib/BannerMessagePreference/AndroidManifest.xml b/packages/SettingsLib/BannerMessagePreference/AndroidManifest.xml
index 56b886f..dd51ea3 100644
--- a/packages/SettingsLib/BannerMessagePreference/AndroidManifest.xml
+++ b/packages/SettingsLib/BannerMessagePreference/AndroidManifest.xml
@@ -18,6 +18,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.settingslib.widget">
 
-    <uses-sdk android:minSdkVersion="21"/>
+    <uses-sdk android:minSdkVersion="28"/>
 
 </manifest>
diff --git a/packages/SettingsLib/BannerMessagePreference/lint-baseline.xml b/packages/SettingsLib/BannerMessagePreference/lint-baseline.xml
deleted file mode 100644
index ba02a1f..0000000
--- a/packages/SettingsLib/BannerMessagePreference/lint-baseline.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
-    <issue
-        id="NewApi"
-        message="`@android:style/Widget.DeviceDefault.Button.Borderless.Colored` requires API level 28 (current min is 21)"
-        errorLine1="            style=&quot;@android:style/Widget.DeviceDefault.Button.Borderless.Colored&quot;/>"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="frameworks/base/packages/SettingsLib/BannerMessagePreference/res/layout/banner_message.xml"
-            line="65"
-            column="13"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="`@android:style/Widget.DeviceDefault.Button.Borderless.Colored` requires API level 28 (current min is 21)"
-        errorLine1="            style=&quot;@android:style/Widget.DeviceDefault.Button.Borderless.Colored&quot;/>"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="frameworks/base/packages/SettingsLib/BannerMessagePreference/res/layout/banner_message.xml"
-            line="71"
-            column="13"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="`?android:attr/colorError` requires API level 26 (current min is 21)"
-        errorLine1="        android:fillColor=&quot;?android:attr/colorError&quot;"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="frameworks/base/packages/SettingsLib/BannerMessagePreference/res/drawable/ic_warning.xml"
-            line="24"
-            column="9"/>
-    </issue>
-
-</issues>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/drawable-v31/settingslib_card_background.xml b/packages/SettingsLib/BannerMessagePreference/res/drawable-v31/settingslib_card_background.xml
new file mode 100644
index 0000000..072eb58
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/drawable-v31/settingslib_card_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="?android:attr/background" />
+    <corners android:radius="28dp"/>
+</shape>
\ No newline at end of file
diff --git a/packages/SettingsLib/BannerMessagePreference/res/drawable-v31/settingslib_ic_cross.xml b/packages/SettingsLib/BannerMessagePreference/res/drawable-v31/settingslib_ic_cross.xml
new file mode 100644
index 0000000..d926cc6
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/drawable-v31/settingslib_ic_cross.xml
@@ -0,0 +1,25 @@
+<!--
+  Copyright (C) 2021 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="?android:attr/textColorSecondary"
+        android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12 19,6.41z"/>
+</vector>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/layout-v31/settingslib_banner_message.xml b/packages/SettingsLib/BannerMessagePreference/res/layout-v31/settingslib_banner_message.xml
new file mode 100644
index 0000000..904b78c
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/layout-v31/settingslib_banner_message.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    style="@style/Banner.Preference.SettingsLib">
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="8dp"
+        android:orientation="horizontal">
+
+        <ImageView
+            android:id="@+id/banner_icon"
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:layout_alignParentStart="true"
+            android:importantForAccessibility="no" />
+
+        <ImageButton
+            android:id="@+id/banner_dismiss_btn"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/settingslib_ic_cross"
+            android:layout_alignParentEnd="true"
+            android:contentDescription="@string/accessibility_banner_message_dismiss"
+            style="@style/Banner.Dismiss.SettingsLib" />
+    </RelativeLayout>
+
+    <TextView
+        android:id="@+id/banner_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingBottom="4dp"
+        android:textAppearance="@style/Banner.Title.SettingsLib"/>
+
+    <TextView
+        android:id="@+id/banner_subtitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingBottom="4dp"
+        android:textAppearance="@style/Banner.Subtitle.SettingsLib"
+        android:visibility="gone"/>
+
+    <TextView
+        android:id="@+id/banner_summary"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingTop="4dp"
+        android:paddingBottom="8dp"
+        android:textAppearance="@style/Banner.Summary.SettingsLib"/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:minHeight="8dp"
+        android:gravity="end">
+
+        <Button
+            android:id="@+id/banner_negative_btn"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            style="@style/Banner.ButtonText.SettingsLib"/>
+
+        <Button
+            android:id="@+id/banner_positive_btn"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            style="@style/Banner.ButtonText.SettingsLib"/>
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/BannerMessagePreference/res/layout/banner_message.xml b/packages/SettingsLib/BannerMessagePreference/res/layout/settingslib_banner_message.xml
similarity index 81%
rename from packages/SettingsLib/BannerMessagePreference/res/layout/banner_message.xml
rename to packages/SettingsLib/BannerMessagePreference/res/layout/settingslib_banner_message.xml
index 977e196..80cb1d5 100644
--- a/packages/SettingsLib/BannerMessagePreference/res/layout/banner_message.xml
+++ b/packages/SettingsLib/BannerMessagePreference/res/layout/settingslib_banner_message.xml
@@ -30,8 +30,10 @@
         android:orientation="horizontal">
 
         <ImageView
+            android:id="@+id/banner_icon"
             android:layout_width="24dp"
             android:layout_height="24dp"
+            android:importantForAccessibility="no"
             android:src="@drawable/ic_warning"/>
 
         <LinearLayout
@@ -70,4 +72,19 @@
             android:layout_height="wrap_content"
             style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"/>
     </LinearLayout>
+
+    <!-- Not supported before v31 -->
+    <TextView
+        android:id="@+id/banner_subtitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:visibility="gone"/>
+
+    <!-- Not supported before v31 -->
+    <ImageButton
+        android:id="@+id/banner_dismiss_btn"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:contentDescription="@string/accessibility_banner_message_dismiss"
+        android:visibility="gone"/>
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-night/colors.xml b/packages/SettingsLib/BannerMessagePreference/res/values-night/colors.xml
new file mode 100644
index 0000000..50141a8
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-night/colors.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+
+<resources>
+    <color name="banner_background_attention_high">#3B2D2C</color> <!-- red card background -->
+    <color name="banner_background_attention_medium">#333121</color> <!-- yellow card background -->
+    <color name="banner_background_attention_low">#2B3328</color> <!-- green card background -->
+    <color name="banner_accent_attention_high">#F28B82</color> <!-- red accent color -->
+    <color name="banner_accent_attention_medium">#FDD663</color> <!-- yellow accent color -->
+    <color name="banner_accent_attention_low">#81C995</color> <!-- green accent color -->
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml b/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml
new file mode 100644
index 0000000..a39e779
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2020 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.
+  -->
+
+<resources>
+
+    <style name="Banner.Preference.SettingsLib"
+        parent="android:Widget.DeviceDefault">
+        <item name="android:paddingStart">20dp</item>
+        <item name="android:paddingEnd">20dp</item>
+        <item name="android:paddingTop">20dp</item>
+        <item name="android:paddingBottom">8dp</item>
+        <item name="android:layout_marginTop">8dp</item>
+        <item name="android:layout_marginStart">16dp</item>
+        <item name="android:layout_marginBottom">8dp</item>
+        <item name="android:layout_marginEnd">16dp</item>
+        <item name="android:background">@drawable/settingslib_card_background</item>
+    </style>
+
+    <style name="Banner.Title.SettingsLib"
+        parent="@android:style/TextAppearance.Material.Subhead">
+        <item name="android:textSize">20sp</item>
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    </style>
+
+    <style name="Banner.Subtitle.SettingsLib"
+        parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+        <item name="android:textSize">14sp</item>
+    </style>
+
+    <style name="Banner.Summary.SettingsLib"
+        parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+        <item name="android:textSize">14sp</item>
+    </style>
+
+    <style name="Banner.Dismiss.SettingsLib"
+        parent="android:Widget.DeviceDefault.ImageButton">
+        <item name="android:background">@android:color/transparent</item>
+    </style>
+
+    <style name="Banner.ButtonText.SettingsLib"
+        parent="android:Widget.DeviceDefault.Button.Borderless.Colored">
+        <item name="android:textColor">?android:attr/colorAccent</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values/attrs.xml b/packages/SettingsLib/BannerMessagePreference/res/values/attrs.xml
new file mode 100644
index 0000000..96634a5
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values/attrs.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+
+<resources>
+    <declare-styleable name="BannerMessagePreference">
+        <attr format="enum" name="attentionLevel">
+            <enum name="high" value="0"/>
+            <enum name="medium" value="1"/>
+            <enum name="low" value="2"/>
+        </attr>
+        <attr format="string" name="subtitle" />
+    </declare-styleable>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values/colors.xml b/packages/SettingsLib/BannerMessagePreference/res/values/colors.xml
new file mode 100644
index 0000000..53d72d1
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values/colors.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+
+<resources>
+    <color name="banner_background_attention_high">#FFDAD5</color> <!-- red card background -->
+    <color name="banner_background_attention_medium">#F0E3A8</color> <!-- yellow card background -->
+    <color name="banner_background_attention_low">#CFEBC0</color> <!-- green card background -->
+    <color name="banner_accent_attention_high">#BB3322</color> <!-- red accent color -->
+    <color name="banner_accent_attention_medium">#895900</color> <!-- yellow accent color -->
+    <color name="banner_accent_attention_low">#1D7233</color> <!-- green accent color -->
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values/strings.xml
new file mode 100644
index 0000000..a1af38a
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2021 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.
+  -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Content description of the dismiss button on a banner message for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_banner_message_dismiss">Dismiss</string>
+</resources>
+
+
diff --git a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
index 5352552..5bedd7a 100644
--- a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
+++ b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
@@ -17,13 +17,25 @@
 package com.android.settingslib.widget;
 
 import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.annotation.ColorInt;
+import androidx.annotation.ColorRes;
+import androidx.annotation.RequiresApi;
 import androidx.annotation.StringRes;
+import androidx.core.os.BuildCompat;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceViewHolder;
 
@@ -33,55 +45,151 @@
  */
 public class BannerMessagePreference extends Preference {
 
+    public enum AttentionLevel {
+        HIGH(0, R.color.banner_background_attention_high, R.color.banner_accent_attention_high),
+        MEDIUM(1,
+               R.color.banner_background_attention_medium,
+               R.color.banner_accent_attention_medium),
+        LOW(2, R.color.banner_background_attention_low, R.color.banner_accent_attention_low);
+
+        // Corresponds to the enum valye of R.attr.attentionLevel
+        private final int mAttrValue;
+        @ColorRes private final int mBackgroundColorResId;
+        @ColorRes private final int mAccentColorResId;
+
+        AttentionLevel(int attrValue, @ColorRes int backgroundColorResId,
+                @ColorRes int accentColorResId) {
+            mAttrValue = attrValue;
+            mBackgroundColorResId = backgroundColorResId;
+            mAccentColorResId = accentColorResId;
+        }
+
+        static AttentionLevel fromAttr(int attrValue) {
+            for (AttentionLevel level : values()) {
+                if (level.mAttrValue == attrValue) {
+                    return level;
+                }
+            }
+            throw new IllegalArgumentException();
+        }
+
+        @ColorRes int getAccentColorResId() {
+            return mAccentColorResId;
+        }
+
+        @ColorRes int getBackgroundColorResId() {
+            return mBackgroundColorResId;
+        }
+    }
+
     private static final String TAG = "BannerPreference";
-    private BannerMessagePreference.ButtonInfo mPositiveButtonInfo;
-    private BannerMessagePreference.ButtonInfo mNegativeButtonInfo;
+    private static final boolean IS_AT_LEAST_S = BuildCompat.isAtLeastS();
+
+    private final BannerMessagePreference.ButtonInfo mPositiveButtonInfo =
+            new BannerMessagePreference.ButtonInfo();
+    private final BannerMessagePreference.ButtonInfo mNegativeButtonInfo =
+            new BannerMessagePreference.ButtonInfo();
+    private final BannerMessagePreference.DismissButtonInfo mDismissButtonInfo =
+            new BannerMessagePreference.DismissButtonInfo();
+
+    // Default attention level is High.
+    private AttentionLevel mAttentionLevel = AttentionLevel.HIGH;
+    private String mSubtitle;
 
     public BannerMessagePreference(Context context) {
         super(context);
-        init();
+        init(context, null /* attrs */);
     }
 
     public BannerMessagePreference(Context context, AttributeSet attrs) {
         super(context, attrs);
-        init();
+        init(context, attrs);
     }
 
     public BannerMessagePreference(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        init();
+        init(context, attrs);
     }
 
     public BannerMessagePreference(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        init();
+        init(context, attrs);
+    }
+
+    private void init(Context context, AttributeSet attrs) {
+        setSelectable(false);
+        setLayoutResource(R.layout.settingslib_banner_message);
+
+        if (IS_AT_LEAST_S) {
+            if (attrs != null) {
+                // Get attention level and subtitle from layout XML
+                TypedArray a =
+                        context.obtainStyledAttributes(attrs, R.styleable.BannerMessagePreference);
+                int mAttentionLevelValue =
+                        a.getInt(R.styleable.BannerMessagePreference_attentionLevel, 0);
+                mAttentionLevel = AttentionLevel.fromAttr(mAttentionLevelValue);
+                mSubtitle = a.getString(R.styleable.BannerMessagePreference_subtitle);
+                a.recycle();
+            }
+        }
     }
 
     @Override
     public void onBindViewHolder(PreferenceViewHolder holder) {
         super.onBindViewHolder(holder);
-        holder.setDividerAllowedAbove(true);
-        holder.setDividerAllowedBelow(true);
+        final Context context = getContext();
+
+        final TextView titleView = (TextView) holder.findViewById(R.id.banner_title);
+        CharSequence title = getTitle();
+        titleView.setText(title);
+        titleView.setVisibility(title == null ? View.GONE : View.VISIBLE);
+
+        final TextView summaryView = (TextView) holder.findViewById(R.id.banner_summary);
+        summaryView.setText(getSummary());
 
         mPositiveButtonInfo.mButton = (Button) holder.findViewById(R.id.banner_positive_btn);
         mNegativeButtonInfo.mButton = (Button) holder.findViewById(R.id.banner_negative_btn);
 
+        if (IS_AT_LEAST_S) {
+            final Resources.Theme theme = context.getTheme();
+            @ColorInt final int accentColor =
+                    context.getResources().getColor(mAttentionLevel.getAccentColorResId(), theme);
+            @ColorInt final int backgroundColor =
+                    context.getResources().getColor(
+                            mAttentionLevel.getBackgroundColorResId(), theme);
+
+            holder.setDividerAllowedAbove(false);
+            holder.setDividerAllowedBelow(false);
+            holder.itemView.getBackground().setTint(backgroundColor);
+
+            mPositiveButtonInfo.mColor = accentColor;
+            mNegativeButtonInfo.mColor = accentColor;
+
+            mDismissButtonInfo.mButton = (ImageButton) holder.findViewById(R.id.banner_dismiss_btn);
+            mDismissButtonInfo.setUpButton();
+
+            final TextView subtitleView = (TextView) holder.findViewById(R.id.banner_subtitle);
+            subtitleView.setText(mSubtitle);
+            subtitleView.setVisibility(mSubtitle == null ? View.GONE : View.VISIBLE);
+
+            final ImageView iconView = (ImageView) holder.findViewById(R.id.banner_icon);
+            if (iconView != null) {
+                Drawable icon = getIcon();
+                iconView.setImageDrawable(
+                        icon == null
+                                ? getContext().getDrawable(R.drawable.ic_warning)
+                                : icon);
+                iconView.setColorFilter(
+                        new PorterDuffColorFilter(accentColor, PorterDuff.Mode.SRC_IN));
+            }
+        } else {
+            holder.setDividerAllowedAbove(true);
+            holder.setDividerAllowedBelow(true);
+        }
+
         mPositiveButtonInfo.setUpButton();
         mNegativeButtonInfo.setUpButton();
-
-        final TextView titleView = (TextView) holder.findViewById(R.id.banner_title);
-        final TextView summaryView = (TextView) holder.findViewById(R.id.banner_summary);
-
-        titleView.setText(getTitle());
-        summaryView.setText(getSummary());
-    }
-
-    private void init() {
-        mPositiveButtonInfo = new BannerMessagePreference.ButtonInfo();
-        mNegativeButtonInfo = new BannerMessagePreference.ButtonInfo();
-        setSelectable(false);
-        setLayoutResource(R.layout.banner_message);
     }
 
     /**
@@ -107,6 +215,18 @@
     }
 
     /**
+     * Set the visibility state of dismiss button.
+     */
+    @RequiresApi(Build.VERSION_CODES.S)
+    public BannerMessagePreference setDismissButtonVisible(boolean isVisible) {
+        if (isVisible != mDismissButtonInfo.mIsVisible) {
+            mDismissButtonInfo.mIsVisible = isVisible;
+            notifyChanged();
+        }
+        return this;
+    }
+
+    /**
      * Register a callback to be invoked when positive button is clicked.
      */
     public BannerMessagePreference setPositiveButtonOnClickListener(
@@ -131,12 +251,31 @@
     }
 
     /**
+     * Register a callback to be invoked when the dismiss button is clicked.
+     */
+    @RequiresApi(Build.VERSION_CODES.S)
+    public BannerMessagePreference setDismissButtonOnClickListener(
+            View.OnClickListener listener) {
+        if (listener != mDismissButtonInfo.mListener) {
+            mDismissButtonInfo.mListener = listener;
+            notifyChanged();
+        }
+        return this;
+    }
+
+    /**
      * Sets the text to be displayed in positive button.
      */
     public BannerMessagePreference setPositiveButtonText(@StringRes int textResId) {
-        final String newText = getContext().getString(textResId);
-        if (!TextUtils.equals(newText, mPositiveButtonInfo.mText)) {
-            mPositiveButtonInfo.mText = newText;
+        return setPositiveButtonText(getContext().getString(textResId));
+    }
+
+    /**
+     * Sets the text to be displayed in positive button.
+     */
+    public BannerMessagePreference setPositiveButtonText(String positiveButtonText) {
+        if (!TextUtils.equals(positiveButtonText, mPositiveButtonInfo.mText)) {
+            mPositiveButtonInfo.mText = positiveButtonText;
             notifyChanged();
         }
         return this;
@@ -146,9 +285,51 @@
      * Sets the text to be displayed in negative button.
      */
     public BannerMessagePreference setNegativeButtonText(@StringRes int textResId) {
-        final String newText = getContext().getString(textResId);
-        if (!TextUtils.equals(newText, mNegativeButtonInfo.mText)) {
-            mNegativeButtonInfo.mText = newText;
+        return setNegativeButtonText(getContext().getString(textResId));
+    }
+
+    /**
+     * Sets the text to be displayed in negative button.
+     */
+    public BannerMessagePreference setNegativeButtonText(String negativeButtonText) {
+        if (!TextUtils.equals(negativeButtonText, mNegativeButtonInfo.mText)) {
+            mNegativeButtonInfo.mText = negativeButtonText;
+            notifyChanged();
+        }
+        return this;
+    }
+
+    /**
+     * Sets the subtitle.
+     */
+    @RequiresApi(Build.VERSION_CODES.S)
+    public BannerMessagePreference setSubtitle(@StringRes int textResId) {
+        return setSubtitle(getContext().getString(textResId));
+    }
+
+    /**
+     * Sets the subtitle.
+     */
+    @RequiresApi(Build.VERSION_CODES.S)
+    public BannerMessagePreference setSubtitle(String subtitle) {
+        if (!TextUtils.equals(subtitle, mSubtitle)) {
+            mSubtitle = subtitle;
+            notifyChanged();
+        }
+        return this;
+    }
+
+    /**
+     * Sets the attention level. This will update the color theme of the preference.
+     */
+    @RequiresApi(Build.VERSION_CODES.S)
+    public BannerMessagePreference setAttentionLevel(AttentionLevel attentionLevel) {
+        if (attentionLevel == mAttentionLevel) {
+            return this;
+        }
+
+        if (attentionLevel != null) {
+            mAttentionLevel = attentionLevel;
             notifyChanged();
         }
         return this;
@@ -159,11 +340,16 @@
         private CharSequence mText;
         private View.OnClickListener mListener;
         private boolean mIsVisible = true;
+        @ColorInt private int mColor;
 
         void setUpButton() {
             mButton.setText(mText);
             mButton.setOnClickListener(mListener);
 
+            if (IS_AT_LEAST_S) {
+                mButton.setTextColor(mColor);
+            }
+
             if (shouldBeVisible()) {
                 mButton.setVisibility(View.VISIBLE);
             } else {
@@ -179,4 +365,26 @@
             return mIsVisible && (!TextUtils.isEmpty(mText));
         }
     }
+
+    static class DismissButtonInfo {
+        private ImageButton mButton;
+        private View.OnClickListener mListener;
+        private boolean mIsVisible = true;
+
+        void setUpButton() {
+            mButton.setOnClickListener(mListener);
+            if (shouldBeVisible()) {
+                mButton.setVisibility(View.VISIBLE);
+            } else {
+                mButton.setVisibility(View.GONE);
+            }
+        }
+
+        /**
+         * By default, dismiss button is visible if it has a click listener.
+         */
+        private boolean shouldBeVisible() {
+            return mIsVisible && (mListener != null);
+        }
+    }
 }