/* * 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. */ package com.android.settingslib.widget; import android.content.Context; import android.text.SpannableString; import android.text.Spanned; import android.text.TextUtils; import android.text.style.AbsoluteSizeSpan; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Progres bar preference with a usage summary and a total summary. * This preference shows number in usage summary with enlarged font size. */ public class UsageProgressBarPreference extends Preference { private final Pattern mNumberPattern = Pattern.compile("[\\d]*[\\٫.,]?[\\d]+"); private CharSequence mUsageSummary; private CharSequence mTotalSummary; private CharSequence mBottomSummary; private ImageView mCustomImageView; private int mPercent = -1; /** * Perform inflation from XML and apply a class-specific base style. * * @param context The {@link Context} this is associated with, through which it can * access the current theme, resources, {@link SharedPreferences}, etc. * @param attrs The attributes of the XML tag that is inflating the preference * @param defStyle 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 UsageProgressBarPreference(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setLayoutResource(R.layout.preference_usage_progress_bar); } /** * Perform inflation from XML and apply a class-specific base style. * * @param context The {@link Context} this is associated with, through which it can * access the current theme, resources, {@link SharedPreferences}, etc. * @param attrs The attributes of the XML tag that is inflating the preference */ public UsageProgressBarPreference(Context context, AttributeSet attrs) { super(context, attrs); setLayoutResource(R.layout.preference_usage_progress_bar); } /** * Constructor to create a preference. * * @param context The Context this is associated with. */ public UsageProgressBarPreference(Context context) { this(context, null); } /** Set usage summary, number in the summary will show with enlarged font size. */ public void setUsageSummary(CharSequence usageSummary) { if (TextUtils.equals(mUsageSummary, usageSummary)) { return; } mUsageSummary = usageSummary; notifyChanged(); } /** Set total summary. */ public void setTotalSummary(CharSequence totalSummary) { if (TextUtils.equals(mTotalSummary, totalSummary)) { return; } mTotalSummary = totalSummary; notifyChanged(); } /** Set bottom summary. */ public void setBottomSummary(CharSequence bottomSummary) { if (TextUtils.equals(mBottomSummary, bottomSummary)) { return; } mBottomSummary = bottomSummary; notifyChanged(); } /** Set percentage of the progress bar. */ public void setPercent(long usage, long total) { if (usage > total) { return; } if (total == 0L) { if (mPercent != 0) { mPercent = 0; notifyChanged(); } return; } final int percent = (int) (usage / (double) total * 100); if (mPercent == percent) { return; } mPercent = percent; notifyChanged(); } /** Set custom ImageView to the right side of total summary. */ public void setCustomContent(T imageView) { if (imageView == mCustomImageView) { return; } mCustomImageView = imageView; notifyChanged(); } /** * Binds the created View to the data for this preference. * *

This is a good place to grab references to custom Views in the layout and set * properties on them. * *

Make sure to call through to the superclass's implementation. * * @param holder The ViewHolder that provides references to the views to fill in. These views * will be recycled, so you should not hold a reference to them after this method * returns. */ @Override public void onBindViewHolder(PreferenceViewHolder holder) { super.onBindViewHolder(holder); holder.setDividerAllowedAbove(false); holder.setDividerAllowedBelow(false); final TextView usageSummary = (TextView) holder.findViewById(R.id.usage_summary); usageSummary.setText(enlargeFontOfNumber(mUsageSummary)); final TextView totalSummary = (TextView) holder.findViewById(R.id.total_summary); if (mTotalSummary != null) { totalSummary.setText(mTotalSummary); } final TextView bottomSummary = (TextView) holder.findViewById(R.id.bottom_summary); if (TextUtils.isEmpty(mBottomSummary)) { bottomSummary.setVisibility(View.GONE); } else { bottomSummary.setVisibility(View.VISIBLE); bottomSummary.setText(mBottomSummary); } final ProgressBar progressBar = (ProgressBar) holder.findViewById(android.R.id.progress); if (mPercent < 0) { progressBar.setIndeterminate(true); } else { progressBar.setIndeterminate(false); progressBar.setProgress(mPercent); } final FrameLayout customLayout = (FrameLayout) holder.findViewById(R.id.custom_content); if (mCustomImageView == null) { customLayout.removeAllViews(); customLayout.setVisibility(View.GONE); } else { customLayout.removeAllViews(); customLayout.addView(mCustomImageView); customLayout.setVisibility(View.VISIBLE); } } private CharSequence enlargeFontOfNumber(CharSequence summary) { if (TextUtils.isEmpty(summary)) { return ""; } final Matcher matcher = mNumberPattern.matcher(summary); if (matcher.find()) { final SpannableString spannableSummary = new SpannableString(summary); spannableSummary.setSpan(new AbsoluteSizeSpan(64, true /* dip */), matcher.start(), matcher.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); return spannableSummary; } return summary; } }