When offline show a list of countries with phone support.

Bug: 29105266

TODO:
- Support phones UI for international travel
- Selecting default country
- Show operation hours for selected country

Change-Id: I08a6780497dfcb9b9dc8670f2705d01df021c57b
diff --git a/res/layout/support_offline_escalation_options.xml b/res/layout/support_offline_escalation_options.xml
new file mode 100644
index 0000000..f440d20
--- /dev/null
+++ b/res/layout/support_offline_escalation_options.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@color/card_background_grey"
+    android:gravity="center_horizontal"
+    android:paddingBottom="40dp"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/support_country_list_title"
+            android:textAppearance="@style/TextAppearance.Small"
+            android:textColor="?android:attr/textColorSecondary"/>
+        <Spinner
+            android:id="@+id/spinner"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+    </LinearLayout>
+    <Button
+        android:id="@android:id/text1"
+        style="@style/SupportPrimaryButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="8dp"/>
+    <Button
+        android:id="@android:id/text2"
+        style="@style/SupportSecondaryButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="16dp"
+        android:minHeight="48dp"/>
+</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0b8f351..c4ac8e3 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -7522,12 +7522,24 @@
         <xliff:g id="start_day">%s</xliff:g> - <xliff:g id="end_day">%s</xliff:g>, <xliff:g id="start_time">%s</xliff:g> - <xliff:g id="end_time">%s</xliff:g>&lt;br&gt;
     </string>
 
+    <!-- Button label for choosing country for phone support. [CHAR LIMIT=40]-->
+    <string name="support_country_list_title">Support for:</string>
+
+    <!-- Template for formatting country and language. eg Canada - French [CHAR LIMIT=NONE]-->
+    <string name="support_country_format"><xliff:g id="country" example="Canada">%s</xliff:g> - <xliff:g id="language" example="French">%s</xliff:g></string>
+
     <!-- Title text that indicates there is not internet connection. [CHAR LIMIT=80]-->
     <string name="support_offline_title">You\'re offline</string>
 
     <!-- Summary text telling user to connect to Internet in order to request customer support. [CHAR LIMIT=NONE]-->
     <string name="support_offline_summary">To reach support, first connect to Wi-Fi or data.</string>
 
+    <!-- Title text for a list of international support phone numbers. [CHAR LIMIT=60]-->
+    <string name="support_international_phone_title">Traveling aboard?</string>
+
+    <!-- Description text warning international phone charge may apply when dialing support numbers. [CHAR LIMIT=NONE]-->
+    <string name="support_international_phone_summary">International charges may apply</string>
+
     <!-- Button label for contacting customer support by phone [CHAR LIMIT=20]-->
     <string name="support_escalation_by_phone">Phone</string>
 
diff --git a/src/com/android/settings/dashboard/SupportItemAdapter.java b/src/com/android/settings/dashboard/SupportItemAdapter.java
index e76ca8b..94cc94b 100644
--- a/src/com/android/settings/dashboard/SupportItemAdapter.java
+++ b/src/com/android/settings/dashboard/SupportItemAdapter.java
@@ -28,7 +28,10 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
 import android.widget.ImageView;
+import android.widget.Spinner;
 import android.widget.TextView;
 
 import com.android.internal.logging.MetricsLogger;
@@ -36,6 +39,7 @@
 import com.android.settings.R;
 import com.android.settings.overlay.SupportFeatureProvider;
 import com.android.settings.support.SupportDisclaimerDialogFragment;
+import com.android.settings.support.SupportPhone;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -51,15 +55,19 @@
 
     private static final int TYPE_TITLE = R.layout.support_item_title;
     private static final int TYPE_ESCALATION_OPTIONS = R.layout.support_escalation_options;
+    private static final int TYPE_ESCALATION_OPTIONS_OFFLINE =
+            R.layout.support_offline_escalation_options;
     private static final int TYPE_SUPPORT_TILE = R.layout.support_tile;
     private static final int TYPE_SIGN_IN_BUTTON = R.layout.support_sign_in_button;
 
     private final Activity mActivity;
     private final EscalationClickListener mEscalationClickListener;
