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.v7.widget.RecyclerView; 30 import android.text.TextUtils; 31 import android.view.LayoutInflater; 32 import android.view.View; 33 import android.view.ViewGroup; 34 import android.widget.AdapterView; 35 import android.widget.ArrayAdapter; 36 import android.widget.ImageView; 37 import android.widget.Spinner; 38 import android.widget.TextView; 39 40 import com.android.internal.logging.MetricsLogger; 41 import com.android.internal.logging.MetricsProto; 42 import com.android.settings.R; 43 import com.android.settings.overlay.SupportFeatureProvider; 44 import com.android.settings.support.SupportDisclaimerDialogFragment; 45 import com.android.settings.support.SupportPhone; 46 import com.android.settings.support.SupportPhoneDialogFragment; 47 48 import java.util.ArrayList; 49 import java.util.List; 50 import java.util.Objects; 51 52 import static com.android.settings.overlay.SupportFeatureProvider.SupportType.CHAT; 53 import static com.android.settings.overlay.SupportFeatureProvider.SupportType.PHONE; 54 55 /** 56 * Item adapter for support tiles. 57 */ 58 public 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