blob: 6300bd3b318e7a6b9eaad210802451952aab7860 [file] [log] [blame]
Edgar Wangcdff5c62021-06-08 09:10:41 +00001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings.widget;
18
19import android.content.Context;
20import android.content.res.TypedArray;
21import android.graphics.drawable.Drawable;
22import android.util.AttributeSet;
Govinda Wasserman3869aac2021-08-20 17:06:40 +000023import android.view.View;
Peter_Liangcc5808c2022-01-19 21:41:17 +080024import android.view.ViewGroup;
25import android.widget.ImageView;
Edgar Wangcdff5c62021-06-08 09:10:41 +000026import android.widget.SeekBar;
27import android.widget.TextView;
28
29import androidx.core.content.res.TypedArrayUtils;
30import androidx.preference.PreferenceViewHolder;
31
Peter_Liangcc5808c2022-01-19 21:41:17 +080032import com.android.internal.util.Preconditions;
Edgar Wangcdff5c62021-06-08 09:10:41 +000033import com.android.settings.R;
Edgar Wang2b0d9cf2022-05-19 09:20:30 +080034import com.android.settings.Utils;
Edgar Wangcdff5c62021-06-08 09:10:41 +000035
Peter_Liangcc5808c2022-01-19 21:41:17 +080036/**
37 * A labeled {@link SeekBarPreference} with left and right text label, icon label, or both.
38 *
39 * <p>
40 * The component provides the attribute usage below.
41 * <attr name="textStart" format="reference" />
42 * <attr name="textEnd" format="reference" />
43 * <attr name="tickMark" format="reference" />
44 * <attr name="iconStart" format="reference" />
45 * <attr name="iconEnd" format="reference" />
46 * <attr name="iconStartContentDescription" format="reference" />
47 * <attr name="iconEndContentDescription" format="reference" />
48 * </p>
49 *
50 * <p> If you set the attribute values {@code iconStartContentDescription} or {@code
51 * iconEndContentDescription} from XML, you must also set the corresponding attributes {@code
52 * iconStart} or {@code iconEnd}, otherwise throws an {@link IllegalArgumentException}.</p>
53 */
Edgar Wangcdff5c62021-06-08 09:10:41 +000054public class LabeledSeekBarPreference extends SeekBarPreference {
55
56 private final int mTextStartId;
57 private final int mTextEndId;
58 private final int mTickMarkId;
Peter_Liangcc5808c2022-01-19 21:41:17 +080059 private final int mIconStartId;
60 private final int mIconEndId;
61 private final int mIconStartContentDescriptionId;
62 private final int mIconEndContentDescriptionId;
Edgar Wangcdff5c62021-06-08 09:10:41 +000063 private OnPreferenceChangeListener mStopListener;
Peter_Liangcc5808c2022-01-19 21:41:17 +080064 private SeekBar.OnSeekBarChangeListener mSeekBarChangeListener;
Edgar Wangcdff5c62021-06-08 09:10:41 +000065
Candice Lob132ada2023-03-20 08:17:26 +000066 private SeekBar mSeekBar;
67
Edgar Wangcdff5c62021-06-08 09:10:41 +000068 public LabeledSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr,
69 int defStyleRes) {
70
71 super(context, attrs, defStyleAttr, defStyleRes);
72 setLayoutResource(R.layout.preference_labeled_slider);
73
74 final TypedArray styledAttrs = context.obtainStyledAttributes(attrs,
75 R.styleable.LabeledSeekBarPreference);
76 mTextStartId = styledAttrs.getResourceId(
Peter_Liang88d63ea2022-01-20 01:32:58 +080077 R.styleable.LabeledSeekBarPreference_textStart, /* defValue= */ 0);
Edgar Wangcdff5c62021-06-08 09:10:41 +000078 mTextEndId = styledAttrs.getResourceId(
Peter_Liang88d63ea2022-01-20 01:32:58 +080079 R.styleable.LabeledSeekBarPreference_textEnd, /* defValue= */ 0);
Edgar Wangcdff5c62021-06-08 09:10:41 +000080 mTickMarkId = styledAttrs.getResourceId(
81 R.styleable.LabeledSeekBarPreference_tickMark, /* defValue= */ 0);
Peter_Liangcc5808c2022-01-19 21:41:17 +080082 mIconStartId = styledAttrs.getResourceId(
83 R.styleable.LabeledSeekBarPreference_iconStart, /* defValue= */ 0);
84 mIconEndId = styledAttrs.getResourceId(
85 R.styleable.LabeledSeekBarPreference_iconEnd, /* defValue= */ 0);
86
87 mIconStartContentDescriptionId = styledAttrs.getResourceId(
88 R.styleable.LabeledSeekBarPreference_iconStartContentDescription,
89 /* defValue= */ 0);
90 Preconditions.checkArgument(!(mIconStartContentDescriptionId != 0 && mIconStartId == 0),
91 "The resource of the iconStart attribute may be invalid or not set, "
92 + "you should set the iconStart attribute and have the valid resource.");
93
94 mIconEndContentDescriptionId = styledAttrs.getResourceId(
95 R.styleable.LabeledSeekBarPreference_iconEndContentDescription,
96 /* defValue= */ 0);
97 Preconditions.checkArgument(!(mIconEndContentDescriptionId != 0 && mIconEndId == 0),
98 "The resource of the iconEnd attribute may be invalid or not set, "
99 + "you should set the iconEnd attribute and have the valid resource.");
Edgar Wangcdff5c62021-06-08 09:10:41 +0000100 styledAttrs.recycle();
101 }
102
103 public LabeledSeekBarPreference(Context context, AttributeSet attrs) {
104 this(context, attrs, TypedArrayUtils.getAttr(context,
105 androidx.preference.R.attr.seekBarPreferenceStyle,
106 com.android.internal.R.attr.seekBarPreferenceStyle), 0);
107 }
108
Candice Lob132ada2023-03-20 08:17:26 +0000109 public SeekBar getSeekbar() {
110 return mSeekBar;
111 }
112
Edgar Wangcdff5c62021-06-08 09:10:41 +0000113 @Override
114 public void onBindViewHolder(PreferenceViewHolder holder) {
115 super.onBindViewHolder(holder);
116
Edgar Wang2b0d9cf2022-05-19 09:20:30 +0800117 final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
118 boolean isSummaryVisible = false;
119 if (summaryView != null) {
120 isSummaryVisible = (summaryView.getVisibility() == View.VISIBLE);
121 }
122 final TextView titleView = (TextView) holder.findViewById(android.R.id.title);
123 if (titleView != null && !isSelectable() && isEnabled() && isSummaryVisible) {
124 titleView.setTextColor(
125 Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary));
126 }
127
Edgar Wangcdff5c62021-06-08 09:10:41 +0000128 final TextView startText = (TextView) holder.findViewById(android.R.id.text1);
Peter_Liang88d63ea2022-01-20 01:32:58 +0800129 if (mTextStartId > 0) {
130 startText.setText(mTextStartId);
131 }
132
Edgar Wangcdff5c62021-06-08 09:10:41 +0000133 final TextView endText = (TextView) holder.findViewById(android.R.id.text2);
Peter_Liang88d63ea2022-01-20 01:32:58 +0800134 if (mTextEndId > 0) {
135 endText.setText(mTextEndId);
136 }
137
138 final View labelFrame = holder.findViewById(R.id.label_frame);
139 final boolean isValidTextResIdExist = mTextStartId > 0 || mTextEndId > 0;
140 labelFrame.setVisibility(isValidTextResIdExist ? View.VISIBLE : View.GONE);
Edgar Wangcdff5c62021-06-08 09:10:41 +0000141
Candice Lob132ada2023-03-20 08:17:26 +0000142 mSeekBar = (SeekBar) holder.findViewById(com.android.internal.R.id.seekbar);
Edgar Wangcdff5c62021-06-08 09:10:41 +0000143 if (mTickMarkId != 0) {
144 final Drawable tickMark = getContext().getDrawable(mTickMarkId);
Candice Lob132ada2023-03-20 08:17:26 +0000145 mSeekBar.setTickMark(tickMark);
Edgar Wangcdff5c62021-06-08 09:10:41 +0000146 }
Govinda Wasserman3869aac2021-08-20 17:06:40 +0000147
Peter_Liangcc5808c2022-01-19 21:41:17 +0800148 final ViewGroup iconStartFrame = (ViewGroup) holder.findViewById(R.id.icon_start_frame);
149 final ImageView iconStartView = (ImageView) holder.findViewById(R.id.icon_start);
Candice Lob132ada2023-03-20 08:17:26 +0000150 updateIconStartIfNeeded(iconStartFrame, iconStartView, mSeekBar);
Peter_Liangcc5808c2022-01-19 21:41:17 +0800151
152 final ViewGroup iconEndFrame = (ViewGroup) holder.findViewById(R.id.icon_end_frame);
153 final ImageView iconEndView = (ImageView) holder.findViewById(R.id.icon_end);
Candice Lob132ada2023-03-20 08:17:26 +0000154 updateIconEndIfNeeded(iconEndFrame, iconEndView, mSeekBar);
Edgar Wangcdff5c62021-06-08 09:10:41 +0000155 }
156
157 public void setOnPreferenceChangeStopListener(OnPreferenceChangeListener listener) {
158 mStopListener = listener;
159 }
160
161 @Override
Peter_Liangcc5808c2022-01-19 21:41:17 +0800162 public void onStartTrackingTouch(SeekBar seekBar) {
163 super.onStartTrackingTouch(seekBar);
164
165 if (mSeekBarChangeListener != null) {
166 mSeekBarChangeListener.onStartTrackingTouch(seekBar);
167 }
168 }
169
170 @Override
171 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
172 super.onProgressChanged(seekBar, progress, fromUser);
173
174 if (mSeekBarChangeListener != null) {
175 mSeekBarChangeListener.onProgressChanged(seekBar, progress, fromUser);
176 }
177 }
178
179 @Override
Edgar Wangcdff5c62021-06-08 09:10:41 +0000180 public void onStopTrackingTouch(SeekBar seekBar) {
181 super.onStopTrackingTouch(seekBar);
182
Peter_Liangcc5808c2022-01-19 21:41:17 +0800183 if (mSeekBarChangeListener != null) {
184 mSeekBarChangeListener.onStopTrackingTouch(seekBar);
185 }
186
Edgar Wangcdff5c62021-06-08 09:10:41 +0000187 if (mStopListener != null) {
188 mStopListener.onPreferenceChange(this, seekBar.getProgress());
189 }
Peter_Liangcc5808c2022-01-19 21:41:17 +0800190
191 // Need to update the icon enabled status
192 notifyChanged();
Edgar Wangcdff5c62021-06-08 09:10:41 +0000193 }
Govinda Wasserman3869aac2021-08-20 17:06:40 +0000194
Peter_Liangcc5808c2022-01-19 21:41:17 +0800195 public void setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener seekBarChangeListener) {
196 mSeekBarChangeListener = seekBarChangeListener;
197 }
198
199 private void updateIconStartIfNeeded(ViewGroup iconFrame, ImageView iconStart,
200 SeekBar seekBar) {
201 if (mIconStartId == 0) {
202 return;
203 }
204
205 if (iconStart.getDrawable() == null) {
206 iconStart.setImageResource(mIconStartId);
207 }
208
209 if (mIconStartContentDescriptionId != 0) {
210 final String contentDescription =
211 iconFrame.getContext().getString(mIconStartContentDescriptionId);
212 iconFrame.setContentDescription(contentDescription);
213 }
214
215 iconFrame.setOnClickListener((view) -> {
216 final int progress = getProgress();
217 if (progress > 0) {
218 setProgress(progress - 1);
219 }
220 });
221
222 iconFrame.setVisibility(View.VISIBLE);
223 setIconViewAndFrameEnabled(iconStart, seekBar.getProgress() > 0);
224 }
225
226 private void updateIconEndIfNeeded(ViewGroup iconFrame, ImageView iconEnd, SeekBar seekBar) {
227 if (mIconEndId == 0) {
228 return;
229 }
230
231 if (iconEnd.getDrawable() == null) {
232 iconEnd.setImageResource(mIconEndId);
233 }
234
235 if (mIconEndContentDescriptionId != 0) {
236 final String contentDescription =
237 iconFrame.getContext().getString(mIconEndContentDescriptionId);
238 iconFrame.setContentDescription(contentDescription);
239 }
240
241 iconFrame.setOnClickListener((view) -> {
242 final int progress = getProgress();
243 if (progress < getMax()) {
244 setProgress(progress + 1);
245 }
246 });
247
248 iconFrame.setVisibility(View.VISIBLE);
249 setIconViewAndFrameEnabled(iconEnd, seekBar.getProgress() < seekBar.getMax());
250 }
251
252 private static void setIconViewAndFrameEnabled(View iconView, boolean enabled) {
253 iconView.setEnabled(enabled);
254 final ViewGroup iconFrame = (ViewGroup) iconView.getParent();
255 iconFrame.setEnabled(enabled);
256 }
Edgar Wangcdff5c62021-06-08 09:10:41 +0000257}
258