1 /* 2 * Copyright 2018 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 17 package androidx.car.widget; 18 19 import static java.lang.annotation.RetentionPolicy.SOURCE; 20 21 import android.car.drivingstate.CarUxRestrictions; 22 import android.content.Context; 23 import android.graphics.drawable.Drawable; 24 import android.text.TextUtils; 25 import android.view.View; 26 import android.view.ViewGroup; 27 import android.widget.ImageView; 28 import android.widget.LinearLayout; 29 import android.widget.RelativeLayout; 30 import android.widget.SeekBar; 31 import android.widget.TextView; 32 33 import androidx.annotation.DrawableRes; 34 import androidx.annotation.IntDef; 35 import androidx.annotation.Nullable; 36 import androidx.car.R; 37 import androidx.car.utils.CarUxRestrictionsUtils; 38 39 import java.lang.annotation.Retention; 40 import java.util.ArrayList; 41 import java.util.List; 42 43 /** 44 * Class to build a list item with {@link SeekBar}. 45 * 46 * <p>An item supports primary action and supplemental action(s). 47 * 48 * <p>An item visually composes of 3 parts; each part may contain multiple views. 49 * <ul> 50 * <li>{@code Primary Action}: represented by an icon of following types. 51 * <ul> 52 * <li>Primary Icon - icon size could be large or small. 53 * <li>No Icon - no icon is shown. 54 * <li>Empty Icon - {@code Seekbar} offsets start space as if there was an icon. 55 * </ul> 56 * <li>{@code Seekbar}: with optional {@code Text}. 57 * <li>{@code Supplemental Action}: presented by an icon of following types; aligned to 58 * the end of item. 59 * <ul> 60 * <li>Supplemental Icon. 61 * <li>Supplemental Empty Icon - {@code Seekbar} offsets end space as if there was an icon. 62 * </ul> 63 * </ul> 64 * 65 * {@code SeekbarListItem} binds data to {@link ViewHolder} based on components selected. 66 * 67 * <p>When conflicting methods are called (e.g. setting primary action to both primary icon and 68 * no icon), the last called method wins. 69 * 70 * {@code minimum value} is set to 0. 71 */ 72 public class SeekbarListItem extends ListItem<SeekbarListItem.ViewHolder> { 73 74 @Retention(SOURCE) 75 @IntDef({ 76 PRIMARY_ACTION_TYPE_NO_ICON, PRIMARY_ACTION_TYPE_EMPTY_ICON, 77 PRIMARY_ACTION_TYPE_SMALL_ICON}) 78 private @interface PrimaryActionType {} 79 80 private static final int PRIMARY_ACTION_TYPE_NO_ICON = 0; 81 private static final int PRIMARY_ACTION_TYPE_EMPTY_ICON = 1; 82 private static final int PRIMARY_ACTION_TYPE_SMALL_ICON = 2; 83 84 @Retention(SOURCE) 85 @IntDef({SUPPLEMENTAL_ACTION_NO_ACTION, SUPPLEMENTAL_ACTION_SUPPLEMENTAL_ICON, 86 SUPPLEMENTAL_ACTION_SUPPLEMENTAL_EMPTY_ICON, 87 SUPPLEMENTAL_ACTION_SUPPLEMENTAL_EMPTY_ICON_WITH_DIVIDER}) 88 private @interface SupplementalActionType {} 89 90 private static final int SUPPLEMENTAL_ACTION_NO_ACTION = 0; 91 private static final int SUPPLEMENTAL_ACTION_SUPPLEMENTAL_ICON = 1; 92 private static final int SUPPLEMENTAL_ACTION_SUPPLEMENTAL_EMPTY_ICON = 2; 93 private static final int SUPPLEMENTAL_ACTION_SUPPLEMENTAL_EMPTY_ICON_WITH_DIVIDER = 3; 94 95 private final Context mContext; 96 97 private final List<ViewBinder<ViewHolder>> mBinders = new ArrayList<>(); 98 99 @PrimaryActionType private int mPrimaryActionType = PRIMARY_ACTION_TYPE_NO_ICON; 100 private Drawable mPrimaryActionIconDrawable; 101 private View.OnClickListener mPrimaryActionIconOnClickListener; 102 103 private String mText; 104 105 private int mMax; 106 private int mProgress; 107 private int mSecondaryProgress; 108 private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener; 109 110 @SupplementalActionType private int mSupplementalActionType = SUPPLEMENTAL_ACTION_NO_ACTION; 111 private Drawable mSupplementalIconDrawable; 112 private View.OnClickListener mSupplementalIconOnClickListener; 113 private boolean mShowSupplementalIconDivider; 114 115 /** 116 * Creates a {@link SeekbarListItem.ViewHolder}. 117 */ 118 public static ViewHolder createViewHolder(View itemView) { 119 return new ViewHolder(itemView); 120 } 121 122 public SeekbarListItem(Context context) { 123 mContext = context; 124 markDirty(); 125 } 126 127 /** 128 * Used by {@link ListItemAdapter} to choose layout to inflate for view holder. 129 */ 130 @Override 131 public int getViewType() { 132 return ListItemAdapter.LIST_ITEM_TYPE_SEEKBAR; 133 } 134 135 /** 136 * Sets max value of seekbar. 137 */ 138 public void setMax(int max) { 139 mMax = max; 140 markDirty(); 141 } 142 143 /** 144 * Sets progress of seekbar. 145 */ 146 public void setProgress(int progress) { 147 mProgress = progress; 148 markDirty(); 149 } 150 151 /** 152 * Sets secondary progress of seekbar. 153 */ 154 public void setSecondaryProgress(int secondaryProgress) { 155 mSecondaryProgress = secondaryProgress; 156 markDirty(); 157 } 158 159 /** 160 * Sets {@link SeekBar.OnSeekBarChangeListener}. 161 */ 162 public void setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener listener) { 163 mOnSeekBarChangeListener = listener; 164 markDirty(); 165 } 166 167 /** 168 * Sets text that sits on top of seekbar. 169 */ 170 public void setText(String text) { 171 mText = text; 172 markDirty(); 173 } 174 175 /** 176 * Calculates the layout params for views in {@link ViewHolder}. 177 */ 178 @Override 179 protected void resolveDirtyState() { 180 mBinders.clear(); 181 182 // Create binders that adjust layout params of each view. 183 setItemLayoutHeight(); 184 setPrimaryAction(); 185 setSeekBarAndText(); 186 setSupplementalAction(); 187 } 188 189 /** 190 * Hides all views in {@link ViewHolder} then applies ViewBinders to adjust view layout params. 191 */ 192 @Override 193 protected void onBind(ViewHolder viewHolder) { 194 // Hide all subviews then apply view binders to adjust subviews. 195 hideSubViews(viewHolder); 196 for (ViewBinder binder : mBinders) { 197 binder.bind(viewHolder); 198 } 199 } 200 201 private void hideSubViews(ViewHolder vh) { 202 View[] subviews = new View[] { 203 vh.getPrimaryIcon(), 204 // SeekBar is always visible. 205 vh.getText(), 206 vh.getSupplementalIcon(), vh.getSupplementalIconDivider(), 207 }; 208 for (View v : subviews) { 209 v.setVisibility(View.GONE); 210 } 211 } 212 213 private void setItemLayoutHeight() { 214 int minHeight = mContext.getResources().getDimensionPixelSize( 215 R.dimen.car_single_line_list_item_height); 216 mBinders.add(vh -> { 217 vh.itemView.setMinimumHeight(minHeight); 218 vh.getContainerLayout().setMinimumHeight(minHeight); 219 220 ViewGroup.LayoutParams layoutParams = vh.itemView.getLayoutParams(); 221 layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; 222 vh.itemView.requestLayout(); 223 }); 224 } 225 226 private void setPrimaryAction() { 227 setPrimaryActionLayout(); 228 setPrimaryActionContent(); 229 } 230 231 private void setSeekBarAndText() { 232 setSeekBarAndTextContent(); 233 setSeekBarAndTextLayout(); 234 } 235 236 private void setSupplementalAction() { 237 setSupplementalActionLayout(); 238 setSupplementalActionContent(); 239 } 240 241 private void setPrimaryActionLayout() { 242 switch (mPrimaryActionType) { 243 case PRIMARY_ACTION_TYPE_NO_ICON: 244 case PRIMARY_ACTION_TYPE_EMPTY_ICON: 245 // Do nothing. 246 break; 247 case PRIMARY_ACTION_TYPE_SMALL_ICON: 248 int startMargin = mContext.getResources().getDimensionPixelSize( 249 R.dimen.car_keyline_1); 250 int iconSize = mContext.getResources().getDimensionPixelSize( 251 R.dimen.car_primary_icon_size); 252 mBinders.add(vh -> { 253 RelativeLayout.LayoutParams layoutParams = 254 (RelativeLayout.LayoutParams) vh.getPrimaryIcon().getLayoutParams(); 255 // Icon size. 256 layoutParams.height = layoutParams.width = iconSize; 257 // Start margin. 258 layoutParams.addRule(RelativeLayout.ALIGN_PARENT_START); 259 layoutParams.setMarginStart(startMargin); 260 261 if (!TextUtils.isEmpty(mText)) { 262 // Set icon top margin so that the icon remains in the same position it 263 // would've been in for non-long-text item, namely so that the center 264 // line of icon matches that of line item. 265 int itemHeight = mContext.getResources().getDimensionPixelSize( 266 R.dimen.car_double_line_list_item_height); 267 layoutParams.removeRule(RelativeLayout.CENTER_VERTICAL); 268 layoutParams.topMargin = (itemHeight - iconSize) / 2; 269 } else { 270 layoutParams.addRule(RelativeLayout.CENTER_VERTICAL); 271 layoutParams.topMargin = 0; 272 } 273 274 vh.getPrimaryIcon().requestLayout(); 275 }); 276 break; 277 default: 278 throw new IllegalStateException("Unknown primary action type."); 279 } 280 } 281 282 private void setPrimaryActionContent() { 283 switch (mPrimaryActionType) { 284 case PRIMARY_ACTION_TYPE_NO_ICON: 285 case PRIMARY_ACTION_TYPE_EMPTY_ICON: 286 // Do nothing. 287 break; 288 case PRIMARY_ACTION_TYPE_SMALL_ICON: 289 mBinders.add(vh -> { 290 vh.getPrimaryIcon().setVisibility(View.VISIBLE); 291 vh.getPrimaryIcon().setImageDrawable(mPrimaryActionIconDrawable); 292 vh.getPrimaryIcon().setOnClickListener( 293 mPrimaryActionIconOnClickListener); 294 vh.getPrimaryIcon().setClickable( 295 mPrimaryActionIconOnClickListener != null); 296 }); 297 break; 298 default: 299 throw new IllegalStateException("Unknown primary action type."); 300 } 301 } 302 303 private void setSeekBarAndTextContent() { 304 mBinders.add(vh -> { 305 vh.getSeekBar().setMax(mMax); 306 vh.getSeekBar().setProgress(mProgress); 307 vh.getSeekBar().setSecondaryProgress(mSecondaryProgress); 308 vh.getSeekBar().setOnSeekBarChangeListener(mOnSeekBarChangeListener); 309 310 if (!TextUtils.isEmpty(mText)) { 311 vh.getText().setVisibility(View.VISIBLE); 312 vh.getText().setText(mText); 313 vh.getText().setTextAppearance(getTitleTextAppearance()); 314 } 315 }); 316 } 317 318 private void setSeekBarAndTextLayout() { 319 mBinders.add(vh -> { 320 // SeekBar is below text with a gap. 321 ViewGroup.MarginLayoutParams seekBarLayoutParams = 322 (ViewGroup.MarginLayoutParams) vh.getSeekBar().getLayoutParams(); 323 seekBarLayoutParams.topMargin = TextUtils.isEmpty(mText) 324 ? 0 325 : mContext.getResources().getDimensionPixelSize(R.dimen.car_padding_1); 326 vh.getSeekBar().requestLayout(); 327 328 // Set start and end margin of text and seek bar. 329 setViewStartMargin(vh.getSeekBarContainer()); 330 setViewEndMargin(vh.getSeekBarContainer()); 331 332 RelativeLayout.LayoutParams containerLayoutParams = 333 (RelativeLayout.LayoutParams) vh.getSeekBarContainer().getLayoutParams(); 334 containerLayoutParams.addRule(RelativeLayout.CENTER_VERTICAL); 335 }); 336 } 337 338 // Helper method to set start margin of seekbar/text. 339 private void setViewStartMargin(View v) { 340 int startMarginResId; 341 switch (mPrimaryActionType) { 342 case PRIMARY_ACTION_TYPE_NO_ICON: 343 startMarginResId = R.dimen.car_keyline_1; 344 break; 345 case PRIMARY_ACTION_TYPE_EMPTY_ICON: 346 case PRIMARY_ACTION_TYPE_SMALL_ICON: 347 startMarginResId = R.dimen.car_keyline_3; 348 break; 349 default: 350 throw new IllegalStateException("Unknown primary action type."); 351 } 352 ViewGroup.MarginLayoutParams layoutParams = 353 (ViewGroup.MarginLayoutParams) v.getLayoutParams(); 354 layoutParams.setMarginStart( 355 mContext.getResources().getDimensionPixelSize(startMarginResId)); 356 v.requestLayout(); 357 } 358 359 // Helper method to set end margin of seekbar/text. 360 private void setViewEndMargin(View v) { 361 RelativeLayout.LayoutParams layoutParams = 362 (RelativeLayout.LayoutParams) v.getLayoutParams(); 363 int endMargin = 0; 364 switch (mSupplementalActionType) { 365 case SUPPLEMENTAL_ACTION_NO_ACTION: 366 // Aligned to parent end with margin. 367 layoutParams.addRule(RelativeLayout.ALIGN_PARENT_END); 368 layoutParams.removeRule(RelativeLayout.START_OF); 369 layoutParams.setMarginEnd(mContext.getResources().getDimensionPixelSize( 370 R.dimen.car_keyline_1)); 371 break; 372 case SUPPLEMENTAL_ACTION_SUPPLEMENTAL_ICON: 373 // Align to start of divider with padding. 374 layoutParams.addRule(RelativeLayout.START_OF, R.id.supplemental_icon_divider); 375 layoutParams.removeRule(RelativeLayout.ALIGN_PARENT_END); 376 layoutParams.setMarginEnd(mContext.getResources().getDimensionPixelSize( 377 R.dimen.car_padding_4)); 378 break; 379 case SUPPLEMENTAL_ACTION_SUPPLEMENTAL_EMPTY_ICON_WITH_DIVIDER: 380 // Align to parent end with a margin as if the icon and an optional divider were 381 // present. We do this by setting 382 383 // Add divider padding to icon, and width of divider. 384 endMargin += mContext.getResources().getDimensionPixelSize( 385 R.dimen.car_padding_4); 386 endMargin += mContext.getResources().getDimensionPixelSize( 387 R.dimen.car_vertical_line_divider_width); 388 // Fall through. 389 case SUPPLEMENTAL_ACTION_SUPPLEMENTAL_EMPTY_ICON: 390 // Add view padding, width of icon, and icon end margin. 391 endMargin += mContext.getResources().getDimensionPixelSize( 392 R.dimen.car_padding_4); 393 endMargin += mContext.getResources().getDimensionPixelSize( 394 R.dimen.car_primary_icon_size); 395 endMargin += mContext.getResources().getDimensionPixelSize( 396 R.dimen.car_keyline_1); 397 398 layoutParams.addRule(RelativeLayout.ALIGN_PARENT_END); 399 layoutParams.removeRule(RelativeLayout.START_OF); 400 layoutParams.setMarginEnd(endMargin); 401 break; 402 default: 403 throw new IllegalStateException("Unknown supplemental action type."); 404 } 405 v.requestLayout(); 406 } 407 408 private void setSupplementalActionLayout() { 409 int keyline1 = mContext.getResources().getDimensionPixelSize(R.dimen.car_keyline_1); 410 int padding4 = mContext.getResources().getDimensionPixelSize(R.dimen.car_padding_4); 411 mBinders.add(vh -> { 412 RelativeLayout.LayoutParams iconLayoutParams = 413 (RelativeLayout.LayoutParams) vh.getSupplementalIcon().getLayoutParams(); 414 // Align to parent end with margin. 415 iconLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_END); 416 iconLayoutParams.setMarginEnd(keyline1); 417 iconLayoutParams.addRule(RelativeLayout.CENTER_VERTICAL); 418 419 vh.getSupplementalIcon().requestLayout(); 420 421 // Divider aligns to the start of supplemental icon with margin. 422 RelativeLayout.LayoutParams dividerLayoutParams = 423 (RelativeLayout.LayoutParams) vh.getSupplementalIconDivider() 424 .getLayoutParams(); 425 dividerLayoutParams.addRule(RelativeLayout.START_OF, R.id.supplemental_icon); 426 dividerLayoutParams.setMarginEnd(padding4); 427 dividerLayoutParams.addRule(RelativeLayout.CENTER_VERTICAL); 428 429 vh.getSupplementalIconDivider().requestLayout(); 430 }); 431 } 432 433 private void setSupplementalActionContent() { 434 switch (mSupplementalActionType) { 435 case SUPPLEMENTAL_ACTION_NO_ACTION: 436 case SUPPLEMENTAL_ACTION_SUPPLEMENTAL_EMPTY_ICON_WITH_DIVIDER: 437 case SUPPLEMENTAL_ACTION_SUPPLEMENTAL_EMPTY_ICON: 438 break; 439 case SUPPLEMENTAL_ACTION_SUPPLEMENTAL_ICON: 440 mBinders.add(vh -> { 441 vh.getSupplementalIcon().setVisibility(View.VISIBLE); 442 if (mShowSupplementalIconDivider) { 443 vh.getSupplementalIconDivider().setVisibility(View.VISIBLE); 444 } 445 446 vh.getSupplementalIcon().setImageDrawable(mSupplementalIconDrawable); 447 448 vh.getSupplementalIcon().setOnClickListener( 449 mSupplementalIconOnClickListener); 450 vh.getSupplementalIcon().setClickable( 451 mSupplementalIconOnClickListener != null); 452 }); 453 break; 454 default: 455 throw new IllegalStateException("Unknown supplemental action type."); 456 } 457 } 458 459 /** 460 * Sets {@code Primary Action} to be represented by an icon. 461 * 462 * @param iconResId the resource identifier of the drawable. 463 */ 464 public void setPrimaryActionIcon(@DrawableRes int iconResId) { 465 setPrimaryActionIcon(mContext.getDrawable(iconResId)); 466 } 467 468 /** 469 * Sets {@code Primary Action} to be represented by an icon. 470 * 471 * @param drawable the Drawable to set, or null to clear the content. 472 */ 473 public void setPrimaryActionIcon(Drawable drawable) { 474 mPrimaryActionType = PRIMARY_ACTION_TYPE_SMALL_ICON; 475 mPrimaryActionIconDrawable = drawable; 476 markDirty(); 477 } 478 479 /** 480 * Sets an {@code OnClickListener} for the icon representing the {@code Primary Action}. 481 * 482 * @param onClickListener the listener to be set for the primary action icon. 483 */ 484 public void setPrimaryActionIconListener(View.OnClickListener onClickListener) { 485 mPrimaryActionIconOnClickListener = onClickListener; 486 markDirty(); 487 } 488 489 /** 490 * Sets {@code Primary Action} to be empty icon. 491 * 492 * {@code Seekbar} would have a start margin as if {@code Primary Action} were set as icon. 493 */ 494 public void setPrimaryActionEmptyIcon() { 495 mPrimaryActionType = PRIMARY_ACTION_TYPE_EMPTY_ICON; 496 497 markDirty(); 498 } 499 500 /** 501 * Sets {@code Supplemental Action} to be represented by an {@code Supplemental Icon}. 502 */ 503 public void setSupplementalIcon(@DrawableRes int iconResId, 504 boolean showSupplementalIconDivider) { 505 setSupplementalIconInfo(mContext.getDrawable(iconResId), showSupplementalIconDivider); 506 } 507 508 /** 509 * Sets {@code Supplemental Action} to be represented by an {@code Supplemental Icon}. 510 */ 511 public void setSupplementalIcon(Drawable drawable, boolean showSupplementalIconDivider) { 512 setSupplementalIconInfo(drawable, showSupplementalIconDivider); 513 } 514 515 /** 516 * Sets {@code OnClickListener} for a {@code Supplemental Icon}. 517 */ 518 public void setSupplementalIconListener(View.OnClickListener listener) { 519 mSupplementalIconOnClickListener = listener; 520 521 markDirty(); 522 } 523 524 private void setSupplementalIconInfo(Drawable drawable, boolean showSupplementalIconDivider) { 525 mSupplementalActionType = SUPPLEMENTAL_ACTION_SUPPLEMENTAL_ICON; 526 527 mSupplementalIconDrawable = drawable; 528 mShowSupplementalIconDivider = showSupplementalIconDivider; 529 530 markDirty(); 531 } 532 533 /** 534 * Sets {@code Supplemental Action} to be represented by an {@code Supplemental Icon}. 535 * 536 * @deprecated use either {@link #setSupplementalIcon(Drawable, boolean)} or 537 * {@link #setSupplementalIcon(int, boolean)} and 538 * {@link #setSupplementalIconListener(android.view.View.OnClickListener)}. 539 */ 540 @Deprecated 541 public void setSupplementalIcon(Drawable drawable, boolean showSupplementalIconDivider, 542 @Nullable View.OnClickListener listener) { 543 mSupplementalActionType = SUPPLEMENTAL_ACTION_SUPPLEMENTAL_ICON; 544 545 mSupplementalIconDrawable = drawable; 546 mShowSupplementalIconDivider = showSupplementalIconDivider; 547 mSupplementalIconOnClickListener = listener; 548 549 markDirty(); 550 } 551 552 /** 553 * Sets {@code Supplemental Action} to be empty icon. 554 * 555 * {@code Seekbar} would have an end margin as if {@code Supplemental Action} were set. 556 */ 557 public void setSupplementalEmptyIcon(boolean seekbarOffsetDividerWidth) { 558 mSupplementalActionType = seekbarOffsetDividerWidth 559 ? SUPPLEMENTAL_ACTION_SUPPLEMENTAL_EMPTY_ICON_WITH_DIVIDER 560 : SUPPLEMENTAL_ACTION_SUPPLEMENTAL_EMPTY_ICON; 561 markDirty(); 562 } 563 564 /** 565 * Holds views of SeekbarListItem. 566 */ 567 public static class ViewHolder extends ListItem.ViewHolder { 568 569 private RelativeLayout mContainerLayout; 570 571 private ImageView mPrimaryIcon; 572 573 private LinearLayout mSeekBarContainer; 574 private TextView mText; 575 private SeekBar mSeekBar; 576 577 private View mSupplementalIconDivider; 578 private ImageView mSupplementalIcon; 579 580 public ViewHolder(View itemView) { 581 super(itemView); 582 583 mContainerLayout = itemView.findViewById(R.id.container); 584 585 mPrimaryIcon = itemView.findViewById(R.id.primary_icon); 586 587 mSeekBarContainer = itemView.findViewById(R.id.seek_bar_container); 588 mText = itemView.findViewById(R.id.text); 589 mSeekBar = itemView.findViewById(R.id.seek_bar); 590 591 mSupplementalIcon = itemView.findViewById(R.id.supplemental_icon); 592 mSupplementalIconDivider = itemView.findViewById(R.id.supplemental_icon_divider); 593 594 int minTouchSize = itemView.getContext().getResources() 595 .getDimensionPixelSize(R.dimen.car_touch_target_size); 596 597 MinTouchTargetHelper.ensureThat(mSupplementalIcon) 598 .hasMinTouchSize(minTouchSize); 599 } 600 601 @Override 602 protected void complyWithUxRestrictions(CarUxRestrictions restrictions) { 603 CarUxRestrictionsUtils.comply(itemView.getContext(), restrictions, getText()); 604 } 605 606 public RelativeLayout getContainerLayout() { 607 return mContainerLayout; 608 } 609 610 public ImageView getPrimaryIcon() { 611 return mPrimaryIcon; 612 } 613 614 public LinearLayout getSeekBarContainer() { 615 return mSeekBarContainer; 616 } 617 618 public TextView getText() { 619 return mText; 620 } 621 622 public SeekBar getSeekBar() { 623 return mSeekBar; 624 } 625 626 public ImageView getSupplementalIcon() { 627 return mSupplementalIcon; 628 } 629 630 public View getSupplementalIconDivider() { 631 return mSupplementalIconDivider; 632 } 633 } 634 } 635