1/*
2 * Copyright (C) 2016 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 */
16package com.android.settings.dashboard;
17
18import android.accounts.Account;
19import android.annotation.DrawableRes;
20import android.annotation.LayoutRes;
21import android.annotation.StringRes;
22import android.app.Activity;
23import android.app.ActivityManager;
24import android.app.DialogFragment;
25import android.content.Context;
26import android.content.Intent;
27import android.content.pm.PackageManager;
28import android.os.Bundle;
29import android.support.v7.widget.RecyclerView;
30import android.text.TextUtils;
31import android.view.LayoutInflater;
32import android.view.View;
33import android.view.ViewGroup;
34import android.widget.AdapterView;
35import android.widget.ArrayAdapter;
36import android.widget.ImageView;
37import android.widget.Spinner;
38import android.widget.TextView;
39
40import com.android.internal.logging.MetricsLogger;
41import com.android.internal.logging.MetricsProto;
42import com.android.settings.R;
43import com.android.settings.overlay.SupportFeatureProvider;
44import com.android.settings.support.SupportDisclaimerDialogFragment;
45import com.android.settings.support.SupportPhone;
46import com.android.settings.support.SupportPhoneDialogFragment;
47
48import java.util.ArrayList;
49import java.util.List;
50import java.util.Objects;
51
52import static com.android.settings.overlay.SupportFeatureProvider.SupportType.CHAT;
53import static com.android.settings.overlay.SupportFeatureProvider.SupportType.PHONE;
54
55/**
56 * Item adapter for support tiles.
57 */
58public final class SupportItemAdapter extends RecyclerView.Adapter<SupportItemAdapter.ViewHolder> {
59
60    private static final String STATE_SELECTED_COUNTRY = "STATE_SELECTED_COUNTRY";
61    private static final int TYPE_ESCALATION_OPTIONS = R.layout.support_escalation_options;
62    private static final int TYPE_ESCALATION_OPTIONS_OFFLINE =
63            R.layout.support_offline_escalation_options;
64    private static final int TYPE_SUPPORT_TILE = R.layout.support_tile;
65    private static final int TYPE_SUPPORT_TILE_SPACER = R.layout.support_tile_spacer;
66    private static final int TYPE_SIGN_IN_BUTTON = R.layout.support_sign_in_button;
67
68    private final Activity mActivity;
69    private final EscalationClickListener mEscalationClickListener;
70    private final SpinnerItemSelectListener mSpinnerItemSelectListener;
71    private final SupportFeatureProvider mSupportFeatureProvider;
72    private final View.OnClickListener mItemClickListener;
73    private final List<SupportData> mSupportData;
74
75    private String mSelectedCountry;
76    private boolean mHasInternet;
77    private Account mAccount;
78
79    public SupportItemAdapter(Activity activity, Bundle savedInstanceState,
80            SupportFeatureProvider supportFeatureProvider, View.OnClickListener itemClickListener) {
81        mActivity = activity;
82        mSupportFeatureProvider = supportFeatureProvider;
83        mItemClickListener = itemClickListener;
84        mEscalationClickListener = new EscalationClickListener();
85        mSpinnerItemSelectListener = new SpinnerItemSelectListener();
86        mSupportData = new ArrayList<>();
87        // Optimistically assume we have Internet access. It will be updated later to correct value.
88        mHasInternet = true;
89        if (savedInstanceState != null) {
90            mSelectedCountry = savedInstanceState.getString(STATE_SELECTED_COUNTRY);
91        } else {
92            mSelectedCountry = mSupportFeatureProvider.getCurrentCountryCodeIfHasConfig(PHONE);
93        }
94        mAccount = mSupportFeatureProvider.getSupportEligibleAccount(mActivity);
95        refreshData();
96    }
97
98    @Override
99    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
100        return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(
101                viewType, parent, false));
102    }
103
104    @Override
105    public void onBindViewHolder(ViewHolder holder, int position) {
106        final SupportData data = mSupportData.get(position);
107        switch (holder.getItemViewType()) {
108            case TYPE_SIGN_IN_BUTTON:
109                bindSignInPromoTile(holder, (EscalationData) data);
110                break;
111            case TYPE_ESCALATION_OPTIONS:
112                bindEscalationOptions(holder, (EscalationData) data);
113                break;
114            case TYPE_ESCALATION_OPTIONS_OFFLINE:
115                bindOfflineEscalationOptions(holder, (OfflineEscalationData) data);
116                break;
117            case TYPE_SUPPORT_TILE_SPACER:
118                break;
119            default:
120                bindSupportTile(holder, data);
121                break;
122        }
123    }
124
125    @Override
126    public int getItemViewType(int position) {
127        return mSupportData.get(position).type;
128    }
129
130    @Override
131    public int getItemCount() {
132        return mSupportData.size();
133    }
134
135    /**
136     * Called when a support item is clicked.
137     */
138    public void onItemClicked(int position) {
139        if (position >= 0 && position < mSupportData.size()) {
140            final SupportData data = mSupportData.get(position);
141            if (data.intent != null &&
142                    mActivity.getPackageManager().resolveActivity(data.intent, 0) != null) {
143                if (data.metricsEvent >= 0) {
144                    MetricsLogger.action(mActivity, data.metricsEvent);
145                }
146                mActivity.startActivityForResult(data.intent, 0);
147            }
148        }
149    }
150
151    public void setHasInternet(boolean hasInternet) {
152        if (mHasInternet != hasInternet) {
153            mHasInternet = hasInternet;
154            refreshEscalationCards();
155        }
156    }
157
158    public void setAccount(Account account) {
159        if (!Objects.equals(mAccount, account)) {
160            mAccount = account;
161            mSupportFeatureProvider.refreshOperationRules();
162            refreshEscalationCards();
163        }
164    }
165
166    public void onSaveInstanceState(Bundle outState) {
167        outState.putString(STATE_SELECTED_COUNTRY, mSelectedCountry);
168    }
169
170    /**
171     * Create data for the adapter. If there is already data in the adapter, they will be
172     * destroyed and recreated.
173     */
174    private void refreshData() {
175        mSupportData.clear();
176        addEscalationCards();
177        addMoreHelpItems();
178        notifyDataSetChanged();
179    }
180
181    /**
182     * Adds 1 escalation card. Based on current phone state, the escalation card can display
183     * different content.
184     */
185    private void addEscalationCards() {
186        if (mAccount == null) {
187            addSignInPromo();
188        } else if (mHasInternet) {
189            addOnlineEscalationCards();
190        } else {
191            addOfflineEscalationCards();
192        }
193    }
194
195    /**
196     * Finds and refreshes escalation card data.
197     */
198    private void refreshEscalationCards() {
199        if (getItemCount() > 0) {
200            final int itemType = getItemViewType(0 /* position */);
201            if (itemType == TYPE_SIGN_IN_BUTTON
202                    || itemType == TYPE_ESCALATION_OPTIONS
203                    || itemType == TYPE_ESCALATION_OPTIONS_OFFLINE) {
204                mSupportData.remove(0 /* position */);
205                addEscalationCards();
206                notifyItemChanged(0 /* position */);
207            }
208        }
209    }
210
211    private void addOnlineEscalationCards() {
212        final boolean hasPhoneOperation =
213                mSupportFeatureProvider.isSupportTypeEnabled(mActivity, PHONE);
214        final boolean hasChatOperation =
215                mSupportFeatureProvider.isSupportTypeEnabled(mActivity, CHAT);
216        final EscalationData.Builder builder = new EscalationData.Builder(mActivity);
217        if (!hasPhoneOperation && !hasChatOperation) {
218            // No support at all.
219            builder.setTileTitle(R.string.support_escalation_title)
220                    .setTileSummary(R.string.support_escalation_unavailable_summary);
221        } else if (mSupportFeatureProvider.isAlwaysOperating(PHONE, null /* countryCode */)
222                || mSupportFeatureProvider.isAlwaysOperating(CHAT, null /* countryCode */)) {
223            // Support is available.
224            builder.setTileTitle(R.string.support_escalation_24_7_title)
225                    .setTileTitleDescription(R.string.support_escalation_24_7_content_description)
226                    .setTileSummary(mActivity.getString(R.string.support_escalation_24_7_summary));
227        } else if (mSupportFeatureProvider.isOperatingNow(PHONE)
228                || mSupportFeatureProvider.isOperatingNow(CHAT)) {
229            // Support is available now.
230            builder.setTileTitle(R.string.support_escalation_title)
231                    .setTileSummary(R.string.support_escalation_summary);
232        } else {
233            // Support is now temporarily unavailable.
234            builder.setTileTitle(R.string.support_escalation_title)
235                    .setTileSummary(
236                            mSupportFeatureProvider.getOperationHours(mActivity, PHONE, null,
237                                    true /* hasInternet */));
238        }
239        if (hasPhoneOperation) {
240            builder.setText1(R.string.support_escalation_by_phone)
241                    .setSummary1(mSupportFeatureProvider.getEstimatedWaitTime(mActivity, PHONE))
242                    .setEnabled1(mSupportFeatureProvider.isOperatingNow(PHONE));
243        }
244        if (hasChatOperation) {
245            builder.setText2(R.string.support_escalation_by_chat)
246                    .setSummary2(mSupportFeatureProvider.getEstimatedWaitTime(mActivity, CHAT))
247                    .setEnabled2(mSupportFeatureProvider.isOperatingNow(CHAT));
248        }
249        mSupportData.add(0 /* index */, builder.build());
250    }
251
252    private void addOfflineEscalationCards() {
253        final CharSequence operatingHours;
254        final boolean isPhoneSupportAlwaysOperating =
255                mSupportFeatureProvider.isAlwaysOperating(PHONE, mSelectedCountry);
256        if (isPhoneSupportAlwaysOperating) {
257            operatingHours = mActivity.getString(R.string.support_escalation_24_7_summary);
258        } else {
259            operatingHours = mSupportFeatureProvider.getOperationHours(mActivity,
260                    PHONE, mSelectedCountry, false /* hasInternet */);
261        }
262        mSupportData.add(0 /* index */, new OfflineEscalationData.Builder(mActivity)
263                .setCountries(mSupportFeatureProvider.getPhoneSupportCountries())
264                .setTollFreePhone(mSupportFeatureProvider.getSupportPhones(
265                        mSelectedCountry, true /* isTollFree */))
266                .setTolledPhone(mSupportFeatureProvider.getSupportPhones(
267                        mSelectedCountry, false /* isTollFree */))
268                .setTileTitle(isPhoneSupportAlwaysOperating
269                        ? R.string.support_escalation_24_7_title
270                        : R.string.support_escalation_title)
271                .setTileTitleDescription(isPhoneSupportAlwaysOperating
272                        ? R.string.support_escalation_24_7_content_description
273                        : R.string.support_escalation_title)
274                .setTileSummary(operatingHours)
275                .build());
276    }
277
278    private void addSignInPromo() {
279        mSupportData.add(0 /* index */, new EscalationData.Builder(mActivity, TYPE_SIGN_IN_BUTTON)
280                .setText1(R.string.support_sign_in_button_text)
281                .setText2(R.string.support_sign_in_required_help)
282                .setTileTitle(R.string.support_sign_in_required_title)
283                .setTileSummary(R.string.support_sign_in_required_summary)
284                .build());
285    }
286
287    private void addMoreHelpItems() {
288        mSupportData.add(new SupportData.Builder(mActivity, TYPE_SUPPORT_TILE_SPACER).build());
289        PackageManager packageManager = mActivity.getPackageManager();
290        Intent intent = mSupportFeatureProvider.getHelpIntent(mActivity);
291        if (packageManager.resolveActivity(intent, 0) != null) {
292            mSupportData.add(new SupportData.Builder(mActivity, TYPE_SUPPORT_TILE)
293                    .setIcon(R.drawable.ic_help_24dp)
294                    .setTileTitle(R.string.support_help_feedback_title)
295                    .setIntent(intent)
296                    .setMetricsEvent(MetricsProto.MetricsEvent.ACTION_SUPPORT_HELP_AND_FEEDBACK)
297                    .build());
298        }
299        intent = mSupportFeatureProvider.getTipsAndTricksIntent(mActivity);
300        if (packageManager.resolveActivity(intent, 0) != null) {
301            mSupportData.add(new SupportData.Builder(mActivity, TYPE_SUPPORT_TILE)
302                    .setIcon(R.drawable.ic_lightbulb_outline_24)
303                    .setTileTitle(R.string.support_tips_and_tricks_title)
304                    .setIntent(intent)
305                    .setMetricsEvent(MetricsProto.MetricsEvent.ACTION_SUPPORT_TIPS_AND_TRICKS)
306                    .build());
307        }
308    }
309
310    private void bindEscalationOptions(ViewHolder holder, EscalationData data) {
311        holder.tileTitleView.setText(data.tileTitle);
312        holder.tileTitleView.setContentDescription(data.tileTitleDescription);
313        holder.tileSummaryView.setText(data.tileSummary);
314        if (data.text1 == 0) {
315            holder.text1View.setVisibility(View.GONE);
316        } else {
317            holder.text1View.setText(data.text1);
318            holder.text1View.setOnClickListener(mEscalationClickListener);
319            holder.text1View.setEnabled(data.enabled1 && mHasInternet);
320            holder.text1View.setVisibility(View.VISIBLE);
321        }
322        if (TextUtils.isEmpty(data.text2)) {
323            holder.text2View.setVisibility(View.GONE);
324        } else {
325            holder.text2View.setText(data.text2);
326            holder.text2View.setOnClickListener(mEscalationClickListener);
327            holder.text2View.setEnabled(data.enabled2 && mHasInternet);
328            holder.text2View.setVisibility(View.VISIBLE);
329        }
330        if (holder.summary1View != null) {
331            holder.summary1View.setText(data.summary1);
332            holder.summary1View.setVisibility(mHasInternet && !TextUtils.isEmpty(data.summary1)
333                    ? View.VISIBLE : View.GONE);
334        }
335        if (holder.summary2View != null) {
336            holder.summary2View.setText(data.summary2);
337            holder.summary2View.setVisibility(mHasInternet && !TextUtils.isEmpty(data.summary2)
338                    ? View.VISIBLE : View.GONE);
339        }
340    }
341
342    private void bindOfflineEscalationOptions(ViewHolder holder, OfflineEscalationData data) {
343        // Bind Title
344        holder.tileTitleView.setText(data.tileTitle);
345        holder.tileTitleView.setContentDescription(data.tileTitleDescription);
346        holder.tileSummaryView.setText(data.tileSummary);
347        // Bind spinner
348        final Spinner spinner = (Spinner) holder.itemView.findViewById(R.id.spinner);
349        final ArrayAdapter<String> adapter = new ArrayAdapter(
350                mActivity, android.R.layout.simple_spinner_dropdown_item, data.countries);
351        spinner.setAdapter(adapter);
352        final List<String> countryCodes = mSupportFeatureProvider.getPhoneSupportCountryCodes();
353        for (int i = 0; i < countryCodes.size(); i++) {
354            if (TextUtils.equals(countryCodes.get(i), mSelectedCountry)) {
355                spinner.setSelection(i);
356                break;
357            }
358        }
359        spinner.setOnItemSelectedListener(mSpinnerItemSelectListener);
360        // Bind buttons
361        if (data.tollFreePhone != null) {
362            holder.text1View.setText(data.tollFreePhone.number);
363            holder.text1View.setVisibility(View.VISIBLE);
364            holder.text1View.setOnClickListener(mEscalationClickListener);
365        } else {
366            holder.text1View.setVisibility(View.GONE);
367        }
368        if (data.tolledPhone != null) {
369            holder.text2View.setText(
370                    mActivity.getString(R.string.support_international_phone_title));
371            holder.text2View.setVisibility(View.VISIBLE);
372            holder.text2View.setOnClickListener(mEscalationClickListener);
373        } else {
374            holder.text2View.setVisibility(View.GONE);
375        }
376
377        if (ActivityManager.isUserAMonkey()) {
378            holder.text1View.setVisibility(View.GONE);
379            holder.text2View.setVisibility(View.GONE);
380            spinner.setVisibility(View.GONE);
381            holder.itemView.findViewById(R.id.support_text).setVisibility(View.GONE);
382        }
383    }
384
385    private void bindSignInPromoTile(ViewHolder holder, EscalationData data) {
386        holder.tileTitleView.setText(data.tileTitle);
387        holder.tileTitleView.setContentDescription(data.tileTitleDescription);
388        holder.tileSummaryView.setText(data.tileSummary);
389        holder.text1View.setText(data.text1);
390        holder.text2View.setText(data.text2);
391        holder.text1View.setOnClickListener(mEscalationClickListener);
392        holder.text2View.setOnClickListener(mEscalationClickListener);
393    }
394
395    private void bindSupportTile(ViewHolder holder, SupportData data) {
396        if (holder.iconView != null) {
397            holder.iconView.setImageResource(data.icon);
398        }
399        if (holder.tileTitleView != null) {
400            holder.tileTitleView.setText(data.tileTitle);
401            holder.tileTitleView.setContentDescription(data.tileTitleDescription);
402        }
403        if (holder.tileSummaryView != null) {
404            holder.tileSummaryView.setText(data.tileSummary);
405        }
406        holder.itemView.setOnClickListener(mItemClickListener);
407    }
408
409    /**
410     * Show a disclaimer dialog and start support action after disclaimer has been acknowledged.
411     */
412    private void tryStartDisclaimerAndSupport(final @SupportFeatureProvider.SupportType int type) {
413        if (mSupportFeatureProvider.shouldShowDisclaimerDialog(mActivity)) {
414            DialogFragment fragment = SupportDisclaimerDialogFragment.newInstance(mAccount, type);
415            fragment.show(mActivity.getFragmentManager(), SupportDisclaimerDialogFragment.TAG);
416            return;
417        }
418        mSupportFeatureProvider.startSupport(mActivity, mAccount, type);
419    }
420
421    /**
422     * Click handler for starting escalation options.
423     */
424    private final class EscalationClickListener implements View.OnClickListener {
425        @Override
426        public void onClick(final View v) {
427            if (mAccount == null) {
428                switch (v.getId()) {
429                    case android.R.id.text1:
430                        MetricsLogger.action(mActivity,
431                                MetricsProto.MetricsEvent.ACTION_SUPPORT_SIGN_IN);
432                        mActivity.startActivityForResult(
433                                mSupportFeatureProvider.getAccountLoginIntent(),
434                                0 /* requestCode */);
435                        break;
436                    case android.R.id.text2:
437                        mActivity.startActivityForResult(
438                                mSupportFeatureProvider.getSignInHelpIntent(mActivity),
439                                0 /* requestCode */);
440                        break;
441                }
442            } else if (mHasInternet) {
443                switch (v.getId()) {
444                    case android.R.id.text1:
445                        MetricsLogger.action(mActivity,
446                                MetricsProto.MetricsEvent.ACTION_SUPPORT_PHONE);
447                        tryStartDisclaimerAndSupport(PHONE);
448                        break;
449                    case android.R.id.text2:
450                        MetricsLogger.action(mActivity,
451                                MetricsProto.MetricsEvent.ACTION_SUPPORT_CHAT);
452                        tryStartDisclaimerAndSupport(CHAT);
453                        break;
454                }
455            } else {
456                switch (v.getId()) {
457                    case android.R.id.text1: {
458                        final SupportPhone phone = mSupportFeatureProvider
459                                .getSupportPhones(mSelectedCountry, true /* isTollFree */);
460                        if (phone != null) {
461                            final Intent intent = phone.getDialIntent();
462                            final boolean canDial = !mActivity.getPackageManager()
463                                    .queryIntentActivities(intent, 0)
464                                    .isEmpty();
465                            if (canDial) {
466                                MetricsLogger.action(mActivity,
467                                        MetricsProto.MetricsEvent.ACTION_SUPPORT_DAIL_TOLLFREE);
468                                mActivity.startActivity(intent);
469                            }
470                        }
471                        break;
472                    }
473                    case android.R.id.text2: {
474                        final SupportPhone phone = mSupportFeatureProvider
475                                .getSupportPhones(mSelectedCountry, false /* isTollFree */);
476                        final SupportPhoneDialogFragment fragment =
477                                SupportPhoneDialogFragment.newInstance(phone);
478                        MetricsLogger.action(mActivity,
479                                MetricsProto.MetricsEvent.ACTION_SUPPORT_VIEW_TRAVEL_ABROAD_DIALOG);
480                        fragment.show(mActivity.getFragmentManager(),
481                                SupportPhoneDialogFragment.TAG);
482                        break;
483                    }
484                }
485            }
486        }
487    }
488
489    private final class SpinnerItemSelectListener implements AdapterView.OnItemSelectedListener {
490
491        @Override
492        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
493            final List<String> countryCodes = mSupportFeatureProvider.getPhoneSupportCountryCodes();
494            final String selectedCountry = countryCodes.get(position);
495            if (!TextUtils.equals(selectedCountry, mSelectedCountry)) {
496                mSelectedCountry = selectedCountry;
497                refreshEscalationCards();
498            }
499        }
500
501        @Override
502        public void onNothingSelected(AdapterView<?> parent) {
503            // Do nothing.
504        }
505    }
506
507    /**
508     * {@link RecyclerView.ViewHolder} for support items.
509     */
510    static final class ViewHolder extends RecyclerView.ViewHolder {
511
512        final ImageView iconView;
513        final TextView tileTitleView;
514        final TextView tileSummaryView;
515        final TextView text1View;
516        final TextView text2View;
517        final TextView summary1View;
518        final TextView summary2View;
519
520        ViewHolder(View itemView) {
521            super(itemView);
522            iconView = (ImageView) itemView.findViewById(android.R.id.icon);
523            tileTitleView = (TextView) itemView.findViewById(R.id.tile_title);
524            tileSummaryView = (TextView) itemView.findViewById(R.id.tile_summary);
525            text1View = (TextView) itemView.findViewById(android.R.id.text1);
526            text2View = (TextView) itemView.findViewById(android.R.id.text2);
527            summary1View = (TextView) itemView.findViewById(R.id.summary1);
528            summary2View = (TextView) itemView.findViewById(R.id.summary2);
529        }
530    }
531
532    /**
533     * Data for a single support item.
534     */
535    private static class SupportData {
536
537        final Intent intent;
538        final int metricsEvent;
539        @LayoutRes
540        final int type;
541        @DrawableRes
542        final int icon;
543        @StringRes
544        final int tileTitle;
545        final CharSequence tileTitleDescription;
546        final CharSequence tileSummary;
547
548
549        private SupportData(Builder builder) {
550            this.type = builder.mType;
551            this.icon = builder.mIcon;
552            this.tileTitle = builder.mTileTitle;
553            this.tileTitleDescription = builder.mTileTitleDescription;
554            this.tileSummary = builder.mTileSummary;
555            this.intent = builder.mIntent;
556            this.metricsEvent = builder.mMetricsEvent;
557        }
558
559        static class Builder {
560
561            protected final Context mContext;
562            @LayoutRes
563            private final int mType;
564            @DrawableRes
565            private int mIcon;
566            @StringRes
567            private int mTileTitle;
568            private CharSequence mTileTitleDescription;
569            private CharSequence mTileSummary;
570            private Intent mIntent;
571            private int mMetricsEvent = -1;
572
573            Builder(Context context, @LayoutRes int type) {
574                mContext = context;
575                mType = type;
576            }
577
578            Builder setIcon(@DrawableRes int icon) {
579                mIcon = icon;
580                return this;
581            }
582
583            Builder setTileTitle(@StringRes int title) {
584                mTileTitle = title;
585                return this;
586            }
587
588            Builder setTileTitleDescription(@StringRes int titleDescription) {
589                mTileTitleDescription = mContext.getString(titleDescription);
590                return this;
591            }
592
593            Builder setTileSummary(@StringRes int summary) {
594                mTileSummary = mContext.getString(summary);
595                return this;
596            }
597
598            Builder setTileSummary(CharSequence summary) {
599                mTileSummary = summary;
600                return this;
601            }
602
603            Builder setMetricsEvent(int metricsEvent) {
604                mMetricsEvent = metricsEvent;
605                return this;
606            }
607
608            Builder setIntent(Intent intent) {
609                mIntent = intent;
610                return this;
611            }
612
613            SupportData build() {
614                return new SupportData(this);
615            }
616        }
617    }
618
619    /**
620     * Data model for escalation cards.
621     */
622    private static class EscalationData extends SupportData {
623
624        @StringRes
625        final int text1;
626        final CharSequence text2;
627        final boolean enabled1;
628        final boolean enabled2;
629        final CharSequence summary1;
630        final CharSequence summary2;
631
632        private EscalationData(Builder builder) {
633            super(builder);
634            this.text1 = builder.mText1;
635            this.text2 = builder.mText2;
636            this.summary1 = builder.mSummary1;
637            this.summary2 = builder.mSummary2;
638            this.enabled1 = builder.mEnabled1;
639            this.enabled2 = builder.mEnabled2;
640        }
641
642        static class Builder extends SupportData.Builder {
643
644            @StringRes
645            private int mText1;
646            private CharSequence mText2;
647            private CharSequence mSummary1;
648            private CharSequence mSummary2;
649            private boolean mEnabled1;
650            private boolean mEnabled2;
651
652            protected Builder(Context context, @LayoutRes int type) {
653                super(context, type);
654            }
655
656            Builder(Context context) {
657                this(context, TYPE_ESCALATION_OPTIONS);
658            }
659
660            Builder setEnabled1(boolean enabled) {
661                mEnabled1 = enabled;
662                return this;
663            }
664
665            Builder setText1(@StringRes int text1) {
666                mText1 = text1;
667                return this;
668            }
669
670            Builder setText2(@StringRes int text2) {
671                mText2 = mContext.getString(text2);
672                return this;
673            }
674
675            Builder setText2(CharSequence text2) {
676                mText2 = text2;
677                return this;
678            }
679
680            Builder setSummary1(String summary1) {
681                mSummary1 = summary1;
682                return this;
683            }
684
685            Builder setEnabled2(boolean enabled) {
686                mEnabled2 = enabled;
687                return this;
688            }
689
690            Builder setSummary2(String summary2) {
691                mSummary2 = summary2;
692                return this;
693            }
694
695            EscalationData build() {
696                return new EscalationData(this);
697            }
698        }
699    }
700
701    /**
702     * Support data for offline mode.
703     */
704    private static final class OfflineEscalationData extends EscalationData {
705
706        final List<String> countries;
707        final SupportPhone tollFreePhone;
708        final SupportPhone tolledPhone;
709
710        private OfflineEscalationData(Builder builder) {
711            super(builder);
712            countries = builder.mCountries;
713            tollFreePhone = builder.mTollFreePhone;
714            tolledPhone = builder.mTolledPhone;
715        }
716
717        static final class Builder extends EscalationData.Builder {
718
719            private List<String> mCountries;
720            private SupportPhone mTollFreePhone;
721            private SupportPhone mTolledPhone;
722
723            Builder(Context context) {
724                super(context, TYPE_ESCALATION_OPTIONS_OFFLINE);
725            }
726
727            Builder setCountries(List<String> countries) {
728                mCountries = countries;
729                return this;
730            }
731
732            Builder setTollFreePhone(SupportPhone phone) {
733                mTollFreePhone = phone;
734                return this;
735            }
736
737            Builder setTolledPhone(SupportPhone phone) {
738                mTolledPhone = phone;
739                return this;
740            }
741
742            OfflineEscalationData build() {
743                return new OfflineEscalationData(this);
744            }
745        }
746    }
747}
748