| /* |
| * Copyright (C) 2019 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.preference.Preference; |
| import androidx.preference.PreferenceViewHolder; |
| |
| import java.util.Arrays; |
| |
| /** |
| * This BarChartPreference shows up to 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> |
| * <com.android.settingslib.widget.BarChartPreference |
| * android:key="bar_chart"/> |
| * </pre> |
| * |
| * <p>This code sample demonstrates how to initialize the contents of the BarChartPreference |
| * defined in the previous XML layout: |
| * |
| * <pre> |
| * BarChartPreference preference = ((BarChartPreference) findPreference("bar_chart")); |
| * |
| * BarChartInfo info = new BarChartInfo.Builder() |
| * .setTitle(R.string.permission_bar_chart_title) |
| * .setDetails(R.string.permission_bar_chart_details) |
| * .setEmptyText(R.string.permission_bar_chart_empty_text) |
| * .addBarViewInfo(new barViewInfo(...)) |
| * .addBarViewInfo(new barViewInfo(...)) |
| * .addBarViewInfo(new barViewInfo(...)) |
| * .addBarViewInfo(new barViewInfo(...)) |
| * .setDetailsOnClickListener(v -> doSomething()) |
| * .build(); |
| * |
| * preference.initializeBarChart(info); |
| * </pre> |
| * |
| * |
| * <p>You also can update new information for bar views by |
| * {@link BarChartPreference#setBarViewInfos(BarViewInfo[])} |
| * |
| * <pre> |
| * BarViewInfo[] barViewsInfo = new BarViewInfo [] { |
| * new BarViewInfo(...), |
| * new BarViewInfo(...), |
| * new BarViewInfo(...), |
| * new BarViewInfo(...), |
| * }; |
| * |
| * preference.setBarViewInfos(barViewsInfo); |
| * </pre> |
| */ |
| public class BarChartPreference extends Preference { |
| |
| public static final int MAXIMUM_BAR_VIEWS = 4; |
| private static final String TAG = "BarChartPreference"; |
| 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 BarChartInfo mBarChartInfo; |
| |
| public BarChartPreference(Context context) { |
| super(context); |
| init(); |
| } |
| |
| public BarChartPreference(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| init(); |
| } |
| |
| public BarChartPreference(Context context, AttributeSet attrs, int defStyleAttr) { |
| super(context, attrs, defStyleAttr); |
| init(); |
| } |
| |
| public BarChartPreference(Context context, AttributeSet attrs, int defStyleAttr, |
| int defStyleRes) { |
| super(context, attrs, defStyleAttr, defStyleRes); |
| init(); |
| } |
| |
| /** |
| * According to the information in {@link BarChartInfo} to initialize bar chart. |
| * |
| * @param barChartInfo The barChartInfo contains title, details, empty text, click listener |
| * attached on details view and four bar views. |
| */ |
| public void initializeBarChart(@NonNull BarChartInfo barChartInfo) { |
| mBarChartInfo = barChartInfo; |
| notifyChanged(); |
| } |
| |
| /** |
| * Sets all bar view information which you'd like to show in preference. |
| * |
| * @param barViewInfos the barViewInfos contain at least one {@link BarViewInfo}. |
| */ |
| public void setBarViewInfos(@Nullable BarViewInfo[] barViewInfos) { |
| if (barViewInfos != null && barViewInfos.length > MAXIMUM_BAR_VIEWS) { |
| throw new IllegalStateException("We only support up to four bar views"); |
| } |
| mBarChartInfo.setBarViewInfos(barViewInfos); |
| notifyChanged(); |
| } |
| |
| @Override |
| public void onBindViewHolder(PreferenceViewHolder holder) { |
| super.onBindViewHolder(holder); |
| holder.setDividerAllowedAbove(true); |
| holder.setDividerAllowedBelow(true); |
| |
| // We must show title of bar chart. |
| bindChartTitleView(holder); |
| |
| final BarViewInfo[] barViewInfos = mBarChartInfo.getBarViewInfos(); |
| // If there is no any bar view, we just show an empty text. |
| if (barViewInfos == null || barViewInfos.length == 0) { |
| setEmptyViewVisible(holder, true /* visible */); |
| return; |
| } |
| setEmptyViewVisible(holder, false /* visible */); |
| |
| 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(mBarChartInfo.getTitle()); |
| } |
| |
| private void bindChartDetailsView(PreferenceViewHolder holder) { |
| final Button detailsView = (Button) holder.findViewById(R.id.bar_chart_details); |
| final int details = mBarChartInfo.getDetails(); |
| if (details == 0) { |
| detailsView.setVisibility(View.GONE); |
| } else { |
| detailsView.setVisibility(View.VISIBLE); |
| detailsView.setText(details); |
| detailsView.setOnClickListener(mBarChartInfo.getDetailsOnClickListener()); |
| } |
| } |
| |
| private void updateBarChart(PreferenceViewHolder holder) { |
| normalizeBarViewHeights(); |
| |
| final BarViewInfo[] barViewInfos = mBarChartInfo.getBarViewInfos(); |
| |
| for (int index = 0; index < MAXIMUM_BAR_VIEWS; index++) { |
| final BarView barView = (BarView) holder.findViewById(BAR_VIEWS[index]); |
| |
| // If there is no bar view info can be shown. |
| if (barViewInfos == null || index >= barViewInfos.length) { |
| barView.setVisibility(View.GONE); |
| continue; |
| } |
| barView.setVisibility(View.VISIBLE); |
| barView.updateView(barViewInfos[index]); |
| } |
| } |
| |
| private void normalizeBarViewHeights() { |
| final BarViewInfo[] barViewInfos = mBarChartInfo.getBarViewInfos(); |
| // If there is no any bar view info, we don't need to calculate the height of all bar views. |
| if (barViewInfos == null || barViewInfos.length == 0) { |
| return; |
| } |
| // Do a sort in descending order, the first element would have max {@link |
| // BarViewInfo#mHeight} |
| Arrays.sort(barViewInfos); |
| // Since we sorted this array in advance, the first element must have the max {@link |
| // BarViewInfo#mHeight}. |
| final int maxBarHeight = barViewInfos[0].getHeight(); |
| // If the max number of bar view is zero, then we don't calculate the unit for bar height. |
| final int unit = maxBarHeight == 0 ? 0 : mMaxBarHeight / maxBarHeight; |
| |
| for (BarViewInfo barView : barViewInfos) { |
| barView.setNormalizedHeight(barView.getHeight() * unit); |
| } |
| } |
| |
| private void setEmptyViewVisible(PreferenceViewHolder holder, boolean visible) { |
| final View barViewsContainer = holder.findViewById(R.id.bar_views_container); |
| final TextView emptyView = (TextView) holder.findViewById(R.id.empty_view); |
| final int emptyTextRes = mBarChartInfo.getEmptyText(); |
| |
| if (emptyTextRes != 0) { |
| emptyView.setText(emptyTextRes); |
| } |
| emptyView.setVisibility(visible ? View.VISIBLE : View.GONE); |
| barViewsContainer.setVisibility(visible ? View.GONE : View.VISIBLE); |
| } |
| } |