Create a bar char preference widget

- Per Q design, we will show a bar chart in Settings > Privacy page.
  Permission team also needs this bar chart in their page.
- Create a new library named SettingsLibBarChartPreference

Test: visual, robotest
Change-Id: Iff5a1233357a6aa6a667c0059f542a1b444b59a2
Fixes: 117623686
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 042808a0..2321790 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -19,6 +19,7 @@
         "SettingsLibLayoutPreference",
         "SettingsLibActionButtonsPreference",
         "SettingsLibEntityHeaderWidgets",
+        "SettingsLibBarChartPreference"
     ],
 
     // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
diff --git a/packages/SettingsLib/BarChartPreference/Android.bp b/packages/SettingsLib/BarChartPreference/Android.bp
new file mode 100644
index 0000000..477e897
--- /dev/null
+++ b/packages/SettingsLib/BarChartPreference/Android.bp
@@ -0,0 +1,13 @@
+android_library {
+    name: "SettingsLibBarChartPreference",
+
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+
+    static_libs: [
+          "androidx.preference_preference",
+    ],
+
+    sdk_version: "system_current",
+    min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/BarChartPreference/AndroidManifest.xml b/packages/SettingsLib/BarChartPreference/AndroidManifest.xml
new file mode 100644
index 0000000..4b9f1ab
--- /dev/null
+++ b/packages/SettingsLib/BarChartPreference/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2018 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/BarChartPreference/res/layout/settings_bar_chart.xml b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml
new file mode 100644
index 0000000..1a4d7b7
--- /dev/null
+++ b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2018 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"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginStart="16dp"
+    android:layout_marginEnd="16dp"
+    android:gravity="center"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/bar_chart_title"
+        android:layout_width="wrap_content"
+        android:layout_height="48dp"
+        android:gravity="center"
+        android:textAppearance="@style/BarChart.Text.HeaderTitle"/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center|bottom">
+
+        <com.android.settingslib.widget.BarView
+            android:id="@+id/bar_view1"
+            style="@style/BarViewStyle"
+            settings:barColor="#FA7B17"/>
+        <com.android.settingslib.widget.BarView
+            android:id="@+id/bar_view2"
+            style="@style/BarViewStyle"
+            settings:barColor="#F439A0"/>
+        <com.android.settingslib.widget.BarView
+            android:id="@+id/bar_view3"
+            style="@style/BarViewStyle"
+            settings:barColor="#A142F4"/>
+        <com.android.settingslib.widget.BarView
+            android:id="@+id/bar_view4"
+            style="@style/BarViewStyle"
+            settings:barColor="#24C1E0"/>
+    </LinearLayout>
+
+    <Button
+        android:id="@+id/bar_chart_details"
+        style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+        android:layout_width="wrap_content"
+        android:layout_height="48dp"
+        android:gravity="center"/>
+
+</LinearLayout>
diff --git a/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_view.xml b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_view.xml
new file mode 100644
index 0000000..b053317
--- /dev/null
+++ b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_view.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2018 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="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    android:orientation="vertical">
+
+    <View
+        android:id="@+id/bar_view"
+        android:layout_width="8dp"
+        android:layout_height="wrap_content"
+        android:background="?android:attr/colorAccent"/>
+
+    <ImageView
+        android:id="@+id/icon_view"
+        android:layout_width="@dimen/settings_bar_view_icon_size"
+        android:layout_height="@dimen/settings_bar_view_icon_size"
+        android:scaleType="fitCenter"
+        android:layout_marginTop="12dp"
+        android:layout_marginBottom="12dp"/>
+
+    <TextView
+        android:id="@+id/bar_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="10dp"
+        android:layout_marginBottom="2dp"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:textAppearance="@style/BarChart.Text.Title"/>
+
+    <TextView
+        android:id="@+id/bar_summary"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="12dp"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:textAppearance="@style/BarChart.Text.Summary"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/BarChartPreference/res/values/attrs.xml b/packages/SettingsLib/BarChartPreference/res/values/attrs.xml
new file mode 100644
index 0000000..df3eb0a
--- /dev/null
+++ b/packages/SettingsLib/BarChartPreference/res/values/attrs.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2018 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="SettingsBarView">
+        <!-- The color of bar view -->
+        <attr name="barColor" format="color" />
+    </declare-styleable>
+
+</resources>
diff --git a/packages/SettingsLib/BarChartPreference/res/values/dimens.xml b/packages/SettingsLib/BarChartPreference/res/values/dimens.xml
new file mode 100644
index 0000000..7148afa
--- /dev/null
+++ b/packages/SettingsLib/BarChartPreference/res/values/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2018 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>
+    <dimen name="settings_bar_view_max_height">106dp</dimen>
+    <dimen name="settings_bar_view_icon_size">24dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/BarChartPreference/res/values/styles.xml b/packages/SettingsLib/BarChartPreference/res/values/styles.xml
new file mode 100644
index 0000000..647d080
--- /dev/null
+++ b/packages/SettingsLib/BarChartPreference/res/values/styles.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2018 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="BarViewStyle">
+        <item name="android:layout_width">0dp</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:layout_weight">1</item>
+        <item name="android:layout_marginStart">8dp</item>
+        <item name="android:layout_marginEnd">8dp</item>
+    </style>
+
+    <style name="BarChart.Text"
+           parent="@android:style/TextAppearance.Material.Subhead">
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    </style>
+
+    <style name="BarChart.Text.HeaderTitle">
+        <item name="android:textSize">14sp</item>
+    </style>
+
+    <style name="BarChart.Text.Title">
+        <item name="android:textSize">22sp</item>
+    </style>
+
+    <style name="BarChart.Text.Summary"
+           parent="@android:style/TextAppearance.Material.Body1">
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+        <item name="android:textSize">14sp</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
new file mode 100644
index 0000000..89ebf4d
--- /dev/null
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2018 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.util.AttributeSet;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+import java.util.Arrays;
+
+/**
+ * This BarChartPreference shows four bar views in this preference at most.
+ *
+ * <p>The following code sample shows a typical use, with an XML layout and code to initialize the
+ * contents of the BarChartPreference:
+ *
+ * <pre>
+ * &lt;com.android.settingslib.widget.BarChartPreference
+ *        android:key="bar_chart"/&gt;
+ * </pre>
+ *
+ * <p>This code sample demonstrates how to initialize the contents of the BarChartPreference defined
+ * in the previous XML layout:
+ *
+ * <pre>
+ * BarViewInfo[] viewsInfo = new BarViewInfo [] {
+ *     new BarViewInfo(icon, 18, res of summary),
+ *     new BarViewInfo(icon, 25, res of summary),
+ *     new BarViewInfo(icon, 10, res of summary),
+ *     new BarViewInfo(icon, 3, res of summary),
+ *  };
+ * </pre>
+ *
+ * <pre>
+ * BarChartPreference preference = ((BarChartPreference) findPreference("bar_chart"));
+ *
+ * preference.setBarChartTitleRes(R.string.title_res);
+ * preference.setBarChartDetailsRes(R.string.details_res);
+ * preference.setBarChartDetailsClickListener(v -> doSomething());
+ * preference.setAllBarViewsData(viewsInfo);
+ * </pre>
+ */
+public class BarChartPreference extends Preference {
+
+    private static final String TAG = "BarChartPreference";
+    private static final int MAXIMUM_BAR_VIEWS = 4;
+    private static final int[] BAR_VIEWS = {
+            R.id.bar_view1,
+            R.id.bar_view2,
+            R.id.bar_view3,
+            R.id.bar_view4
+    };
+
+    private int mMaxBarHeight;
+    private @StringRes int mTitleId;
+    private @StringRes int mDetailsId;
+    private BarViewInfo[] mBarViewsInfo;
+    private View.OnClickListener mDetailsOnClickListener;
+
+    /**
+     * Constructs a new BarChartPreference with the given context's theme.
+     * It sets a layout with settings bar chart style
+     *
+     * @param context The Context the view is running in, through which it can
+     *                access the current theme, resources, etc.
+     */
+    public BarChartPreference(Context context) {
+        super(context);
+        init();
+    }
+
+    /**
+     * Constructs a new BarChartPreference with the given context's theme and the supplied
+     * attribute set.
+     * It sets a layout with settings bar chart style
+     *
+     * @param context the Context the view is running in
+     * @param attrs the attributes of the XML tag that is inflating the view.
+     */
+    public BarChartPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    /**
+     * Constructs a new BarChartPreference with the given context's theme, the supplied
+     * attribute set, and default style attribute.
+     * It sets a layout with settings bar chart style
+     *
+     * @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 BarChartPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    /**
+     * Constructs a new BarChartPreference with the given context's theme, the supplied
+     * attribute set, and default styles.
+     * It sets a layout with settings bar chart style
+     *
+     * @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.
+     * @param defStyleRes  A resource identifier of a style resource that
+     *                     supplies default values for the view, used only if
+     *                     defStyleAttr is 0 or can not be found in the theme.
+     *                     Can be 0 to not look for defaults.
+     */
+    public BarChartPreference(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+    }
+
+    /**
+     * Set the text resource for bar chart title.
+     */
+    public void setBarChartTitle(@StringRes int resId) {
+        mTitleId = resId;
+        notifyChanged();
+    }
+
+    /**
+     * Set the text resource for bar chart details.
+     */
+    public void setBarChartDetails(@StringRes int resId) {
+        mDetailsId = resId;
+        notifyChanged();
+    }
+
+    /**
+     * Register a callback to be invoked when bar chart details view is clicked.
+     */
+    public void setBarChartDetailsClickListener(@Nullable View.OnClickListener clickListener) {
+        mDetailsOnClickListener = clickListener;
+        notifyChanged();
+    }
+
+    /**
+     * Set all bar view information which you'd like to show in preference.
+     *
+     * <p>This method helps you do a sort by {@linkBarViewInfo#mBarNumber} in descending order.
+     *
+     * @param barViewsInfo the barViewsInfo contain at least one {@link BarViewInfo}.
+     */
+    public void setAllBarViewsInfo(@NonNull BarViewInfo[] barViewsInfo) {
+        mBarViewsInfo = barViewsInfo;
+        // Do a sort in descending order, the first element would have max {@link
+        // BarViewInfo#mBarNumber}
+        Arrays.sort(mBarViewsInfo);
+        caculateAllBarViewsHeight();
+        notifyChanged();
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+        holder.setDividerAllowedAbove(true);
+        holder.setDividerAllowedBelow(true);
+
+        bindChartTitleView(holder);
+        bindChartDetailsView(holder);
+        updateBarChart(holder);
+    }
+
+    private void init() {
+        setSelectable(false);
+        setLayoutResource(R.layout.settings_bar_chart);
+        mMaxBarHeight = getContext().getResources().getDimensionPixelSize(
+                R.dimen.settings_bar_view_max_height);
+    }
+
+    private void bindChartTitleView(PreferenceViewHolder holder) {
+        final TextView titleView = (TextView) holder.findViewById(R.id.bar_chart_title);
+        titleView.setText(mTitleId);
+    }
+
+    private void bindChartDetailsView(PreferenceViewHolder holder) {
+        final Button detailsView = (Button) holder.findViewById(R.id.bar_chart_details);
+        detailsView.setText(mDetailsId);
+        detailsView.setOnClickListener(mDetailsOnClickListener);
+    }
+
+    private void updateBarChart(PreferenceViewHolder holder) {
+        for (int index = 0; index < MAXIMUM_BAR_VIEWS; index++) {
+            final BarView barView = (BarView) holder.findViewById(BAR_VIEWS[index]);
+
+            // If there is no bar views data can be shown.
+            if (mBarViewsInfo == null || index >= mBarViewsInfo.length) {
+                barView.setVisibility(View.GONE);
+                continue;
+            }
+            barView.setVisibility(View.VISIBLE);
+            barView.updateBarViewUI(mBarViewsInfo[index]);
+        }
+    }
+
+    private void caculateAllBarViewsHeight() {
+        // Since we sorted this array in advance, the first element must have the max {@link
+        // BarViewInfo#mBarNumber}.
+        final int maxBarViewNumber = mBarViewsInfo[0].getBarNumber();
+        // If the max number of bar view is zero, then we don't caculate the unit for bar height.
+        final int unit = maxBarViewNumber == 0 ? 0 : mMaxBarHeight / maxBarViewNumber;
+
+        for (BarViewInfo barView : mBarViewsInfo) {
+            barView.setBarHeight(barView.getBarNumber() * unit);
+        }
+    }
+}
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
new file mode 100644
index 0000000..6243a2d
--- /dev/null
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2018 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.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.VisibleForTesting;
+
+/**
+ * A extension view for bar chart.
+ */
+public class BarView extends LinearLayout {
+
+    private static final String TAG = "BarView";
+
+    private View mBarView;
+    private ImageView mIcon;
+    private TextView mBarTitle;
+    private TextView mBarSummary;
+
+    /**
+     * Constructs a new BarView with the given context's theme.
+     *
+     * @param context The Context the view is running in, through which it can
+     *                access the current theme, resources, etc.
+     */
+    public BarView(Context context) {
+        super(context);
+        init();
+    }
+
+    /**
+     * Constructs a new BarView with the given context's theme and the supplied
+     * attribute set.
+     *
+     * @param context the Context the view is running in
+     * @param attrs the attributes of the XML tag that is inflating the view.
+     */
+    public BarView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+
+        // Get accent color
+        TypedArray a = context.obtainStyledAttributes(new int[]{android.R.attr.colorAccent});
+        @ColorInt final int colorAccent = a.getColor(0, 0);
+
+        // Get bar color from layout XML
+        a = context.obtainStyledAttributes(attrs, R.styleable.SettingsBarView);
+        @ColorInt final int barColor = a.getColor(R.styleable.SettingsBarView_barColor,
+                colorAccent);
+        a.recycle();
+
+        mBarView.setBackgroundColor(barColor);
+    }
+
+    /**
+     * This helps update the bar view UI with a {@link BarViewInfo}.
+     *
+     * @param barViewInfo A {@link BarViewInfo} saves bar view status.
+     */
+    public void updateBarViewUI(BarViewInfo barViewInfo) {
+        //Set height of bar view
+        mBarView.getLayoutParams().height = barViewInfo.getBarHeight();
+        mIcon.setImageDrawable(barViewInfo.getIcon());
+        // For now, we use the bar number as title.
+        mBarTitle.setText(Integer.toString(barViewInfo.getBarNumber()));
+        mBarSummary.setText(barViewInfo.getSummaryRes());
+    }
+
+    @VisibleForTesting
+    CharSequence getTitle() {
+        return mBarTitle.getText();
+    }
+
+    @VisibleForTesting
+    CharSequence getSummary() {
+        return mBarSummary.getText();
+    }
+
+    private void init() {
+        LayoutInflater.from(getContext()).inflate(R.layout.settings_bar_view, this);
+        setOrientation(LinearLayout.VERTICAL);
+        setGravity(Gravity.CENTER);
+
+        mBarView = findViewById(R.id.bar_view);
+        mIcon = (ImageView) findViewById(R.id.icon_view);
+        mBarTitle = (TextView) findViewById(R.id.bar_title);
+        mBarSummary = (TextView) findViewById(R.id.bar_summary);
+    }
+
+    private void setOnClickListner(View.OnClickListener listener) {
+        mBarView.setOnClickListener(listener);
+    }
+}
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarViewInfo.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarViewInfo.java
new file mode 100644
index 0000000..aa83ce9
--- /dev/null
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarViewInfo.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2018 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.graphics.drawable.Drawable;
+import android.view.View;
+
+import androidx.annotation.IntRange;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+
+import java.util.Comparator;
+
+/**
+ * A class responsible for saving bar view information.
+ */
+public class BarViewInfo implements Comparable<BarViewInfo> {
+
+    private final Drawable mIcon;
+    private View.OnClickListener mListener;
+    private @StringRes int mSummaryRes;
+    // A number indicates this bar's height. The larger number shows a higher bar view.
+    private int mBarNumber;
+    // A real height of bar view.
+    private int mBarHeight;
+
+    /**
+     * Construct a BarViewInfo instance.
+     *
+     * @param icon the icon of bar view.
+     * @param barNumber the number of bar view. The larger number show a more height of bar view.
+     * @param summaryRes the resource identifier of the string resource to be displayed
+     * @return BarViewInfo object.
+     */
+    public BarViewInfo(Drawable icon, @IntRange(from = 0) int barNumber,
+            @StringRes int summaryRes) {
+        mIcon = icon;
+        mBarNumber = barNumber;
+        mSummaryRes = summaryRes;
+    }
+
+    /**
+     * Set number for bar view.
+     *
+     * @param barNumber the number of bar view. The larger number shows a higher bar view.
+     */
+    public void setBarNumber(@IntRange(from = 0) int barNumber) {
+        mBarNumber = barNumber;
+    }
+
+    /**
+     * Set summary resource for bar view
+     *
+     * @param resId the resource identifier of the string resource to be displayed
+     */
+    public void setSummary(@StringRes int resId) {
+        mSummaryRes = resId;
+    }
+
+    /**
+     * Set a click listner for bar view.
+     *
+     * @param listener the click listner is attached on bar view.
+     */
+    public void setClickListener(@Nullable View.OnClickListener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Get the icon of bar view.
+     *
+     * @return Drawable the icon of bar view.
+     */
+    public Drawable getIcon() {
+        return mIcon;
+    }
+
+    /**
+     * Get the OnClickListener of bar view.
+     *
+     * @return View.OnClickListener the click listner of bar view.
+     */
+    public View.OnClickListener getListener() {
+        return mListener;
+    }
+
+    /**
+     * Get the real height of bar view.
+     *
+     * @return the real height of bar view.
+     */
+    public int getBarHeight() {
+        return mBarHeight;
+    }
+
+    /**
+     * Get summary resource of bar view.
+     *
+     * @return summary resource of bar view.
+     */
+    public int getSummaryRes() {
+        return mSummaryRes;
+    }
+
+    /**
+     * Get the number of app uses this permisssion.
+     *
+     * @return the number of app uses this permission.
+     */
+    public int getBarNumber() {
+        return mBarNumber;
+    }
+
+    @Override
+    public int compareTo(BarViewInfo other) {
+        // Descending order
+        return Comparator.comparingInt((BarViewInfo barViewInfo) -> barViewInfo.mBarNumber)
+                .compare(other, this);
+    }
+
+    /**
+     * Set a real height for bar view.
+     *
+     * <p>This method should not be called by outside. It usually should be called by
+     * {@link BarChartPreference#caculateAllBarViewsHeight}
+     *
+     * @param barHeight the real bar height for bar view.
+     */
+    void setBarHeight(@IntRange(from = 0) int barHeight) {
+        mBarHeight = barHeight;
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
new file mode 100644
index 0000000..371c3d4
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2018 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 android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.preference.PreferenceViewHolder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class BarChartPreferenceTest {
+
+    private Context mContext;
+    private View mBarChartView;
+    private Drawable mIcon;
+    private BarView mBarView1;
+    private BarView mBarView2;
+    private BarView mBarView3;
+    private BarView mBarView4;
+    private PreferenceViewHolder mHolder;
+    private BarChartPreference mPreference;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mBarChartView = View.inflate(mContext, R.layout.settings_bar_chart, null /* parent */);
+        mHolder = PreferenceViewHolder.createInstanceForTests(mBarChartView);
+        mPreference = new BarChartPreference(mContext, null /* attrs */);
+        mPreference.setBarChartTitle(R.string.debug_app);
+        mPreference.setBarChartDetails(R.string.debug_app);
+
+
+        mIcon = mContext.getDrawable(R.drawable.ic_menu);
+        mBarView1 = (BarView) mBarChartView.findViewById(R.id.bar_view1);
+        mBarView2 = (BarView) mBarChartView.findViewById(R.id.bar_view2);
+        mBarView3 = (BarView) mBarChartView.findViewById(R.id.bar_view3);
+        mBarView4 = (BarView) mBarChartView.findViewById(R.id.bar_view4);
+    }
+
+    @Test
+    public void setBarChartTitleRes_setTitleRes_showInBarChartTitle() {
+        final TextView titleView = (TextView) mBarChartView.findViewById(R.id.bar_chart_title);
+
+        mPreference.setBarChartTitle(R.string.debug_app);
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(titleView.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(titleView.getText()).isEqualTo(mContext.getText(R.string.debug_app));
+    }
+
+    @Test
+    public void setBarChartDetailsRes_setDetailsRes_showInBarChartDetails() {
+        final TextView detailsView = (TextView) mBarChartView.findViewById(R.id.bar_chart_details);
+
+        mPreference.setBarChartDetails(R.string.debug_app);
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(detailsView.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(detailsView.getText()).isEqualTo(mContext.getText(R.string.debug_app));
+    }
+
+    @Test
+    public void setBarChartDetailsClickListener_setClickListener_detailsViewAttachClickListener() {
+        final TextView detailsView = (TextView) mBarChartView.findViewById(R.id.bar_chart_details);
+
+        mPreference.setBarChartDetailsClickListener(v -> {
+        });
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(detailsView.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(detailsView.hasOnClickListeners()).isTrue();
+    }
+
+    @Test
+    public void setAllBarViewsInfo_setOneBarViewInfo_showOneBarView() {
+        final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
+                new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app)
+        };
+
+        mPreference.setAllBarViewsInfo(barViewsInfo);
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView1.getTitle()).isEqualTo("10");
+
+        assertThat(mBarView2.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mBarView3.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mBarView4.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void setAllBarViewsInfo_setTwoBarViewsInfo_showTwoBarViews() {
+        final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
+                new BarViewInfo(mIcon, 20 /* barNumber */, R.string.debug_app),
+                new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app)
+        };
+
+        mPreference.setAllBarViewsInfo(barViewsInfo);
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView1.getTitle()).isEqualTo("20");
+        assertThat(mBarView2.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView2.getTitle()).isEqualTo("10");
+
+        assertThat(mBarView3.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mBarView4.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void setAllBarViewsInfo_setThreeBarViewsInfo_showThreeBarViews() {
+        final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
+                new BarViewInfo(mIcon, 20 /* barNumber */, R.string.debug_app),
+                new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app),
+                new BarViewInfo(mIcon, 5 /* barNumber */, R.string.debug_app)
+        };
+
+        mPreference.setAllBarViewsInfo(barViewsInfo);
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView1.getTitle()).isEqualTo("20");
+        assertThat(mBarView2.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView2.getTitle()).isEqualTo("10");
+        assertThat(mBarView3.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView3.getTitle()).isEqualTo("5");
+
+        assertThat(mBarView4.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void setAllBarViewsInfo_setFourBarViewsInfo_showFourBarViews() {
+        final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
+                new BarViewInfo(mIcon, 20 /* barNumber */, R.string.debug_app),
+                new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app),
+                new BarViewInfo(mIcon, 5 /* barNumber */, R.string.debug_app),
+                new BarViewInfo(mIcon, 2 /* barNumber */, R.string.debug_app),
+        };
+
+        mPreference.setAllBarViewsInfo(barViewsInfo);
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView1.getTitle()).isEqualTo("20");
+        assertThat(mBarView2.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView2.getTitle()).isEqualTo("10");
+        assertThat(mBarView3.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView3.getTitle()).isEqualTo("5");
+        assertThat(mBarView4.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView4.getTitle()).isEqualTo("2");
+    }
+
+    @Test
+    public void setAllBarViewsInfo_setFourBarViewsInfo_barViewWasSortedInDescending() {
+        final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
+                new BarViewInfo(mIcon, 30 /* barNumber */, R.string.debug_app),
+                new BarViewInfo(mIcon, 50 /* barNumber */, R.string.debug_app),
+                new BarViewInfo(mIcon, 5 /* barNumber */, R.string.debug_app),
+                new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app),
+        };
+
+        mPreference.setAllBarViewsInfo(barViewsInfo);
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView1.getTitle()).isEqualTo("50");
+        assertThat(mBarView2.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView2.getTitle()).isEqualTo("30");
+        assertThat(mBarView3.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView3.getTitle()).isEqualTo("10");
+        assertThat(mBarView4.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView4.getTitle()).isEqualTo("5");
+    }
+
+    @Test
+    public void setAllBarViewsInfo_setValidSummaryRes_barViewShouldShowSummary() {
+        final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
+                new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app),
+        };
+
+        mPreference.setAllBarViewsInfo(barViewsInfo);
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView1.getSummary()).isEqualTo(mContext.getText(R.string.debug_app));
+    }
+}