+    private final SpinnerItemSelectListener mSpinnerItemSelectListener;
     private final SupportFeatureProvider mSupportFeatureProvider;
     private final View.OnClickListener mItemClickListener;
     private final List<SupportData> mSupportData;
 
+    private String mSelectedCountry;
     private boolean mHasInternet;
     private Account mAccount;
 
@@ -69,6 +77,7 @@
         mSupportFeatureProvider = supportFeatureProvider;
         mItemClickListener = itemClickListener;
         mEscalationClickListener = new EscalationClickListener();
+        mSpinnerItemSelectListener = new SpinnerItemSelectListener();
         mSupportData = new ArrayList<>();
         // Optimistically assume we have Internet access. It will be updated later to correct value.
         mHasInternet = true;
@@ -92,6 +101,9 @@
             case TYPE_ESCALATION_OPTIONS:
                 bindEscalationOptions(holder, data);
                 break;
+            case TYPE_ESCALATION_OPTIONS_OFFLINE:
+                bindOfflineEscalationOptions(holder, (OfflineSupportData) data);
+                break;
             default:
                 bindSupportTile(holder, data);
                 break;
@@ -145,37 +157,32 @@
         mSupportData.clear();
         if (mAccount == null) {
             addSignInPromo();
-        } else {
+        } else if (mHasInternet) {
             addEscalationCards();
+        } else {
+            addOfflineEscalationCards();
         }
         addMoreHelpItems();
         notifyDataSetChanged();
     }
 
     private void addEscalationCards() {
-        if (mHasInternet) {
-            if (mSupportFeatureProvider.isAlwaysOperating(PHONE)
-                    || mSupportFeatureProvider.isAlwaysOperating(CHAT)) {
-                mSupportData.add(new SupportData.Builder(mActivity, TYPE_TITLE)
-                        .setText1(R.string.support_escalation_24_7_title)
-                        .setText2(mActivity.getString(R.string.support_escalation_24_7_summary))
-                        .build());
-            } else if (mSupportFeatureProvider.isOperatingNow(PHONE)
-                    || mSupportFeatureProvider.isOperatingNow(CHAT)) {
-                mSupportData.add(new SupportData.Builder(mActivity, TYPE_TITLE)
-                        .setText1(R.string.support_escalation_title)
-                        .setText2(R.string.support_escalation_summary)
-                        .build());
-            } else {
-                mSupportData.add(new SupportData.Builder(mActivity, TYPE_TITLE)
-                        .setText1(R.string.support_escalation_closed_title)
-                        .setText2(mSupportFeatureProvider.getOperationHours(mActivity, PHONE))
-                        .build());
-            }
+        if (mSupportFeatureProvider.isAlwaysOperating(PHONE)
+                || mSupportFeatureProvider.isAlwaysOperating(CHAT)) {
+            mSupportData.add(new SupportData.Builder(mActivity, TYPE_TITLE)
+                    .setText1(R.string.support_escalation_24_7_title)
+                    .setText2(mActivity.getString(R.string.support_escalation_24_7_summary))
+                    .build());
+        } else if (mSupportFeatureProvider.isOperatingNow(PHONE)
+                || mSupportFeatureProvider.isOperatingNow(CHAT)) {
+            mSupportData.add(new SupportData.Builder(mActivity, TYPE_TITLE)
+                    .setText1(R.string.support_escalation_title)
+                    .setText2(R.string.support_escalation_summary)
+                    .build());
         } else {
             mSupportData.add(new SupportData.Builder(mActivity, TYPE_TITLE)
-                    .setText1(R.string.support_offline_title)
-                    .setText2(R.string.support_offline_summary)
+                    .setText1(R.string.support_escalation_closed_title)
+                    .setText2(mSupportFeatureProvider.getOperationHours(mActivity, PHONE))
                     .build());
         }
         final SupportData.Builder builder =
@@ -193,6 +200,20 @@
         mSupportData.add(builder.build());
     }
 
+    private void addOfflineEscalationCards() {
+        mSupportData.add(new SupportData.Builder(mActivity, TYPE_TITLE)
+                .setText1(R.string.support_offline_title)
+                .setText2(R.string.support_offline_summary)
+                .build());
+        final OfflineSupportData.Builder builder = new OfflineSupportData.Builder(mActivity);
+        builder.setCountries(mSupportFeatureProvider.getPhoneSupportCountries())
+                .setTollFreePhone(mSupportFeatureProvider.getSupportPhones(
+                        mSelectedCountry, true /* isTollFree */))
+                .setTolledPhone(mSupportFeatureProvider.getSupportPhones(
+                        mSelectedCountry, false /* isTollFree */));
+        mSupportData.add(builder.build());
+    }
+
     private void addSignInPromo() {
         mSupportData.add(new SupportData.Builder(mActivity, TYPE_TITLE)
                 .setText1(R.string.support_sign_in_required_title)
@@ -246,6 +267,38 @@
         }
     }
 
+    private void bindOfflineEscalationOptions(ViewHolder holder, OfflineSupportData data) {
+        // Bind spinner
+        final Spinner spinner = (Spinner) holder.itemView.findViewById(R.id.spinner);
+        final ArrayAdapter<String> adapter = new ArrayAdapter(
+                mActivity, android.R.layout.simple_spinner_dropdown_item, data.countries);
+        spinner.setAdapter(adapter);
+        final List<String> countryCodes = mSupportFeatureProvider.getPhoneSupportCountryCodes();
+        for (int i = 0; i < countryCodes.size(); i++) {
+            if (TextUtils.equals(countryCodes.get(i), mSelectedCountry)) {
+                spinner.setSelection(i);
+                break;
+            }
+        }
+        spinner.setOnItemSelectedListener(mSpinnerItemSelectListener);
+        // Bind buttons
+        if (data.tollFreePhone != null) {
+            holder.text1View.setText(data.tollFreePhone.number);
+            holder.text1View.setVisibility(View.VISIBLE);
+            holder.text1View.setOnClickListener(mEscalationClickListener);
+        } else {
+            holder.text1View.setVisibility(View.GONE);
+        }
+        if (data.tolledPhone != null) {
+            holder.text2View.setText(
+                    mActivity.getString(R.string.support_international_phone_title));
+            holder.text2View.setVisibility(View.VISIBLE);
+            holder.text2View.setOnClickListener(mEscalationClickListener);
+        } else {
+            holder.text2View.setVisibility(View.GONE);
+        }
+    }
+
     private void bindSignInPromoTile(ViewHolder holder, SupportData data) {
         holder.text1View.setText(data.text1);
         holder.text2View.setText(data.text2);
@@ -299,7 +352,7 @@
                                 0 /* requestCode */);
                         break;
                 }
