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