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