• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright 2013 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 
18 
19 
20 package com.example.android.batchstepsensor.cardstream;
21 
22 import android.animation.Animator;
23 import android.animation.AnimatorListenerAdapter;
24 import android.animation.ObjectAnimator;
25 import android.app.Activity;
26 import android.graphics.Color;
27 import android.view.LayoutInflater;
28 import android.view.View;
29 import android.view.ViewGroup;
30 import android.widget.Button;
31 import android.widget.ProgressBar;
32 import android.widget.TextView;
33 
34 import com.example.android.batchstepsensor.R;
35 
36 import java.util.ArrayList;
37 
38 /**
39  * A Card contains a description and has a visual state. Optionally a card also contains a title,
40  * progress indicator and zero or more actions. It is constructed through the {@link Builder}.
41  */
42 public class Card {
43 
44     public static final int ACTION_POSITIVE = 1;
45     public static final int ACTION_NEGATIVE = 2;
46     public static final int ACTION_NEUTRAL = 3;
47 
48     public static final int PROGRESS_TYPE_NO_PROGRESS = 0;
49     public static final int PROGRESS_TYPE_NORMAL = 1;
50     public static final int PROGRESS_TYPE_INDETERMINATE = 2;
51     public static final int PROGRESS_TYPE_LABEL = 3;
52 
53     private OnCardClickListener mClickListener;
54 
55 
56     // The card model contains a reference to its desired layout (for extensibility), title,
57     // description, zero to many action buttons, and zero or 1 progress indicators.
58     private int mLayoutId = R.layout.card;
59 
60     /**
61      * Tag that uniquely identifies this card.
62      */
63     private String mTag = null;
64 
65     private String mTitle = null;
66     private String mDescription = null;
67 
68     private View mCardView = null;
69     private View mOverlayView = null;
70     private TextView mTitleView = null;
71     private TextView mDescView = null;
72     private View mActionAreaView = null;
73 
74     private Animator mOngoingAnimator = null;
75 
76     /**
77      * Visual state, either {@link #CARD_STATE_NORMAL}, {@link #CARD_STATE_FOCUSED} or
78      * {@link #CARD_STATE_INACTIVE}.
79      */
80     private int mCardState = CARD_STATE_NORMAL;
81     public static final int CARD_STATE_NORMAL = 1;
82     public static final int CARD_STATE_FOCUSED = 2;
83     public static final int CARD_STATE_INACTIVE = 3;
84 
85     /**
86      * Represent actions that can be taken from the card.  Stylistically the developer can
87      * designate the action as positive, negative (ok/cancel, for instance), or neutral.
88      * This "type" can be used as a UI hint.
89      * @see com.example.android.sensors.batchstepsensor.Card.CardAction
90      */
91     private ArrayList<CardAction> mCardActions = new ArrayList<CardAction>();
92 
93     /**
94      * Some cards will have a sense of "progress" which should be associated with, but separated
95      * from its "parent" card.  To push for simplicity in samples, Cards are designed to have
96      * a maximum of one progress indicator per Card.
97      */
98     private CardProgress mCardProgress = null;
99 
Card()100     public Card() {
101     }
102 
getTag()103     public String getTag() {
104         return mTag;
105     }
106 
getView()107     public View getView() {
108         return mCardView;
109     }
110 
111 
setDescription(String desc)112     public Card setDescription(String desc) {
113         if (mDescView != null) {
114             mDescription = desc;
115             mDescView.setText(desc);
116         }
117         return this;
118     }
119 
setTitle(String title)120     public Card setTitle(String title) {
121         if (mTitleView != null) {
122             mTitle = title;
123             mTitleView.setText(title);
124         }
125         return this;
126     }
127 
128 
129     /**
130      * Return the UI state, either {@link #CARD_STATE_NORMAL}, {@link #CARD_STATE_FOCUSED}
131      * or {@link #CARD_STATE_INACTIVE}.
132      */
getState()133     public int getState() {
134         return mCardState;
135     }
136 
137     /**
138      * Set the UI state. The parameter describes the state and must be either
139      * {@link #CARD_STATE_NORMAL}, {@link #CARD_STATE_FOCUSED} or {@link #CARD_STATE_INACTIVE}.
140      * Note: This method must be called from the UI Thread.
141      * @param state
142      * @return The card itself, allows for chaining of calls
143      */
setState(int state)144     public Card setState(int state) {
145         mCardState = state;
146         if (null != mOverlayView) {
147             if (null != mOngoingAnimator) {
148                 mOngoingAnimator.end();
149                 mOngoingAnimator = null;
150             }
151             switch (state) {
152                 case CARD_STATE_NORMAL: {
153                     mOverlayView.setVisibility(View.GONE);
154                     mOverlayView.setAlpha(1.f);
155                     break;
156                 }
157                 case CARD_STATE_FOCUSED: {
158                     mOverlayView.setVisibility(View.VISIBLE);
159                     mOverlayView.setBackgroundResource(R.drawable.card_overlay_focused);
160                     ObjectAnimator animator = ObjectAnimator.ofFloat(mOverlayView, "alpha", 0.f);
161                     animator.setRepeatMode(ObjectAnimator.REVERSE);
162                     animator.setRepeatCount(ObjectAnimator.INFINITE);
163                     animator.setDuration(1000);
164                     animator.start();
165                     mOngoingAnimator = animator;
166                     break;
167                 }
168                 case CARD_STATE_INACTIVE: {
169                     mOverlayView.setVisibility(View.VISIBLE);
170                     mOverlayView.setAlpha(1.f);
171                     mOverlayView.setBackgroundColor(Color.argb(0xaa, 0xcc, 0xcc, 0xcc));
172                     break;
173                 }
174             }
175         }
176         return this;
177     }
178 
179     /**
180      * Set the type of progress indicator.
181      * The progress type can only be changed if the Card was initially build with a progress
182      * indicator.
183      * See {@link Builder#setProgressType(int)}.
184      * Must be a value of either {@link #PROGRESS_TYPE_NORMAL},
185      * {@link #PROGRESS_TYPE_INDETERMINATE}, {@link #PROGRESS_TYPE_LABEL} or
186      * {@link #PROGRESS_TYPE_NO_PROGRESS}.
187      * @param progressType
188      * @return The card itself, allows for chaining of calls
189      */
setProgressType(int progressType)190     public Card setProgressType(int progressType) {
191         if (mCardProgress == null) {
192             mCardProgress = new CardProgress();
193         }
194         mCardProgress.setProgressType(progressType);
195         return this;
196     }
197 
198     /**
199      * Return the progress indicator type. A value of either {@link #PROGRESS_TYPE_NORMAL},
200      * {@link #PROGRESS_TYPE_INDETERMINATE}, {@link #PROGRESS_TYPE_LABEL}. Otherwise if no progress
201      * indicator is enabled, {@link #PROGRESS_TYPE_NO_PROGRESS} is returned.
202      * @return
203      */
getProgressType()204     public int getProgressType() {
205         if (mCardProgress == null) {
206             return PROGRESS_TYPE_NO_PROGRESS;
207         }
208         return mCardProgress.progressType;
209     }
210 
211     /**
212      * Set the progress to the specified value. Only applicable if the card has a
213      * {@link #PROGRESS_TYPE_NORMAL} progress type.
214      * @param progress
215      * @return
216      * @see #setMaxProgress(int)
217      */
setProgress(int progress)218     public Card setProgress(int progress) {
219         if (mCardProgress != null) {
220             mCardProgress.setProgress(progress);
221         }
222         return this;
223     }
224 
225     /**
226      * Set the range of the progress to 0...max. Only applicable if the card has a
227      * {@link #PROGRESS_TYPE_NORMAL} progress type.
228      * @return
229      */
setMaxProgress(int max)230     public Card setMaxProgress(int max){
231         if (mCardProgress != null) {
232             mCardProgress.setMax(max);
233         }
234         return this;
235     }
236 
237     /**
238      * Set the label text for the progress if the card has a progress type of
239      * {@link #PROGRESS_TYPE_NORMAL}, {@link #PROGRESS_TYPE_INDETERMINATE} or
240      * {@link #PROGRESS_TYPE_LABEL}
241      * @param text
242      * @return
243      */
setProgressLabel(String text)244     public Card setProgressLabel(String text) {
245         if (mCardProgress != null) {
246             mCardProgress.setProgressLabel(text);
247         }
248         return this;
249     }
250 
251     /**
252      * Toggle the visibility of the progress section of the card. Only applicable if
253      * the card has a progress type of
254      * {@link #PROGRESS_TYPE_NORMAL}, {@link #PROGRESS_TYPE_INDETERMINATE} or
255      * {@link #PROGRESS_TYPE_LABEL}.
256      * @param isVisible
257      * @return
258      */
setProgressVisibility(boolean isVisible)259     public Card setProgressVisibility(boolean isVisible) {
260         if (mCardProgress.progressView == null) {
261             return this; // Card does not have progress
262         }
263         mCardProgress.progressView.setVisibility(isVisible ? View.VISIBLE : View.GONE);
264 
265         return this;
266     }
267 
268     /**
269      * Adds an action to this card during build time.
270      *
271      * @param label
272      * @param id
273      * @param type
274      */
addAction(String label, int id, int type)275     private void addAction(String label, int id, int type) {
276         CardAction cardAction = new CardAction();
277         cardAction.label = label;
278         cardAction.id = id;
279         cardAction.type = type;
280         mCardActions.add(cardAction);
281     }
282 
283     /**
284      * Toggles the visibility of a card action.
285      * @param actionId
286      * @param isVisible
287      * @return
288      */
setActionVisibility(int actionId, boolean isVisible)289     public Card setActionVisibility(int actionId, boolean isVisible) {
290         int visibilityFlag = isVisible ? View.VISIBLE : View.GONE;
291         for (CardAction action : mCardActions) {
292             if (action.id == actionId && action.actionView != null) {
293                 action.actionView.setVisibility(visibilityFlag);
294             }
295         }
296         return this;
297     }
298 
299     /**
300      * Toggles visibility of the action area of this Card through an animation.
301      * @param isVisible
302      * @return
303      */
setActionAreaVisibility(boolean isVisible)304     public Card setActionAreaVisibility(boolean isVisible) {
305         if (mActionAreaView == null) {
306             return this; // Card does not have an action area
307         }
308 
309         if (isVisible) {
310             // Show the action area
311             mActionAreaView.setVisibility(View.VISIBLE);
312             mActionAreaView.setPivotY(0.f);
313             mActionAreaView.setPivotX(mCardView.getWidth() / 2.f);
314             mActionAreaView.setAlpha(0.5f);
315             mActionAreaView.setRotationX(-90.f);
316             mActionAreaView.animate().rotationX(0.f).alpha(1.f).setDuration(400);
317         } else {
318             // Hide the action area
319             mActionAreaView.setPivotY(0.f);
320             mActionAreaView.setPivotX(mCardView.getWidth() / 2.f);
321             mActionAreaView.animate().rotationX(-90.f).alpha(0.f).setDuration(400).setListener(
322                     new AnimatorListenerAdapter() {
323                         @Override
324                         public void onAnimationEnd(Animator animation) {
325                             mActionAreaView.setVisibility(View.GONE);
326                         }
327                     });
328         }
329         return this;
330     }
331 
332 
333     /**
334      * Creates a shallow clone of the card.  Shallow means all values are present, but no views.
335      * This is useful for saving/restoring in the case of configuration changes, like screen
336      * rotation.
337      *
338      * @return A shallow clone of the card instance
339      */
createShallowClone()340     public Card createShallowClone() {
341         Card cloneCard = new Card();
342 
343         // Outer card values
344         cloneCard.mTitle = mTitle;
345         cloneCard.mDescription = mDescription;
346         cloneCard.mTag = mTag;
347         cloneCard.mLayoutId = mLayoutId;
348         cloneCard.mCardState = mCardState;
349 
350         // Progress
351         if (mCardProgress != null) {
352             cloneCard.mCardProgress = mCardProgress.createShallowClone();
353         }
354 
355         // Actions
356         for (CardAction action : mCardActions) {
357             cloneCard.mCardActions.add(action.createShallowClone());
358         }
359 
360         return cloneCard;
361     }
362 
363 
364     /**
365      * Prepare the card to be stored for configuration change.
366      */
prepareForConfigurationChange()367     public void prepareForConfigurationChange() {
368         // Null out views.
369         mCardView = null;
370         for (CardAction action : mCardActions) {
371             action.actionView = null;
372         }
373         mCardProgress.progressView = null;
374     }
375 
376     /**
377      * Creates a new {@link #Card}.
378      */
379     public static class Builder {
380         private Card mCard;
381 
382         /**
383          * Instantiate the builder with data from a shallow clone.
384          * @param listener
385          * @param card
386          * @see Card#createShallowClone()
387          */
Builder(OnCardClickListener listener, Card card)388         protected Builder(OnCardClickListener listener, Card card) {
389             mCard = card;
390             mCard.mClickListener = listener;
391         }
392 
393         /**
394          * Instantiate the builder with the tag of the card.
395          * @param listener
396          * @param tag
397          */
Builder(OnCardClickListener listener, String tag)398         public Builder(OnCardClickListener listener, String tag) {
399             mCard = new Card();
400             mCard.mTag = tag;
401             mCard.mClickListener = listener;
402         }
403 
setTitle(String title)404         public Builder setTitle(String title) {
405             mCard.mTitle = title;
406             return this;
407         }
408 
setDescription(String desc)409         public Builder setDescription(String desc) {
410             mCard.mDescription = desc;
411             return this;
412         }
413 
414         /**
415          * Add an action.
416          * The type describes how this action will be displayed. Accepted values are
417          * {@link #ACTION_NEUTRAL}, {@link #ACTION_POSITIVE} or {@link #ACTION_NEGATIVE}.
418          *
419          * @param label The text to display for this action
420          * @param id Identifier for this action, supplied in the click listener
421          * @param type UI style of action
422          * @return
423          */
addAction(String label, int id, int type)424         public Builder addAction(String label, int id, int type) {
425             mCard.addAction(label, id, type);
426             return this;
427         }
428 
429         /**
430          * Override the default layout.
431          * The referenced layout file has to contain the same identifiers as defined in the default
432          * layout configuration.
433          * @param layout
434          * @return
435          * @see R.layout.card
436          */
setLayout(int layout)437         public Builder setLayout(int layout) {
438             mCard.mLayoutId = layout;
439             return this;
440         }
441 
442         /**
443          * Set the type of progress bar to display.
444          * Accepted values are:
445          * <ul>
446          *     <li>{@link #PROGRESS_TYPE_NO_PROGRESS} disables the progress indicator</li>
447          *     <li>{@link #PROGRESS_TYPE_NORMAL}
448          *     displays a standard, linear progress indicator.</li>
449          *     <li>{@link #PROGRESS_TYPE_INDETERMINATE} displays an indeterminate (infite) progress
450          *     indicator.</li>
451          *     <li>{@link #PROGRESS_TYPE_LABEL} only displays a label text in the progress area
452          *     of the card.</li>
453          * </ul>
454          *
455          * @param progressType
456          * @return
457          */
setProgressType(int progressType)458         public Builder setProgressType(int progressType) {
459             mCard.setProgressType(progressType);
460             return this;
461         }
462 
setProgressLabel(String label)463         public Builder setProgressLabel(String label) {
464             // ensure the progress layout has been initialized, use 'no progress' by default
465             if (mCard.mCardProgress == null) {
466                 mCard.setProgressType(PROGRESS_TYPE_NO_PROGRESS);
467             }
468             mCard.mCardProgress.label = label;
469             return this;
470         }
471 
setProgressMaxValue(int maxValue)472         public Builder setProgressMaxValue(int maxValue) {
473             // ensure the progress layout has been initialized, use 'no progress' by default
474             if (mCard.mCardProgress == null) {
475                 mCard.setProgressType(PROGRESS_TYPE_NO_PROGRESS);
476             }
477             mCard.mCardProgress.maxValue = maxValue;
478             return this;
479         }
480 
setStatus(int status)481         public Builder setStatus(int status) {
482             mCard.setState(status);
483             return this;
484         }
485 
build(Activity activity)486         public Card build(Activity activity) {
487             LayoutInflater inflater = activity.getLayoutInflater();
488             // Inflating the card.
489             ViewGroup cardView = (ViewGroup) inflater.inflate(mCard.mLayoutId,
490                     (ViewGroup) activity.findViewById(R.id.card_stream), false);
491 
492             // Check that the layout contains a TextView with the card_title id
493             View viewTitle = cardView.findViewById(R.id.card_title);
494             if (mCard.mTitle != null && viewTitle != null) {
495                 mCard.mTitleView = (TextView) viewTitle;
496                 mCard.mTitleView.setText(mCard.mTitle);
497             } else if (viewTitle != null) {
498                 viewTitle.setVisibility(View.GONE);
499             }
500 
501             // Check that the layout contains a TextView with the card_content id
502             View viewDesc = cardView.findViewById(R.id.card_content);
503             if (mCard.mDescription != null && viewDesc != null) {
504                 mCard.mDescView = (TextView) viewDesc;
505                 mCard.mDescView.setText(mCard.mDescription);
506             } else if (viewDesc != null) {
507                 cardView.findViewById(R.id.card_content).setVisibility(View.GONE);
508             }
509 
510 
511             ViewGroup actionArea = (ViewGroup) cardView.findViewById(R.id.card_actionarea);
512 
513             // Inflate Progress
514             initializeProgressView(inflater, actionArea);
515 
516             // Inflate all action views.
517             initializeActionViews(inflater, cardView, actionArea);
518 
519             mCard.mCardView = cardView;
520             mCard.mOverlayView = cardView.findViewById(R.id.card_overlay);
521 
522             return mCard;
523         }
524 
525         /**
526          * Initialize data from the given card.
527          * @param card
528          * @return
529          * @see Card#createShallowClone()
530          */
cloneFromCard(Card card)531         public Builder cloneFromCard(Card card) {
532             mCard = card.createShallowClone();
533             return this;
534         }
535 
536         /**
537          * Build the action views by inflating the appropriate layouts and setting the text and
538          * values.
539          * @param inflater
540          * @param cardView
541          * @param actionArea
542          */
initializeActionViews(LayoutInflater inflater, ViewGroup cardView, ViewGroup actionArea)543         private void initializeActionViews(LayoutInflater inflater, ViewGroup cardView,
544                                            ViewGroup actionArea) {
545             if (!mCard.mCardActions.isEmpty()) {
546                 // Set action area to visible only when actions are visible
547                 actionArea.setVisibility(View.VISIBLE);
548                 mCard.mActionAreaView = actionArea;
549             }
550 
551             // Inflate all card actions
552             for (final CardAction action : mCard.mCardActions) {
553 
554                 int useActionLayout = 0;
555                 switch (action.type) {
556                     case Card.ACTION_POSITIVE:
557                         useActionLayout = R.layout.card_button_positive;
558                         break;
559                     case Card.ACTION_NEGATIVE:
560                         useActionLayout = R.layout.card_button_negative;
561                         break;
562                     case Card.ACTION_NEUTRAL:
563                     default:
564                         useActionLayout = R.layout.card_button_neutral;
565                         break;
566                 }
567 
568                 action.actionView = inflater.inflate(useActionLayout, actionArea, false);
569                 Button actionButton = (Button) action.actionView.findViewById(R.id.card_button);
570 
571                 actionButton.setText(action.label);
572                 actionButton.setOnClickListener(new View.OnClickListener() {
573                     @Override
574                     public void onClick(View v) {
575                         mCard.mClickListener.onCardClick(action.id, mCard.mTag);
576                     }
577                 });
578                 actionArea.addView(action.actionView);
579             }
580         }
581 
582         /**
583          * Build the progress view into the given ViewGroup.
584          *
585          * @param inflater
586          * @param actionArea
587          */
initializeProgressView(LayoutInflater inflater, ViewGroup actionArea)588         private void initializeProgressView(LayoutInflater inflater, ViewGroup actionArea) {
589 
590             // Only inflate progress layout if a progress type other than NO_PROGRESS was set.
591             if (mCard.mCardProgress != null) {
592                 //Setup progress card.
593                 View progressView = inflater.inflate(R.layout.card_progress, actionArea, false);
594                 ProgressBar progressBar =
595                         (ProgressBar) progressView.findViewById(R.id.card_progress);
596                 ((TextView) progressView.findViewById(R.id.card_progress_text))
597                         .setText(mCard.mCardProgress.label);
598                 progressBar.setMax(mCard.mCardProgress.maxValue);
599                 progressBar.setProgress(0);
600                 mCard.mCardProgress.progressView = progressView;
601                 mCard.mCardProgress.setProgressType(mCard.getProgressType());
602                 actionArea.addView(progressView);
603             }
604         }
605     }
606 
607     /**
608      * Represents a clickable action, accessible from the bottom of the card.
609      * Fields include the label, an ID to specify the action that was performed in the callback,
610      * an action type (positive, negative, neutral), and the callback.
611      */
612     public class CardAction {
613 
614         public String label;
615         public int id;
616         public int type;
617         public View actionView;
618 
createShallowClone()619         public CardAction createShallowClone() {
620             CardAction actionClone = new CardAction();
621             actionClone.label = label;
622             actionClone.id = id;
623             actionClone.type = type;
624             return actionClone;
625             // Not the view.  Never the view (don't want to hold view references for
626             // onConfigurationChange.
627         }
628 
629     }
630 
631     /**
632      * Describes the progress of a {@link Card}.
633      * Three types of progress are supported:
634      * <ul><li>{@link Card#PROGRESS_TYPE_NORMAL: Standard progress bar with label text</li>
635      * <li>{@link Card#PROGRESS_TYPE_INDETERMINATE}: Indeterminate progress bar with label txt</li>
636      * <li>{@link Card#PROGRESS_TYPE_LABEL}: Label only, no progresss bar</li>
637      * </ul>
638      */
639     public class CardProgress {
640         private int progressType = Card.PROGRESS_TYPE_NO_PROGRESS;
641         private String label = "";
642         private int currProgress = 0;
643         private int maxValue = 100;
644 
645         public View progressView = null;
646         private ProgressBar progressBar = null;
647         private TextView progressLabel = null;
648 
createShallowClone()649         public CardProgress createShallowClone() {
650             CardProgress progressClone = new CardProgress();
651             progressClone.label = label;
652             progressClone.currProgress = currProgress;
653             progressClone.maxValue = maxValue;
654             progressClone.progressType = progressType;
655             return progressClone;
656         }
657 
658         /**
659          * Set the progress. Only useful for the type {@link #PROGRESS_TYPE_NORMAL}.
660          * @param progress
661          * @see android.widget.ProgressBar#setProgress(int)
662          */
setProgress(int progress)663         public void setProgress(int progress) {
664             currProgress = progress;
665             final ProgressBar bar = getProgressBar();
666             if (bar != null) {
667                 bar.setProgress(currProgress);
668                 bar.invalidate();
669             }
670         }
671 
672         /**
673          * Set the range of the progress to 0...max.
674          * Only useful for the type {@link #PROGRESS_TYPE_NORMAL}.
675          * @param max
676          * @see android.widget.ProgressBar#setMax(int)
677          */
setMax(int max)678         public void setMax(int max) {
679             maxValue = max;
680             final ProgressBar bar = getProgressBar();
681             if (bar != null) {
682                 bar.setMax(maxValue);
683             }
684         }
685 
686         /**
687          * Set the label text that appears near the progress indicator.
688          * @param text
689          */
setProgressLabel(String text)690         public void setProgressLabel(String text) {
691             label = text;
692             final TextView labelView = getProgressLabel();
693             if (labelView != null) {
694                 labelView.setText(text);
695             }
696         }
697 
698         /**
699          * Set how progress is displayed. The parameter must be one of three supported types:
700          * <ul><li>{@link Card#PROGRESS_TYPE_NORMAL: Standard progress bar with label text</li>
701          * <li>{@link Card#PROGRESS_TYPE_INDETERMINATE}:
702          * Indeterminate progress bar with label txt</li>
703          * <li>{@link Card#PROGRESS_TYPE_LABEL}: Label only, no progresss bar</li>
704          * @param type
705          */
setProgressType(int type)706         public void setProgressType(int type) {
707             progressType = type;
708             if (progressView != null) {
709                 switch (type) {
710                     case PROGRESS_TYPE_NO_PROGRESS: {
711                         progressView.setVisibility(View.GONE);
712                         break;
713                     }
714                     case PROGRESS_TYPE_NORMAL: {
715                         progressView.setVisibility(View.VISIBLE);
716                         getProgressBar().setIndeterminate(false);
717                         break;
718                     }
719                     case PROGRESS_TYPE_INDETERMINATE: {
720                         progressView.setVisibility(View.VISIBLE);
721                         getProgressBar().setIndeterminate(true);
722                         break;
723                     }
724                 }
725             }
726         }
727 
getProgressLabel()728         private TextView getProgressLabel() {
729             if (progressLabel != null) {
730                 return progressLabel;
731             } else if (progressView != null) {
732                 progressLabel = (TextView) progressView.findViewById(R.id.card_progress_text);
733                 return progressLabel;
734             } else {
735                 return null;
736             }
737         }
738 
getProgressBar()739         private ProgressBar getProgressBar() {
740             if (progressBar != null) {
741                 return progressBar;
742             } else if (progressView != null) {
743                 progressBar = (ProgressBar) progressView.findViewById(R.id.card_progress);
744                 return progressBar;
745             } else {
746                 return null;
747             }
748         }
749 
750     }
751 }
752 
753