Create ButtonPreference

Bug: 201577970
Test: robotest

Change-Id: I2be43bc41405a529961ded3371d7c382bb1fdf57
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index b266df5..fcf2282 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -49,6 +49,7 @@
         "SettingsLibTwoTargetPreference",
         "SettingsLibSettingsTransition",
         "SettingsLibActivityEmbedding",
+        "SettingsLibButtonPreference",
     ],
 
     // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
diff --git a/packages/SettingsLib/ButtonPreference/Android.bp b/packages/SettingsLib/ButtonPreference/Android.bp
new file mode 100644
index 0000000..39f804f
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/Android.bp
@@ -0,0 +1,23 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_library {
+    name: "SettingsLibButtonPreference",
+
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+
+    static_libs: [
+        "androidx.preference_preference",
+        "SettingsLibSettingsTheme",
+    ],
+
+    sdk_version: "system_current",
+    min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/ButtonPreference/AndroidManifest.xml b/packages/SettingsLib/ButtonPreference/AndroidManifest.xml
new file mode 100644
index 0000000..2d35c331
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2022 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.settingslib.widget">
+
+    <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/ButtonPreference/res/color/settingslib_btn_colored_background_material.xml b/packages/SettingsLib/ButtonPreference/res/color/settingslib_btn_colored_background_material.xml
new file mode 100644
index 0000000..51ca4ac
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/res/color/settingslib_btn_colored_background_material.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 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.
+-->
+
+<!-- Used for the text of a bordered colored button. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?android:attr/disabledAlpha"
+          android:color="?android:attr/colorButtonNormal" />
+    <item android:color="?android:attr/colorAccent" />
+</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/ButtonPreference/res/color/settingslib_btn_colored_text_material.xml b/packages/SettingsLib/ButtonPreference/res/color/settingslib_btn_colored_text_material.xml
new file mode 100644
index 0000000..8dca4db
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/res/color/settingslib_btn_colored_text_material.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 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.
+-->
+
+<!-- Used for the text of a bordered colored button. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?android:attr/disabledAlpha"
+          android:color="?android:attr/textColorPrimary" />
+    <item android:color="?android:attr/textColorPrimaryInverse" />
+</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/ButtonPreference/res/color/settingslib_ripple_material_dark.xml b/packages/SettingsLib/ButtonPreference/res/color/settingslib_ripple_material_dark.xml
new file mode 100644
index 0000000..1e930ea
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/res/color/settingslib_ripple_material_dark.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:alpha="@dimen/settingslib_highlight_alpha_material_dark"
+          android:color="@android:color/white" />
+</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/ButtonPreference/res/color/settingslib_ripple_material_light.xml b/packages/SettingsLib/ButtonPreference/res/color/settingslib_ripple_material_light.xml
new file mode 100644
index 0000000..378fc16
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/res/color/settingslib_ripple_material_light.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:alpha="@dimen/settingslib_highlight_alpha_material_light"
+          android:color="@android:color/black" />
+</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/ButtonPreference/res/drawable/settingslib_btn_colored_material.xml b/packages/SettingsLib/ButtonPreference/res/drawable/settingslib_btn_colored_material.xml
new file mode 100644
index 0000000..bb0597d
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/res/drawable/settingslib_btn_colored_material.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 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.
+-->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+       android:insetLeft="4dp"
+       android:insetTop="6dp"
+       android:insetRight="4dp"
+       android:insetBottom="6dp">
+    <ripple android:color="?attr/colorControlHighlight">
+        <item>
+            <shape android:shape="rectangle"
+                   android:tint="@color/settingslib_btn_colored_background_material">
+                <corners android:radius="2dp" />
+                <solid android:color="@android:color/white" />
+                <padding android:left="8dp"
+                         android:top="4dp"
+                         android:right="8dp"
+                         android:bottom="4dp" />
+            </shape>
+        </item>
+    </ripple>
+</inset>
\ No newline at end of file
diff --git a/packages/SettingsLib/ButtonPreference/res/layout/settingslib_button_layout.xml b/packages/SettingsLib/ButtonPreference/res/layout/settingslib_button_layout.xml
new file mode 100644
index 0000000..1ff0990
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/res/layout/settingslib_button_layout.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 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"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+    <Button
+        android:id="@+id/settingslib_button"
+        android:drawablePadding="8dp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:paddingStart="16dp"
+        android:paddingEnd="16dp"
+        android:layout_marginStart="-4dp"
+        style="@style/SettingsLibButtonStyle" />
+
+</LinearLayout>
diff --git a/packages/SettingsLib/ButtonPreference/res/values-night/colors.xml b/packages/SettingsLib/ButtonPreference/res/values-night/colors.xml
new file mode 100644
index 0000000..6be7b93
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/res/values-night/colors.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 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>
+    <!-- Material inverse ripple color, useful for inverted backgrounds. -->
+    <color name="settingslib_button_ripple">@color/settingslib_ripple_material_light</color>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/ButtonPreference/res/values-v23/styles.xml b/packages/SettingsLib/ButtonPreference/res/values-v23/styles.xml
new file mode 100644
index 0000000..202645f
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/res/values-v23/styles.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 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="SettingsLibButtonStyle" parent="android:Widget.Material.Button.Colored">
+        <item name="android:theme">@style/SettingsLibRoundedCornerThemeOverlay</item>
+        <item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item>
+        <item name="android:textSize">16sp</item>
+        <item name="android:textColor">@color/settingslib_btn_colored_text_material</item>
+    </style>
+</resources>
diff --git a/packages/SettingsLib/ButtonPreference/res/values-v28/styles.xml b/packages/SettingsLib/ButtonPreference/res/values-v28/styles.xml
new file mode 100644
index 0000000..d8c6ac3f
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/res/values-v28/styles.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 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="SettingsLibButtonStyle" parent="android:Widget.DeviceDefault.Button.Colored">
+        <item name="android:theme">@style/SettingsLibRoundedCornerThemeOverlay</item>
+        <item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item>
+        <item name="android:textSize">16sp</item>
+    </style>
+</resources>
diff --git a/packages/SettingsLib/ButtonPreference/res/values-v31/styles.xml b/packages/SettingsLib/ButtonPreference/res/values-v31/styles.xml
new file mode 100644
index 0000000..12dcbbf
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/res/values-v31/styles.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 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="SettingsLibRoundedCornerThemeOverlay">
+        <item name="android:buttonCornerRadius">24dp</item>
+        <item name="android:paddingStart">16dp</item>
+        <item name="android:paddingEnd">16dp</item>
+        <item name="android:colorControlHighlight">@color/settingslib_button_ripple</item>
+    </style>
+</resources>
diff --git a/packages/SettingsLib/ButtonPreference/res/values/attrs.xml b/packages/SettingsLib/ButtonPreference/res/values/attrs.xml
new file mode 100644
index 0000000..9a4312a
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/res/values/attrs.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 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="ButtonPreference">
+        <attr name="android:gravity" />
+    </declare-styleable>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/ButtonPreference/res/values/colors.xml b/packages/SettingsLib/ButtonPreference/res/values/colors.xml
new file mode 100644
index 0000000..45baeeb
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/res/values/colors.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 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>
+    <!-- Material inverse ripple color, useful for inverted backgrounds. -->
+    <color name="settingslib_button_ripple">@color/settingslib_ripple_material_dark</color>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/ButtonPreference/res/values/dimens.xml b/packages/SettingsLib/ButtonPreference/res/values/dimens.xml
new file mode 100644
index 0000000..3d7831e
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/res/values/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 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>
+    <item name="settingslib_highlight_alpha_material_light" format="float" type="dimen">0.10</item>
+    <item name="settingslib_highlight_alpha_material_dark" format="float" type="dimen">0.10</item>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/ButtonPreference/res/values/styles.xml b/packages/SettingsLib/ButtonPreference/res/values/styles.xml
new file mode 100644
index 0000000..3963732
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/res/values/styles.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 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="SettingsLibRoundedCornerThemeOverlay">
+        <item name="android:paddingStart">16dp</item>
+        <item name="android:paddingEnd">16dp</item>
+        <item name="android:colorControlHighlight">@color/settingslib_button_ripple</item>
+    </style>
+
+    <style name="SettingsLibButtonStyle" parent="android:Widget.Material.Button">
+        <item name="android:theme">@style/SettingsLibRoundedCornerThemeOverlay</item>
+        <item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item>
+        <item name="android:textSize">16sp</item>
+        <item name="android:textColor">@color/settingslib_btn_colored_text_material</item>
+        <item name="android:background">@drawable/settingslib_btn_colored_material</item>
+    </style>
+</resources>
diff --git a/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java b/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java
new file mode 100644
index 0000000..56d2967
--- /dev/null
+++ b/packages/SettingsLib/ButtonPreference/src/com/android/settingslib/widget/ButtonPreference.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2022 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 com.android.settingslib.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import androidx.annotation.GravityInt;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+/**
+ * A preference handled a button
+ */
+public class ButtonPreference extends Preference {
+
+    private static final int ICON_SIZE = 24;
+
+    private View.OnClickListener mClickListener;
+    private Button mButton;
+    private CharSequence mTitle;
+    private Drawable mIcon;
+    @GravityInt
+    private int mGravity;
+
+    /**
+     * Constructs a new LayoutPreference with the given context's theme, the supplied
+     * attribute set, and default style attribute.
+     *
+     * @param context      The Context the view is running in, through which it can
+     *                     access the current theme, resources, etc.
+     * @param attrs        The attributes of the XML tag that is inflating the view.
+     * @param defStyleAttr An attribute in the current theme that contains a
+     *                     reference to a style resource that supplies default
+     *                     values for the view. Can be 0 to not look for
+     *                     defaults.
+     */
+    public ButtonPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context, attrs, defStyleAttr);
+    }
+
+    /**
+     * Constructs a new LayoutPreference with the given context's theme and the supplied
+     * attribute set.
+     *
+     * @param context The Context the view is running in, through which it can
+     *                access the current theme, resources, etc.
+     * @param attrs   The attributes of the XML tag that is inflating the view.
+     */
+    public ButtonPreference(Context context, AttributeSet attrs) {
+        this(context, attrs, 0 /* defStyleAttr */);
+    }
+
+    /**
+     * Constructs a new LayoutPreference with the given context's theme and a customized view.
+     *
+     * @param context The Context the view is running in, through which it can
+     *                access the current theme, resources, etc.
+     */
+    public ButtonPreference(Context context) {
+        this(context, null);
+    }
+
+    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
+        setLayoutResource(R.layout.settingslib_button_layout);
+
+        if (attrs != null) {
+            TypedArray a = context.obtainStyledAttributes(attrs,
+                    androidx.preference.R.styleable.Preference, defStyleAttr,
+                    0 /*defStyleRes*/);
+            mTitle = a.getText(
+                    androidx.preference.R.styleable.Preference_android_title);
+            mIcon = a.getDrawable(
+                    androidx.preference.R.styleable.Preference_android_icon);
+            a.recycle();
+
+            a = context.obtainStyledAttributes(attrs,
+                    R.styleable.ButtonPreference, defStyleAttr,
+                    0 /*defStyleRes*/);
+            mGravity = a.getInt(R.styleable.ButtonPreference_android_gravity, Gravity.START);
+            a.recycle();
+        }
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        mButton = (Button) holder.findViewById(R.id.settingslib_button);
+        setTitle(mTitle);
+        setIcon(mIcon);
+        setGravity(mGravity);
+        setOnClickListener(mClickListener);
+
+        if (mButton != null) {
+            final boolean selectable = isSelectable();
+            mButton.setFocusable(selectable);
+            mButton.setClickable(selectable);
+
+            mButton.setEnabled(isEnabled());
+        }
+
+        holder.setDividerAllowedAbove(false);
+        holder.setDividerAllowedBelow(false);
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {
+        mTitle = title;
+        if (mButton != null) {
+            mButton.setText(title);
+        }
+    }
+
+    @Override
+    public void setIcon(Drawable icon) {
+        mIcon = icon;
+        if (mButton == null || icon == null) {
+            return;
+        }
+        //get pixel from dp
+        int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, ICON_SIZE,
+                getContext().getResources().getDisplayMetrics());
+        icon.setBounds(0, 0, size, size);
+
+        //set drawableStart
+        mButton.setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null/* top */, null/* end */,
+                null/* bottom */);
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        if (mButton != null) {
+            mButton.setEnabled(enabled);
+        }
+    }
+
+    /**
+     * Return Button
+     */
+    public Button getButton() {
+        return mButton;
+    }
+
+
+    /**
+     * Set a listener for button click
+     */
+    public void setOnClickListener(View.OnClickListener listener) {
+        mClickListener = listener;
+        if (mButton != null) {
+            mButton.setOnClickListener(listener);
+        }
+    }
+
+    /**
+     * Set the gravity of button
+     *
+     * @param gravity The {@link Gravity} supported CENTER_HORIZONTAL
+     *                and the default value is START
+     */
+    public void setGravity(@GravityInt int gravity) {
+        if (gravity == Gravity.CENTER_HORIZONTAL || gravity == Gravity.CENTER_VERTICAL
+                || gravity == Gravity.CENTER) {
+            mGravity = Gravity.CENTER_HORIZONTAL;
+        } else {
+            mGravity = Gravity.START;
+        }
+
+        if (mButton != null) {
+            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mButton.getLayoutParams();
+            lp.gravity = mGravity;
+            mButton.setLayoutParams(lp);
+        }
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ButtonPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ButtonPreferenceTest.java
new file mode 100644
index 0000000..625b214
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ButtonPreferenceTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2022 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 com.android.settingslib.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.robolectric.Shadows.shadowOf;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import androidx.preference.PreferenceViewHolder;
+import androidx.preference.R;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.shadows.ShadowDrawable;
+
+@RunWith(RobolectricTestRunner.class)
+public class ButtonPreferenceTest {
+
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+    private ButtonPreference mPreference;
+    private PreferenceViewHolder mHolder;
+
+    private boolean mClickListenerCalled;
+    private final View.OnClickListener mClickListener = v -> mClickListenerCalled = true;
+
+    @Before
+    public void setUp() {
+        mClickListenerCalled = false;
+        mPreference = new ButtonPreference(mContext);
+        setUpViewHolder();
+    }
+
+    @Test
+    public void onBindViewHolder_whenTitleSet_shouldSetButtonText() {
+        final String testTitle = "Test title";
+        mPreference.setTitle(testTitle);
+
+        mPreference.onBindViewHolder(mHolder);
+
+        final Button button = mPreference.getButton();
+        assertThat(button.getText().toString()).isEqualTo(testTitle);
+    }
+
+    @Test
+    public void onBindViewHolder_whenIconSet_shouldSetIcon() {
+        mPreference.setIcon(R.drawable.settingslib_ic_cross);
+
+        mPreference.onBindViewHolder(mHolder);
+
+        final Button button = mPreference.getButton();
+        final Drawable icon = button.getCompoundDrawablesRelative()[0];
+        final ShadowDrawable shadowDrawable = shadowOf(icon);
+        assertThat(shadowDrawable.getCreatedFromResId()).isEqualTo(R.drawable.settingslib_ic_cross);
+    }
+
+    @Test
+    public void onBindViewHolder_setEnable_shouldSetButtonEnabled() {
+        mPreference.setEnabled(true);
+
+        mPreference.onBindViewHolder(mHolder);
+
+        final Button button = mPreference.getButton();
+        assertThat(button.isEnabled()).isTrue();
+    }
+
+    @Test
+    public void onBindViewHolder_setDisable_shouldSetButtonDisabled() {
+        mPreference.setEnabled(false);
+
+        mPreference.onBindViewHolder(mHolder);
+
+        final Button button = mPreference.getButton();
+        assertThat(button.isEnabled()).isFalse();
+    }
+
+    @Test
+    public void onBindViewHolder_default_shouldReturnButtonGravityStart() {
+        mPreference.onBindViewHolder(mHolder);
+
+        final Button button = mPreference.getButton();
+        final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) button.getLayoutParams();
+        assertThat(lp.gravity).isEqualTo(Gravity.START);
+    }
+
+    @Test
+    public void onBindViewHolder_setGravityStart_shouldReturnButtonGravityStart() {
+        mPreference.setGravity(Gravity.START);
+
+        mPreference.onBindViewHolder(mHolder);
+
+        final Button button = mPreference.getButton();
+        final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) button.getLayoutParams();
+        assertThat(lp.gravity).isEqualTo(Gravity.START);
+    }
+
+    @Test
+    public void onBindViewHolder_setGravityCenter_shouldReturnButtonGravityCenterHorizontal() {
+        mPreference.setGravity(Gravity.CENTER_HORIZONTAL);
+
+        mPreference.onBindViewHolder(mHolder);
+
+        final Button button = mPreference.getButton();
+        final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) button.getLayoutParams();
+        assertThat(lp.gravity).isEqualTo(Gravity.CENTER_HORIZONTAL);
+
+        mPreference.setGravity(Gravity.CENTER_VERTICAL);
+        mPreference.onBindViewHolder(mHolder);
+        assertThat(lp.gravity).isEqualTo(Gravity.CENTER_HORIZONTAL);
+
+        mPreference.setGravity(Gravity.CENTER);
+        mPreference.onBindViewHolder(mHolder);
+        assertThat(lp.gravity).isEqualTo(Gravity.CENTER_HORIZONTAL);
+    }
+
+    @Test
+    public void onBindViewHolder_setUnsupportedGravity_shouldReturnButtonGravityStart() {
+        mPreference.setGravity(Gravity.END);
+
+        mPreference.onBindViewHolder(mHolder);
+
+        final Button button = mPreference.getButton();
+        final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) button.getLayoutParams();
+        assertThat(lp.gravity).isEqualTo(Gravity.START);
+    }
+
+    @Test
+    public void setButtonOnClickListener_setsClickListener() {
+        mPreference.setOnClickListener(mClickListener);
+
+        mPreference.onBindViewHolder(mHolder);
+        final Button button = mPreference.getButton();
+        button.callOnClick();
+
+        assertThat(mClickListenerCalled).isTrue();
+    }
+
+    private void setUpViewHolder() {
+        final View rootView =
+                View.inflate(mContext, mPreference.getLayoutResource(), null /* parent */);
+        mHolder = PreferenceViewHolder.createInstanceForTests(rootView);
+    }
+}