-            } else {
+            } else if (mHasInternet) {
                 switch (v.getId()) {
                     case android.R.id.text1:
                         MetricsLogger.action(mActivity,
@@ -312,10 +365,40 @@
                         tryStartDisclaimerAndSupport(CHAT);
                         break;
                 }
+            } else {
+                switch (v.getId()) {
+                    case android.R.id.text1:
+                        final SupportPhone phone = mSupportFeatureProvider
+                                .getSupportPhones(mSelectedCountry, true /* isTollFree */);
+                        if (phone != null) {
+                            mActivity.startActivity(phone.getDialIntent());
+                        }
+                        break;
+                    case android.R.id.text2:
+                        break;
+                }
             }
         }
     }
 
+    private final class SpinnerItemSelectListener implements AdapterView.OnItemSelectedListener {
+
+        @Override
+        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+            final List<String> countryCodes = mSupportFeatureProvider.getPhoneSupportCountryCodes();
+            final String selectedCountry = countryCodes.get(position);
+            if (!TextUtils.equals(selectedCountry, mSelectedCountry)) {
+                mSelectedCountry = selectedCountry;
+                refreshData();
+            }
+        }
+
+        @Override
+        public void onNothingSelected(AdapterView<?> parent) {
+            // Do nothing.
+        }
+    }
+
     /**
      * {@link RecyclerView.ViewHolder} for support items.
      */
@@ -340,7 +423,7 @@
     /**
      * Data for a single support item.
      */
-    private static final class SupportData {
+    private static class SupportData {
 
         final Intent intent;
         final int metricsEvent;
@@ -369,7 +452,7 @@
             this.metricsEvent = builder.mMetricsEvent;
         }
 
-        static final class Builder {
+        static class Builder {
 
             private final Context mContext;
             @LayoutRes
@@ -446,4 +529,51 @@
             }
         }
     }
+
+    /**
+     * Support data for offline mode.
+     */
+    private static final class OfflineSupportData extends SupportData {
+
+        final List<String> countries;
+        final SupportPhone tollFreePhone;
+        final SupportPhone tolledPhone;
+
+        private OfflineSupportData(Builder builder) {
+            super(builder);
+            countries = builder.mCountries;
+            tollFreePhone = builder.mTollFreePhone;
+            tolledPhone = builder.mTolledPhone;
+        }
+
+        static final class Builder extends SupportData.Builder {
+
+            private List<String> mCountries;
+            private SupportPhone mTollFreePhone;
+            private SupportPhone mTolledPhone;
+
+            Builder(Context context) {
+                super(context, TYPE_ESCALATION_OPTIONS_OFFLINE);
+            }
+
+            Builder setCountries(List<String> countries) {
+                mCountries = countries;
+                return this;
+            }
+
+            Builder setTollFreePhone(SupportPhone phone) {
+                mTollFreePhone = phone;
+                return this;
+            }
+
+            Builder setTolledPhone(SupportPhone phone) {
+                mTolledPhone = phone;
+                return this;
+            }
+
+            OfflineSupportData build() {
+                return new OfflineSupportData(this);
+            }
+        }
+    }
 }
diff --git a/src/com/android/settings/overlay/SupportFeatureProvider.java b/src/com/android/settings/overlay/SupportFeatureProvider.java
index 3c66910..df066ea 100644
--- a/src/com/android/settings/overlay/SupportFeatureProvider.java
+++ b/src/com/android/settings/overlay/SupportFeatureProvider.java
@@ -22,8 +22,11 @@
 import android.content.Context;
 import android.content.Intent;
 
+import com.android.settings.support.SupportPhone;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.List;
 
 /**
  * Feature provider for support tab.
@@ -68,6 +71,22 @@
      */
     String getEstimatedWaitTime(Context context, @SupportType int type);
 
+
+    /**
+     * Returns a list of country codes that have phone support.
+     */
+    List<String> getPhoneSupportCountryCodes();
+
+    /**
+     * Returns a list of countries that have phone support.
+     */
+    List<String> getPhoneSupportCountries();
+
+    /**
+     * Returns a support phone for specified country.
+     */
+    SupportPhone getSupportPhones(String countryCode, boolean isTollfree);
+
     /**
      * Whether or not a disclaimer dialog should be displayed.
      */
diff --git a/src/com/android/settings/support/SupportPhone.java b/src/com/android/settings/support/SupportPhone.java
new file mode 100644
index 0000000..6c8bf29
--- /dev/null
+++ b/src/com/android/settings/support/SupportPhone.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.support;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.text.TextUtils;
+
+import java.text.ParseException;
+
+/**
+ * Data model for a support phone number.
+ */
+public final class SupportPhone {
+
+    public final String language;
+    public final String number;
+    public final boolean isTollFree;
+
+    public SupportPhone(String config) throws ParseException {
+        // Config follows this format: language:[tollfree|tolled]:number
+        final String[] tokens = config.split(":");
+        if (tokens.length != 3) {
+            throw new ParseException("Phone config is invalid " + config, 0);
+        }
+        language = tokens[0];
+        isTollFree = TextUtils.equals(tokens[1], "tollfree");
+        number = tokens[2];
+    }
+
+    public Intent getDialIntent() {
+        return new Intent(Intent.ACTION_DIAL)
+                .setData(new Uri.Builder()
+                        .scheme("tel")
+                        .appendPath(number)
+                        .build());
+    }
+}