Remove support v1

Support v1 is no longer used and we want to keep the codebase clean.

Test: robotests still pass
Bug: 70620533
Change-Id: Ic8af0f34aab510a533bd7a7ec5c059834395baf5
This commit is contained in:
Salvador Martinez
2018-01-05 10:39:49 -08:00
parent efac313a9b
commit 616397d28c
24 changed files with 13 additions and 2270 deletions

View File

@@ -3104,13 +3104,6 @@
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.deletionhelper.AutomaticStorageManagerSettings" />
</activity>
<activity android:name="Settings$LegacySupportActivity"
android:label="@string/page_tab_title_support">
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.dashboard.SupportFragment"/>
</activity>
<!-- Information architecture host activities -->
<!-- Alias for battery settings in new IA. Remove and merge metadata into TargetActivity -->

View File

@@ -1,26 +0,0 @@
<?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.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
style="?android:attr/spinnerItemStyle"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textAlignment="inherit"/>

View File

@@ -1,39 +0,0 @@
<?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.
-->
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp">
<com.android.settingslib.widget.LinkTextView
android:id="@+id/support_disclaimer_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="24dp"/>
<CheckBox
android:id="@+id/support_disclaimer_do_not_show_again"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/support_disclaimer_do_not_show"
android:textColor="?android:attr/textColorSecondary"/>
</LinearLayout>
</ScrollView>

View File

@@ -1,101 +0,0 @@
<?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"
style="@style/SupportEscalationCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tile_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textAppearance="@style/TextAppearance.SupportTitle"/>
<TextView
android:id="@+id/tile_summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingTop="8dp"
android:paddingBottom="30dp"
android:textAppearance="?android:attr/textAppearanceSmall"/>
<TextView
android:id="@+id/account_request_prefix"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="@string/support_account_request_prefix"
android:textAppearance="?android:attr/textAppearanceSmall"/>
<Spinner
android:id="@+id/account_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginStart="16dp"
android:gravity="center_horizontal"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:gravity="center_horizontal"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:gravity="center_horizontal"
android:orientation="vertical">
<Button
android:id="@android:id/text1"
style="@style/ActionPrimaryButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"/>
<TextView
android:id="@+id/summary1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="14dp"
android:textAppearance="?android:attr/textAppearanceSmall"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:gravity="center_horizontal"
android:orientation="vertical">
<Button
android:id="@android:id/text2"
style="@style/ActionPrimaryButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"/>
<TextView
android:id="@+id/summary2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="14dp"
android:textAppearance="?android:attr/textAppearanceSmall"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@@ -1,31 +0,0 @@
<?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.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:focusable="false"
android:paddingStart="@dimen/dashboard_padding_start"
android:paddingEnd="@dimen/dashboard_padding_end">
<android.support.v7.widget.RecyclerView
android:id="@+id/support_items"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
</FrameLayout>

View File

@@ -1,71 +0,0 @@
<?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"
style="@style/SupportEscalationCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tile_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textAppearance="@style/TextAppearance.SupportTitle"/>
<TextView
android:id="@+id/tile_summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingTop="8dp"
android:paddingBottom="10dp"
android:textAppearance="@style/TextAppearance.Small"
android:textColor="?android:attr/textColorSecondary"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/support_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="8dp"
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"
android:dropDownWidth="196dp"/>
</LinearLayout>
<Button
android:id="@android:id/text1"
style="@style/ActionPrimaryButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layoutDirection="ltr"/>
<Button
android:id="@android:id/text2"
style="@style/SupportSecondaryButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:visibility="gone"/>
</LinearLayout>

View File

@@ -1,50 +0,0 @@
<?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:orientation="vertical"
android:paddingStart="24dp"
android:paddingEnd="24dp"
android:paddingTop="12dp"
android:paddingBottom="12dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
android:text="@string/support_international_phone_summary"/>
<LinearLayout
android:id="@+id/phone_number_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="48dp"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="32dp"
android:src="@drawable/ic_call_24dp"/>
<TextView
android:id="@+id/phone_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:textAppearance="@style/TextAppearance.TileTitle"/>
</LinearLayout>
</LinearLayout>

View File

@@ -1,52 +0,0 @@
<?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"
style="@style/SupportEscalationCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tile_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textAppearance="@style/TextAppearance.SupportTitle"/>
<TextView
android:id="@+id/tile_summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingTop="8dp"
android:paddingBottom="30dp"
android:textAppearance="@style/TextAppearance.Small"
android:textColor="?android:attr/textColorSecondary"/>
<Button
android:id="@android:id/text1"
style="@style/ActionPrimaryButton"
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>

View File

@@ -1,41 +0,0 @@
<?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="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="@dimen/support_tile_min_height"
android:orientation="horizontal">
<ImageView
android:id="@android:id/icon"
android:layout_width="@dimen/dashboard_tile_image_size"
android:layout_height="@dimen/dashboard_tile_image_size"
android:scaleType="centerInside"
android:layout_marginStart="@dimen/dashboard_tile_image_margin"
android:layout_marginEnd="@dimen/dashboard_tile_image_margin"/>
<TextView
android:id="@+id/tile_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
android:textAppearance="@style/TextAppearance.TileTitle"
android:ellipsize="end"
android:fadingEdge="horizontal"/>
</LinearLayout>

View File

@@ -1,21 +0,0 @@
<?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.
-->
<View
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/support_spacer_height"/>

View File

@@ -279,17 +279,8 @@
<dimen name="gestures_play_button_size">36dp</dimen>
<dimen name="gesture_animation_padding">0dp</dimen>
<!-- Support tile minimum height -->
<dimen name="support_tile_min_height">48dp</dimen>
<!-- support spacer layout height -->
<dimen name="support_spacer_height">8dp</dimen>
<dimen name="password_requirement_textsize">14sp</dimen>
<!-- Padding for the escalation card in normal dimens -->
<dimen name="support_escalation_card_padding_start">40dp</dimen>
<dimen name="support_escalation_card_padding_end">40dp</dimen>
<!-- Padding between the donut and the storage summary. -->
<dimen name="storage_summary_padding_end">16dp</dimen>
<!-- Text size of the big number in the donut. -->

View File

@@ -8643,93 +8643,6 @@
<!-- [CHAR LIMIT=60] Name of dev option to enable extra quick settings tiles -->
<string name="quick_settings_developer_tiles">Quick settings developer tiles</string>
<!-- Title text for connecting to customer support [CHAR LIMIT=80]-->
<string name="support_escalation_title">We\'re here to help</string>
<!-- Title text for connecting to 24/7 available customer support [CHAR LIMIT=80]-->
<string name="support_escalation_24_7_title">We\'re here for you 24/7</string>
<!-- Content description for connecting customer support. The "24 7" part indicates
support is available 24 hours a day, 7 days a week. It's used by screenreaders so it
cannot contain any symbol other that space. [CHAR LIMIT=80]-->
<string name="support_escalation_24_7_content_description">We\'re here for you 24 7</string>
<!-- Summary text for connecting to customer support [CHAR LIMIT=NONE]-->
<string name="support_escalation_summary">Our support team is here to help address any issue</string>
<!-- Summary text for connecting to 24/7 customer support [CHAR LIMIT=NONE]-->
<string name="support_escalation_24_7_summary">Our support team is available all day, every day</string>
<!-- Summary text when customer support is closed. [CHAR LIMIT=NONE]-->
<string name="support_escalation_closed_summary">Search help or come back during support hours (local time):&lt;br&gt;&lt;b&gt;<xliff:g id="operation_hours">%s</xliff:g>&lt;/b&gt;</string>
<!-- Summary text to call customer support when there is no internet. [CHAR LIMIT=NONE]-->
<string name="support_escalation_no_internet_summary">Phone support hours (local time)&lt;br&gt;&lt;b&gt;<xliff:g id="operation_hours">%s</xliff:g>&lt;/b&gt;</string>
<!-- Summary text when customer support is unavailable in the region. [CHAR LIMIT=NONE]-->
<string name="support_escalation_unavailable_summary">Search help or explore tips &amp; tricks</string>
<!-- Template for formatting support hours eg Mon - Fri, 8:00 AM - 19:30 PM. [CHAR LIMIT=NONE]-->
<string name="support_hour_format" translatable="false">
<xliff:g id="start_day">%1$s</xliff:g> - <xliff:g id="end_day">%2$s</xliff:g>, <xliff:g id="start_time">%3$s</xliff:g> - <xliff:g id="end_time">%4$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">%1$s</xliff:g> - <xliff:g id="language" example="French">%2$s</xliff:g></string>
<!-- Template for formatting phone number and language. eg English (800-000-0000) [CHAR LIMIT=NONE]-->
<string name ="support_phone_international_format">
<xliff:g id="language" example="English">%1$s</xliff:g> (<xliff:g id="phone" example="800-000-0000">%2$s</xliff:g>)
</string>
<!-- Title text for a list of international support phone numbers. [CHAR LIMIT=60]-->
<string name="support_international_phone_title">Traveling abroad?</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>
<!-- Button label for contacting customer support by chat [CHAR LIMIT=20]-->
<string name="support_escalation_by_chat">Chat</string>
<!-- Button label for visiting the tips & tricks site [CHAR LIMIT=60]-->
<string name="support_tips_and_tricks_title">Explore tips &amp; tricks</string>
<!-- Button label for visiting help and/or send feedback [CHAR LIMIT=60]-->
<string name="support_help_feedback_title">Search help &amp; send feedback</string>
<!-- Title text that indicates user needs to sign in to get customer support. [CHAR LIMIT=80]-->
<string name="support_sign_in_required_title">Contact support</string>
<!-- Summary text that indicates user needs to sign-in to get real time customer support. [CHAR LIMIT=NONE]-->
<string name="support_sign_in_required_summary" translatable="false"></string>
<!-- Button label for signing in an account [CHAR LIMIT=40]-->
<string name="support_sign_in_button_text">Sign in</string>
<!-- Button label that redirects user who needs help for signin to help screen [CHAR LIMIT=NONE]-->
<string name="support_sign_in_required_help">Can\'t sign in?</string>
<!-- Dialog title displayed before initiating real time support [CHAR LIMIT=80]-->
<string name="support_disclaimer_title">Send system information</string>
<!-- Checkbox text, when checked dialog will not show again [CHAR LIMIT=80] -->
<string name="support_disclaimer_do_not_show">Do not show again</string>
<!-- Prefix text for the account picker, e.g. "Requesting as user@gmail.com" [CHAR LIMIT=60] -->
<string name="support_account_request_prefix">Requesting as</string>
<!-- Spinner dropdown text, when selected will try to add account [CHAR LIMIT=60] -->
<string name="support_account_picker_add_account">Add account</string>
<!-- Title for the dialog containing system information shown [CHAR LIMIT=30] -->
<string name="support_system_information_title">System information</string>
<!-- [CHAR LIMIT=60] Title of work profile setting page -->
<string name="managed_profile_settings_title">Work profile settings</string>
<!-- [CHAR LIMIT=60] The preference title for enabling cross-profile remote contact search -->
@@ -8755,9 +8668,6 @@
<item quantity="other"><xliff:g id="number" example="7">%s</xliff:g> seconds</item>
</plurals>
<!-- Estimated wait time range for real time supports -->
<string name="support_estimated_wait_time">~<xliff:g id="ESTIMATE" example="2 minutes">%1$s</xliff:g> wait</string>
<!-- Used as title on the automatic storage manager settings. [CHAR LIMIT=60] -->
<string name="automatic_storage_manager_settings">Manage storage</string>

View File

@@ -330,19 +330,6 @@
<item name="android:textColor">?android:attr/colorError</item>
</style>
<style name="TextAppearance.SupportTitle"
parent="@android:style/TextAppearance.Material.Subhead">
<item name="android:textColor">?android:attr/colorAccent</item>
<item name="android:textSize">24sp</item>
</style>
<style name="TextAppearance.SupportSummary" parent="TextAppearance.CategoryTitle"/>
<style name="SupportSecondaryButton"
parent="android:Widget.DeviceDefault.Button.Borderless.Colored">
<item name="android:textSize">12sp</item>
</style>
<style name="FingerprintLayoutTheme">
<item name="android:icon">@drawable/ic_fingerprint_header</item>
</style>
@@ -386,14 +373,6 @@
<item name="android:textAppearance">@android:style/TextAppearance.Material.Subhead</item>
</style>
<style name="SupportEscalationCard">
<item name="android:background">?android:attr/colorSecondary</item>
<item name="android:gravity">center</item>
<item name="android:minHeight">368dp</item>
<item name="android:paddingStart">@dimen/support_escalation_card_padding_start</item>
<item name="android:paddingEnd">@dimen/support_escalation_card_padding_end</item>
</style>
<style name="FingerprintHeaderStyle" parent="android:style/TextAppearance.Material.Subhead">
<item name="android:paddingTop">16dp</item>
<item name="android:textColor">@color/primary_dark_material_light</item>

View File

@@ -162,7 +162,6 @@ public class Settings extends SettingsActivity {
}
}
public static class WebViewAppPickerActivity extends SettingsActivity { /* empty */ }
public static class LegacySupportActivity extends SettingsActivity{ /* empty */ }
// Top level categories for new IA
public static class NetworkDashboardActivity extends SettingsActivity {}

View File

@@ -59,7 +59,6 @@ import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
import com.android.settings.bluetooth.BluetoothSettings;
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragmentOld;
import com.android.settings.dashboard.SupportFragment;
import com.android.settings.datausage.DataPlanUsageSummary;
import com.android.settings.datausage.DataUsageList;
import com.android.settings.datausage.DataUsageSummary;
@@ -242,7 +241,6 @@ public class SettingsGateway {
NightDisplaySettings.class.getName(),
ManageDomainUrls.class.getName(),
AutomaticStorageManagerSettings.class.getName(),
SupportFragment.class.getName(),
StorageDashboardFragment.class.getName(),
SystemDashboardFragment.class.getName(),
NetworkDashboardFragment.class.getName(),

View File

@@ -1,164 +0,0 @@
/*
* 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.dashboard;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.OnAccountsUpdateListener;
import android.app.Activity;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.InstrumentedFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.overlay.SupportFeatureProvider;
import com.android.settingslib.utils.ThreadUtils;
/**
* Fragment for support tab in SettingsGoogle.
*/
public final class SupportFragment extends InstrumentedFragment implements View.OnClickListener,
OnAccountsUpdateListener {
private final ConnectivityManager.NetworkCallback mNetworkCallback =
new ConnectivityManager.NetworkCallback() {
@Override
public void onCapabilitiesChanged(Network network,
NetworkCapabilities capabilities) {
postConnectivityChanged();
}
@Override
public void onAvailable(Network network) {
postConnectivityChanged();
}
@Override
public void onLost(Network network) {
postConnectivityChanged();
}
};
private Activity mActivity;
private View mContent;
private RecyclerView mRecyclerView;
private SupportItemAdapter mSupportItemAdapter;
private AccountManager mAccountManager;
private SupportFeatureProvider mSupportFeatureProvider;
private ConnectivityManager mConnectivityManager;
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.SUPPORT_FRAGMENT;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
mActivity = getActivity();
mAccountManager = AccountManager.get(mActivity);
mSupportFeatureProvider =
FeatureFactory.getFactory(mActivity).getSupportFeatureProvider(mActivity);
mSupportItemAdapter = new SupportItemAdapter(mActivity, savedInstanceState,
mSupportFeatureProvider, mMetricsFeatureProvider, this /* itemClickListener */);
mConnectivityManager =
(ConnectivityManager) mActivity.getSystemService(Context.CONNECTIVITY_SERVICE);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mContent = inflater.inflate(R.layout.support_fragment, container, false);
mRecyclerView = (RecyclerView) mContent.findViewById(R.id.support_items);
mRecyclerView.setLayoutManager(new LinearLayoutManager(
getActivity(), LinearLayoutManager.VERTICAL, false /* reverseLayout */));
mRecyclerView.setAdapter(mSupportItemAdapter);
return mContent;
}
@Override
public void onResume() {
super.onResume();
// Monitor account change.
mAccountManager.addOnAccountsUpdatedListener(
this /* listener */, null /* handler */, true /* updateImmediately */);
// Monitor connectivity
mConnectivityManager.registerNetworkCallback(
new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build(),
mNetworkCallback);
mSupportItemAdapter.setHasInternet(hasInternet());
mSupportItemAdapter.refreshData();
}
@Override
public void onPause() {
super.onPause();
// Stop monitor account change.
mAccountManager.removeOnAccountsUpdatedListener(this /* listener */);
// Stop monitor connectivity.
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mSupportItemAdapter.onSaveInstanceState(outState);
}
@Override
public void onAccountsUpdated(Account[] accounts) {
// Account changed, update support items.
mSupportItemAdapter.setAccounts(
mSupportFeatureProvider.getSupportEligibleAccounts(mActivity));
}
@Override
public void onClick(View v) {
final SupportItemAdapter.ViewHolder vh =
(SupportItemAdapter.ViewHolder) mRecyclerView.getChildViewHolder(v);
mSupportItemAdapter.onItemClicked(vh.getAdapterPosition());
}
private void postConnectivityChanged() {
ThreadUtils.postOnMainThread(() -> {
if (mSupportItemAdapter != null) {
mSupportItemAdapter.setHasInternet(hasInternet());
}
});
}
private boolean hasInternet() {
final NetworkInfo activeNetwork = mConnectivityManager.getActiveNetworkInfo();
return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
}
}

View File

@@ -1,823 +0,0 @@
/*
* 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.dashboard;
import android.accounts.Account;
import android.annotation.DrawableRes;
import android.annotation.LayoutRes;
import android.annotation.StringRes;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.DialogFragment;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.VisibleForTesting;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
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.nano.MetricsProto;
import com.android.internal.util.ArrayUtils;
import com.android.settings.R;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.SupportFeatureProvider;
import com.android.settings.support.SupportDisclaimerDialogFragment;
import com.android.settings.support.SupportPhone;
import com.android.settings.support.SupportPhoneDialogFragment;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.android.settings.overlay.SupportFeatureProvider.SupportType.CHAT;
import static com.android.settings.overlay.SupportFeatureProvider.SupportType.PHONE;
/**
* Item adapter for support tiles.
*/
public final class SupportItemAdapter extends RecyclerView.Adapter<SupportItemAdapter.ViewHolder> {
private static final String STATE_SELECTED_COUNTRY = "STATE_SELECTED_COUNTRY";
private static final String ACCOUNT_SELECTED_INDEX = "ACCOUNT_SELECTED_INDEX";
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_SUPPORT_TILE_SPACER = R.layout.support_tile_spacer;
private static final int TYPE_SIGN_IN_BUTTON = R.layout.support_sign_in_button;
private final Activity mActivity;
private final EscalationClickListener mEscalationClickListener;
private final OfflineSpinnerItemSelectListener mOfflineSpinnerItemSelectListener;
private final OnlineSpinnerItemSelectListener mOnlineSpinnerItemSelectListener;
private final SupportFeatureProvider mSupportFeatureProvider;
private final MetricsFeatureProvider mMetricsFeatureProvider;
private final View.OnClickListener mItemClickListener;
private final List<SupportData> mSupportData;
private String mSelectedCountry;
private boolean mHasInternet;
private Account[] mAccounts;
private int mSelectedAccountIndex;
public SupportItemAdapter(Activity activity, Bundle savedInstanceState,
SupportFeatureProvider supportFeatureProvider,
MetricsFeatureProvider metricsFeatureProvider,
View.OnClickListener itemClickListener) {
mActivity = activity;
mSupportFeatureProvider = supportFeatureProvider;
mMetricsFeatureProvider = metricsFeatureProvider;
mItemClickListener = itemClickListener;
mEscalationClickListener = new EscalationClickListener();
mOfflineSpinnerItemSelectListener = new OfflineSpinnerItemSelectListener();
mOnlineSpinnerItemSelectListener = new OnlineSpinnerItemSelectListener();
mSupportData = new ArrayList<>();
// Optimistically assume we have Internet access. It will be updated later to correct value.
mHasInternet = true;
if (savedInstanceState != null) {
mSelectedCountry = savedInstanceState.getString(STATE_SELECTED_COUNTRY);
mSelectedAccountIndex = savedInstanceState.getInt(ACCOUNT_SELECTED_INDEX);
} else {
mSelectedCountry = mSupportFeatureProvider.getCurrentCountryCodeIfHasConfig(PHONE);
mSelectedAccountIndex = 0;
}
mAccounts = mSupportFeatureProvider.getSupportEligibleAccounts(mActivity);
refreshData();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(
viewType, parent, false));
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final SupportData data = mSupportData.get(position);
switch (holder.getItemViewType()) {
case TYPE_SIGN_IN_BUTTON:
bindSignInPromoTile(holder, (EscalationData) data);
break;
case TYPE_ESCALATION_OPTIONS:
bindEscalationOptions(holder, (EscalationData) data);
break;
case TYPE_ESCALATION_OPTIONS_OFFLINE:
bindOfflineEscalationOptions(holder, (OfflineEscalationData) data);
break;
case TYPE_SUPPORT_TILE_SPACER:
break;
default:
bindSupportTile(holder, data);
break;
}
}
@Override
public int getItemViewType(int position) {
return mSupportData.get(position).type;
}
@Override
public int getItemCount() {
return mSupportData.size();
}
/**
* Called when a support item is clicked.
*/
public void onItemClicked(int position) {
if (position >= 0 && position < mSupportData.size()) {
final SupportData data = mSupportData.get(position);
if (data.intent != null &&
mActivity.getPackageManager().resolveActivity(data.intent, 0) != null) {
if (data.metricsEvent >= 0) {
mMetricsFeatureProvider.action(mActivity, data.metricsEvent);
}
mActivity.startActivityForResult(data.intent, 0);
}
}
}
public void setHasInternet(boolean hasInternet) {
if (mHasInternet != hasInternet) {
mHasInternet = hasInternet;
refreshEscalationCards();
}
}
public void setAccounts(Account accounts[]) {
if (!Arrays.equals(mAccounts, accounts)) {
if (mAccounts.length == 0) {
mSelectedAccountIndex = 0;
} else {
final int index = ArrayUtils.indexOf(accounts, mAccounts[mSelectedAccountIndex]);
mSelectedAccountIndex = index != -1 ? index : 0;
}
mAccounts = accounts;
mSupportFeatureProvider.refreshOperationRules();
refreshEscalationCards();
}
}
public void onSaveInstanceState(Bundle outState) {
outState.putString(STATE_SELECTED_COUNTRY, mSelectedCountry);
outState.putInt(ACCOUNT_SELECTED_INDEX, mSelectedAccountIndex);
}
/**
* Create data for the adapter. If there is already data in the adapter, they will be
* destroyed and recreated.
*/
void refreshData() {
mSupportData.clear();
addEscalationCards();
addMoreHelpItems();
notifyDataSetChanged();
}
/**
* Adds 1 escalation card. Based on current phone state, the escalation card can display
* different content.
*/
private void addEscalationCards() {
if (mAccounts.length == 0) {
addSignInPromo();
} else if (mHasInternet) {
addOnlineEscalationCards();
} else {
addOfflineEscalationCards();
}
}
/**
* Finds and refreshes escalation card data.
*/
private void refreshEscalationCards() {
if (getItemCount() > 0) {
final int itemType = getItemViewType(0 /* position */);
if (itemType == TYPE_SIGN_IN_BUTTON
|| itemType == TYPE_ESCALATION_OPTIONS
|| itemType == TYPE_ESCALATION_OPTIONS_OFFLINE) {
mSupportData.remove(0 /* position */);
addEscalationCards();
notifyItemChanged(0 /* position */);
}
}
}
private void addOnlineEscalationCards() {
final boolean hasPhoneOperation =
mSupportFeatureProvider.isSupportTypeEnabled(mActivity, PHONE);
final boolean hasChatOperation =
mSupportFeatureProvider.isSupportTypeEnabled(mActivity, CHAT);
final EscalationData.Builder builder = new EscalationData.Builder(mActivity);
if (!hasPhoneOperation && !hasChatOperation) {
// No support at all.
builder.setTileTitle(R.string.support_escalation_title)
.setTileSummary(R.string.support_escalation_unavailable_summary);
} else if (mSupportFeatureProvider.isAlwaysOperating(PHONE, null /* countryCode */)
|| mSupportFeatureProvider.isAlwaysOperating(CHAT, null /* countryCode */)) {
// Support is available.
builder.setTileTitle(R.string.support_escalation_24_7_title)
.setTileTitleDescription(R.string.support_escalation_24_7_content_description)
.setTileSummary(mActivity.getString(R.string.support_escalation_24_7_summary));
} else if (mSupportFeatureProvider.isOperatingNow(PHONE)
|| mSupportFeatureProvider.isOperatingNow(CHAT)) {
// Support is available now.
builder.setTileTitle(R.string.support_escalation_title)
.setTileSummary(R.string.support_escalation_summary);
} else {
// Support is now temporarily unavailable.
builder.setTileTitle(R.string.support_escalation_title)
.setTileSummary(
mSupportFeatureProvider.getOperationHours(mActivity, PHONE, null,
true /* hasInternet */));
}
if (hasPhoneOperation) {
builder.setText1(R.string.support_escalation_by_phone)
.setSummary1(mSupportFeatureProvider.getEstimatedWaitTime(mActivity, PHONE))
.setEnabled1(mSupportFeatureProvider.isOperatingNow(PHONE));
}
if (hasChatOperation) {
builder.setText2(R.string.support_escalation_by_chat)
.setSummary2(mSupportFeatureProvider.getEstimatedWaitTime(mActivity, CHAT))
.setEnabled2(mSupportFeatureProvider.isOperatingNow(CHAT));
}
mSupportData.add(0 /* index */, builder.build());
}
private void addOfflineEscalationCards() {
final CharSequence operatingHours;
final boolean isPhoneSupportAlwaysOperating =
mSupportFeatureProvider.isAlwaysOperating(PHONE, mSelectedCountry);
if (isPhoneSupportAlwaysOperating) {
operatingHours = mActivity.getString(R.string.support_escalation_24_7_summary);
} else {
operatingHours = mSupportFeatureProvider.getOperationHours(mActivity,
PHONE, mSelectedCountry, false /* hasInternet */);
}
mSupportData.add(0 /* index */, new OfflineEscalationData.Builder(mActivity)
.setCountries(mSupportFeatureProvider.getPhoneSupportCountries())
.setTollFreePhone(mSupportFeatureProvider.getSupportPhones(
mSelectedCountry, true /* isTollFree */))
.setTolledPhone(mSupportFeatureProvider.getSupportPhones(
mSelectedCountry, false /* isTollFree */))
.setTileTitle(isPhoneSupportAlwaysOperating
? R.string.support_escalation_24_7_title
: R.string.support_escalation_title)
.setTileTitleDescription(isPhoneSupportAlwaysOperating
? R.string.support_escalation_24_7_content_description
: R.string.support_escalation_title)
.setTileSummary(operatingHours)
.build());
}
private void addSignInPromo() {
mSupportData.add(0 /* index */, new EscalationData.Builder(mActivity, TYPE_SIGN_IN_BUTTON)
.setText1(R.string.support_sign_in_button_text)
.setText2(R.string.support_sign_in_required_help)
.setTileTitle(R.string.support_sign_in_required_title)
.setTileSummary(R.string.support_sign_in_required_summary)
.build());
}
private void addMoreHelpItems() {
mSupportData.add(new SupportData.Builder(mActivity, TYPE_SUPPORT_TILE_SPACER).build());
PackageManager packageManager = mActivity.getPackageManager();
Intent intent = mSupportFeatureProvider.getHelpIntent(mActivity);
if (packageManager.resolveActivity(intent, 0) != null) {
mSupportData.add(new SupportData.Builder(mActivity, TYPE_SUPPORT_TILE)
.setIcon(R.drawable.ic_help_24dp)
.setTileTitle(R.string.support_help_feedback_title)
.setIntent(intent)
.setMetricsEvent(MetricsProto.MetricsEvent.ACTION_SUPPORT_HELP_AND_FEEDBACK)
.build());
}
intent = mSupportFeatureProvider.getTipsAndTricksIntent(mActivity);
if (packageManager.resolveActivity(intent, 0) != null) {
mSupportData.add(new SupportData.Builder(mActivity, TYPE_SUPPORT_TILE)
.setIcon(R.drawable.ic_lightbulb_outline_24)
.setTileTitle(R.string.support_tips_and_tricks_title)
.setIntent(intent)
.setMetricsEvent(MetricsProto.MetricsEvent.ACTION_SUPPORT_TIPS_AND_TRICKS)
.build());
}
}
private void bindEscalationOptions(ViewHolder holder, EscalationData data) {
holder.tileTitleView.setText(data.tileTitle);
holder.tileTitleView.setContentDescription(data.tileTitleDescription);
holder.tileSummaryView.setText(data.tileSummary);
if (data.text1 == 0) {
holder.text1View.setVisibility(View.GONE);
} else {
holder.text1View.setText(data.text1);
holder.text1View.setOnClickListener(mEscalationClickListener);
holder.text1View.setEnabled(data.enabled1 && mHasInternet);
holder.text1View.setVisibility(View.VISIBLE);
}
if (TextUtils.isEmpty(data.text2)) {
holder.text2View.setVisibility(View.GONE);
} else {
holder.text2View.setText(data.text2);
holder.text2View.setOnClickListener(mEscalationClickListener);
holder.text2View.setEnabled(data.enabled2 && mHasInternet);
holder.text2View.setVisibility(View.VISIBLE);
}
if (holder.summary1View != null) {
holder.summary1View.setText(data.summary1);
holder.summary1View.setVisibility(mHasInternet && !TextUtils.isEmpty(data.summary1)
? View.VISIBLE : View.GONE);
}
if (holder.summary2View != null) {
holder.summary2View.setText(data.summary2);
holder.summary2View.setVisibility(mHasInternet && !TextUtils.isEmpty(data.summary2)
? View.VISIBLE : View.GONE);
}
bindAccountPicker(holder);
}
@VisibleForTesting
public void bindAccountPicker(ViewHolder holder) {
final Spinner spinner = (Spinner) holder.itemView.findViewById(R.id.account_spinner);
final ArrayAdapter<String> adapter = new ArrayAdapter(
mActivity, R.layout.support_account_spinner_item,
extractAccountNames(mAccounts));
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(mOnlineSpinnerItemSelectListener);
spinner.setSelection(mSelectedAccountIndex);
}
private void bindOfflineEscalationOptions(ViewHolder holder, OfflineEscalationData data) {
// Bind Title
holder.tileTitleView.setText(data.tileTitle);
holder.tileTitleView.setContentDescription(data.tileTitleDescription);
holder.tileSummaryView.setText(data.tileSummary);
// 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(mOfflineSpinnerItemSelectListener);
// 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);
}
if (ActivityManager.isUserAMonkey()) {
holder.text1View.setVisibility(View.GONE);
holder.text2View.setVisibility(View.GONE);
spinner.setVisibility(View.GONE);
holder.itemView.findViewById(R.id.support_text).setVisibility(View.GONE);
}
}
private void bindSignInPromoTile(ViewHolder holder, EscalationData data) {
holder.tileTitleView.setText(data.tileTitle);
holder.tileTitleView.setContentDescription(data.tileTitleDescription);
holder.tileSummaryView.setText(data.tileSummary);
holder.text1View.setText(data.text1);
holder.text2View.setText(data.text2);
holder.text1View.setOnClickListener(mEscalationClickListener);
holder.text2View.setOnClickListener(mEscalationClickListener);
}
private void bindSupportTile(ViewHolder holder, SupportData data) {
if (holder.iconView != null) {
holder.iconView.setImageResource(data.icon);
}
if (holder.tileTitleView != null) {
holder.tileTitleView.setText(data.tileTitle);
holder.tileTitleView.setContentDescription(data.tileTitleDescription);
}
if (holder.tileSummaryView != null) {
holder.tileSummaryView.setText(data.tileSummary);
}
holder.itemView.setOnClickListener(mItemClickListener);
}
/**
* Show a disclaimer dialog and start support action after disclaimer has been acknowledged.
*/
private void tryStartDisclaimerAndSupport(final @SupportFeatureProvider.SupportType int type) {
if (mSupportFeatureProvider.shouldShowDisclaimerDialog(mActivity)) {
DialogFragment fragment = SupportDisclaimerDialogFragment.newInstance(
mAccounts[mSelectedAccountIndex], type);
fragment.show(mActivity.getFragmentManager(), SupportDisclaimerDialogFragment.TAG);
return;
}
mSupportFeatureProvider.startSupport(mActivity, mAccounts[mSelectedAccountIndex], type);
}
private String[] extractAccountNames(Account[] accounts) {
String[] accountNames = new String[accounts.length+1];
for (int i = 0; i < accounts.length; i++) {
accountNames[i] = accounts[i].name;
}
accountNames[accounts.length] = mActivity.getString(
R.string.support_account_picker_add_account);
return accountNames;
}
/**
* Click handler for starting escalation options.
*/
private final class EscalationClickListener implements View.OnClickListener {
@Override
public void onClick(final View v) {
if (mAccounts.length == 0) {
switch (v.getId()) {
case android.R.id.text1:
mMetricsFeatureProvider.action(mActivity,
MetricsProto.MetricsEvent.ACTION_SUPPORT_SIGN_IN);
mActivity.startActivityForResult(
mSupportFeatureProvider.getAccountLoginIntent(),
0 /* requestCode */);
break;
case android.R.id.text2:
mActivity.startActivityForResult(
mSupportFeatureProvider.getSignInHelpIntent(mActivity),
0 /* requestCode */);
break;
}
} else if (mHasInternet) {
switch (v.getId()) {
case android.R.id.text1:
mMetricsFeatureProvider.action(mActivity,
MetricsProto.MetricsEvent.ACTION_SUPPORT_PHONE);
tryStartDisclaimerAndSupport(PHONE);
break;
case android.R.id.text2:
mMetricsFeatureProvider.action(mActivity,
MetricsProto.MetricsEvent.ACTION_SUPPORT_CHAT);
tryStartDisclaimerAndSupport(CHAT);
break;
}
} else {
switch (v.getId()) {
case android.R.id.text1: {
final SupportPhone phone = mSupportFeatureProvider
.getSupportPhones(mSelectedCountry, true /* isTollFree */);
if (phone != null) {
final Intent intent = phone.getDialIntent();
final boolean canDial = !mActivity.getPackageManager()
.queryIntentActivities(intent, 0)
.isEmpty();
if (canDial) {
mMetricsFeatureProvider.action(mActivity,
MetricsProto.MetricsEvent.ACTION_SUPPORT_DAIL_TOLLFREE);
mActivity.startActivity(intent);
}
}
break;
}
case android.R.id.text2: {
final SupportPhone phone = mSupportFeatureProvider
.getSupportPhones(mSelectedCountry, false /* isTollFree */);
final SupportPhoneDialogFragment fragment =
SupportPhoneDialogFragment.newInstance(phone);
mMetricsFeatureProvider.action(mActivity,
MetricsProto.MetricsEvent.ACTION_SUPPORT_VIEW_TRAVEL_ABROAD_DIALOG);
fragment.show(mActivity.getFragmentManager(),
SupportPhoneDialogFragment.TAG);
break;
}
}
}
}
}
private final class OfflineSpinnerItemSelectListener
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;
refreshEscalationCards();
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// Do nothing.
}
}
private final class OnlineSpinnerItemSelectListener
implements AdapterView.OnItemSelectedListener {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (position == mAccounts.length) {
mActivity.startActivity(mSupportFeatureProvider.getAccountLoginIntent());
// Make sure "Add account" is not shown as selected item
parent.setSelection(mSelectedAccountIndex);
} else if (position != mSelectedAccountIndex) {
mSelectedAccountIndex = position;
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// Do nothing.
}
}
/**
* {@link RecyclerView.ViewHolder} for support items.
*/
static final class ViewHolder extends RecyclerView.ViewHolder {
final ImageView iconView;
final TextView tileTitleView;
final TextView tileSummaryView;
final TextView text1View;
final TextView text2View;
final TextView summary1View;
final TextView summary2View;
ViewHolder(View itemView) {
super(itemView);
iconView = (ImageView) itemView.findViewById(android.R.id.icon);
tileTitleView = (TextView) itemView.findViewById(R.id.tile_title);
tileSummaryView = (TextView) itemView.findViewById(R.id.tile_summary);
text1View = (TextView) itemView.findViewById(android.R.id.text1);
text2View = (TextView) itemView.findViewById(android.R.id.text2);
summary1View = (TextView) itemView.findViewById(R.id.summary1);
summary2View = (TextView) itemView.findViewById(R.id.summary2);
}
}
/**
* Data for a single support item.
*/
@VisibleForTesting
static class SupportData {
final Intent intent;
final int metricsEvent;
@LayoutRes
final int type;
@DrawableRes
final int icon;
@StringRes
final int tileTitle;
final CharSequence tileTitleDescription;
final CharSequence tileSummary;
private SupportData(Builder builder) {
this.type = builder.mType;
this.icon = builder.mIcon;
this.tileTitle = builder.mTileTitle;
this.tileTitleDescription = builder.mTileTitleDescription;
this.tileSummary = builder.mTileSummary;
this.intent = builder.mIntent;
this.metricsEvent = builder.mMetricsEvent;
}
static class Builder {
protected final Context mContext;
@LayoutRes
private final int mType;
@DrawableRes
private int mIcon;
@StringRes
private int mTileTitle;
private CharSequence mTileTitleDescription;
private CharSequence mTileSummary;
private Intent mIntent;
private int mMetricsEvent = -1;
Builder(Context context, @LayoutRes int type) {
mContext = context;
mType = type;
}
Builder setIcon(@DrawableRes int icon) {
mIcon = icon;
return this;
}
Builder setTileTitle(@StringRes int title) {
mTileTitle = title;
return this;
}
Builder setTileTitleDescription(@StringRes int titleDescription) {
mTileTitleDescription = mContext.getString(titleDescription);
return this;
}
Builder setTileSummary(@StringRes int summary) {
mTileSummary = mContext.getString(summary);
return this;
}
Builder setTileSummary(CharSequence summary) {
mTileSummary = summary;
return this;
}
Builder setMetricsEvent(int metricsEvent) {
mMetricsEvent = metricsEvent;
return this;
}
Builder setIntent(Intent intent) {
mIntent = intent;
return this;
}
SupportData build() {
return new SupportData(this);
}
}
}
/**
* Data model for escalation cards.
*/
@VisibleForTesting
static class EscalationData extends SupportData {
@StringRes
final int text1;
final CharSequence text2;
final boolean enabled1;
final boolean enabled2;
final CharSequence summary1;
final CharSequence summary2;
private EscalationData(Builder builder) {
super(builder);
this.text1 = builder.mText1;
this.text2 = builder.mText2;
this.summary1 = builder.mSummary1;
this.summary2 = builder.mSummary2;
this.enabled1 = builder.mEnabled1;
this.enabled2 = builder.mEnabled2;
}
static class Builder extends SupportData.Builder {
@StringRes
private int mText1;
private CharSequence mText2;
private CharSequence mSummary1;
private CharSequence mSummary2;
private boolean mEnabled1;
private boolean mEnabled2;
protected Builder(Context context, @LayoutRes int type) {
super(context, type);
}
Builder(Context context) {
this(context, TYPE_ESCALATION_OPTIONS);
}
Builder setEnabled1(boolean enabled) {
mEnabled1 = enabled;
return this;
}
Builder setText1(@StringRes int text1) {
mText1 = text1;
return this;
}
Builder setText2(@StringRes int text2) {
mText2 = mContext.getString(text2);
return this;
}
Builder setText2(CharSequence text2) {
mText2 = text2;
return this;
}
Builder setSummary1(String summary1) {
mSummary1 = summary1;
return this;
}
Builder setEnabled2(boolean enabled) {
mEnabled2 = enabled;
return this;
}
Builder setSummary2(String summary2) {
mSummary2 = summary2;
return this;
}
EscalationData build() {
return new EscalationData(this);
}
}
}
/**
* Support data for offline mode.
*/
private static final class OfflineEscalationData extends EscalationData {
final List<String> countries;
final SupportPhone tollFreePhone;
final SupportPhone tolledPhone;
private OfflineEscalationData(Builder builder) {
super(builder);
countries = builder.mCountries;
tollFreePhone = builder.mTollFreePhone;
tolledPhone = builder.mTolledPhone;
}
static final class Builder extends EscalationData.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;
}
OfflineEscalationData build() {
return new OfflineEscalationData(this);
}
}
}
@VisibleForTesting
List<SupportData> getSupportData() {
return mSupportData;
}
}

View File

@@ -45,89 +45,27 @@ public interface SupportFeatureProvider {
int CHAT = 3;
}
/**
* Returns a intent that will open help & feedback.
*/
Intent getHelpIntent(Context context);
/**
* Whether or not a support type is enabled.
*/
boolean isSupportTypeEnabled(Context context, @SupportType int type);
/**
* Refreshes all operation rules.
*/
void refreshOperationRules();
/**
* Whether or not a support type is in operation 24/7. If country is null, use
* current country.
*/
boolean isAlwaysOperating(@SupportType int type, String countryCode);
/**
* Whether or not a support type is operating now.
*/
boolean isOperatingNow(@SupportType int type);
/**
* Returns the current country code if it has a operation config, otherwise returns null.
*/
String getCurrentCountryCodeIfHasConfig(@SupportType int type);
/**
* Returns localized string for operation hours in specified country. If country is null, use
* current country to figure out operation hours.
*/
CharSequence getOperationHours(Context context, @SupportType int type, String countryCode,
boolean hasInternet);
/**
* Returns a localized string indicating estimated wait time for a support time.
*/
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.
*/
boolean shouldShowDisclaimerDialog(Context context);
/**
* Sets whether or not a disclaimer dialog should be displayed.
*/
void setShouldShowDisclaimerDialog(Context context, boolean shouldShow);
/**
* Returns array of {@link Account} that's eligible for support options.
*/
@NonNull
Account[] getSupportEligibleAccounts(Context context);
/**
* Starts support activity of specified type
*
* @param activity Calling activity
* @param account A account that selected by user
* @param type The type of support account needs.
*/
void startSupport(Activity activity, Account account, @SupportType int type);
/**
* Starts support v2, invokes the support home page. Will no-op if support v2 is not enabled.
*
@@ -135,39 +73,6 @@ public interface SupportFeatureProvider {
*/
void startSupportV2(Activity activity);
/**
* Checks if support v2 is enabled for this device.
*
* @return a boolean indicating if support v2 is enabled.
*/
boolean isSupportV2Enabled();
/**
* Returns an {@link Intent} that opens help and allow user get help on sign in.
*/
Intent getSignInHelpIntent(Context context);
/**
* Returns an intent that will start the add account UI.
*/
Intent getAccountLoginIntent();
/**
* Returns an intent that will launch the tips and tricks UI.
*/
Intent getTipsAndTricksIntent(Context context);
/**
* Returns the string for the disclaimer in the Support dialog.
*/
@StringRes
int getDisclaimerStringResId();
/**
* launches the fragment that displays the system information being sent to support agents.
*/
void launchSystemInfoFragment(Bundle args, FragmentManager manager);
/**
* Returns a url with information to introduce user to new device.
*/

View File

@@ -21,7 +21,6 @@ import android.content.Intent;
import android.os.Bundle;
import com.android.settings.R;
import com.android.settings.Settings.LegacySupportActivity;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.overlay.SupportFeatureProvider;
import com.android.settings.search.BaseSearchIndexProvider;
@@ -43,12 +42,10 @@ public class SupportDashboardActivity extends Activity implements Indexable {
.getSupportFeatureProvider(this);
// try to launch support v2 if we have the feature provider
if (supportFeatureProvider != null && supportFeatureProvider.isSupportV2Enabled()) {
supportFeatureProvider.startSupportV2(this);
} else {
startActivity(new Intent(this, LegacySupportActivity.class));
if (supportFeatureProvider != null) {
supportFeatureProvider.startSupportV2(this);
finish();
}
finish();
}
/**

View File

@@ -1,222 +0,0 @@
/*
* 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.accounts.Account;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.os.Bundle;
import android.text.Annotation;
import android.text.Spannable;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.style.URLSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.overlay.SupportFeatureProvider;
/**
* {@link DialogFragment} for support disclaimer.
*/
public final class SupportDisclaimerDialogFragment extends InstrumentedDialogFragment
implements DialogInterface.OnClickListener {
public static final String TAG = "SupportDisclaimerDialog";
public static final String EXTRA_TYPE = "extra_type";
public static final String EXTRA_ACCOUNT = "extra_account";
public static SupportDisclaimerDialogFragment newInstance(Account account,
@SupportFeatureProvider.SupportType int type) {
final SupportDisclaimerDialogFragment fragment = new SupportDisclaimerDialogFragment();
final Bundle bundle = new Bundle(2);
bundle.putParcelable(SupportDisclaimerDialogFragment.EXTRA_ACCOUNT, account);
bundle.putInt(SupportDisclaimerDialogFragment.EXTRA_TYPE, type);
fragment.setArguments(bundle);
return fragment;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
.setTitle(R.string.support_disclaimer_title)
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, this);
final View content = LayoutInflater.from(builder.getContext())
.inflate(R.layout.support_disclaimer_content, null);
final TextView disclaimer = (TextView) content.findViewById(R.id.support_disclaimer_text);
final Activity activity = getActivity();
final SupportFeatureProvider supportFeatureProvider =
FeatureFactory.getFactory(activity).getSupportFeatureProvider(activity);
// sets the two links that go to privacy policy and terms of service
disclaimer.setText(supportFeatureProvider.getDisclaimerStringResId());
Spannable viewText = (Spannable) disclaimer.getText();
stripUnderlines(viewText);
SystemInformationSpan.linkify(viewText, this);
// sets the link that launches a dialog to expose the signals we are sending
return builder
.setView(content)
.create();
}
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == Dialog.BUTTON_NEGATIVE) {
mMetricsFeatureProvider.action(getContext(),
MetricsProto.MetricsEvent.ACTION_SUPPORT_DISCLAIMER_CANCEL);
return;
}
final Activity activity = getActivity();
final CheckBox doNotShow =
(CheckBox) getDialog().findViewById(R.id.support_disclaimer_do_not_show_again);
final boolean isChecked = doNotShow.isChecked();
final SupportFeatureProvider supportFeatureProvider =
FeatureFactory.getFactory(activity).getSupportFeatureProvider(activity);
supportFeatureProvider.setShouldShowDisclaimerDialog(getContext(), !isChecked);
final Bundle bundle = getArguments();
if (isChecked) {
mMetricsFeatureProvider.action(activity,
MetricsProto.MetricsEvent.ACTION_SKIP_DISCLAIMER_SELECTED);
}
mMetricsFeatureProvider.action(activity,
MetricsProto.MetricsEvent.ACTION_SUPPORT_DISCLAIMER_OK);
supportFeatureProvider.startSupport(getActivity(),
bundle.getParcelable(EXTRA_ACCOUNT), bundle.getInt(EXTRA_TYPE));
}
@Override
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
mMetricsFeatureProvider.action(getContext(),
MetricsProto.MetricsEvent.ACTION_SUPPORT_DISCLAIMER_CANCEL);
}
/**
* Removes the underlines of {@link android.text.style.URLSpan}s.
*/
private static void stripUnderlines(Spannable input) {
final URLSpan[] urls = input.getSpans(0, input.length(), URLSpan.class);
for (URLSpan span : urls) {
final int start = input.getSpanStart(span);
final int end = input.getSpanEnd(span);
if (!TextUtils.isEmpty(span.getURL())) {
input.removeSpan(span);
input.setSpan(new NoUnderlineUrlSpan(span.getURL()), start, end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.DIALOG_SUPPORT_DISCLAIMER;
}
/**
* A {@link URLSpan} that doesn't decorate the link with underline.
*/
public static class NoUnderlineUrlSpan extends URLSpan {
public NoUnderlineUrlSpan(String url) {
super(url);
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
}
}
/**
* A {@link URLSpan} that opens a dialog when clicked
*/
public static class SystemInformationSpan extends URLSpan {
private static final String ANNOTATION_URL = "url";
private final DialogFragment mDialog;
private SupportFeatureProvider mSupport;
public SystemInformationSpan(DialogFragment parent) {
// sets the url to empty string so we can prevent the NoUnderlineUrlSpan from stripping
// this one
super("");
mSupport = FeatureFactory.getFactory(parent.getContext())
.getSupportFeatureProvider(parent.getContext());
mDialog = parent;
}
@Override
public void onClick(View widget) {
Activity activity = mDialog.getActivity();
if (mSupport != null && activity != null) {
// launch the system info fragment
mSupport.launchSystemInfoFragment(mDialog.getArguments(),
activity.getFragmentManager());
// dismiss this fragment
mDialog.dismiss();
}
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
// remove underline
ds.setUnderlineText(false);
}
/**
* This method takes a string and turns it into a url span that will launch a
* SupportSystemInformationDialogFragment
* @param msg The text to turn into a link
* @param parent The dialog the text is in
* @return A CharSequence containing the original text content as a url
*/
public static CharSequence linkify(Spannable msg, DialogFragment parent) {
Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class);
for (Annotation annotation : spans) {
int start = msg.getSpanStart(annotation);
int end = msg.getSpanEnd(annotation);
if (ANNOTATION_URL.equals(annotation.getValue())) {
SystemInformationSpan link = new SystemInformationSpan(parent);
msg.removeSpan(annotation);
msg.setSpan(link, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
return msg;
}
@VisibleForTesting
public void setSupportProvider(SupportFeatureProvider prov) {
mSupport = prov;
}
}
}

View File

@@ -1,89 +0,0 @@
/*
* 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.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import java.util.Locale;
/**
* A dialog fragment that displays support phone numbers.
*/
public final class SupportPhoneDialogFragment extends InstrumentedDialogFragment
implements View.OnClickListener {
public static final String TAG = "SupportPhoneDialog";
private static final String EXTRA_PHONE = "extra_phone";
public static SupportPhoneDialogFragment newInstance(SupportPhone phone) {
final SupportPhoneDialogFragment fragment = new SupportPhoneDialogFragment();
final Bundle bundle = new Bundle(2);
bundle.putParcelable(EXTRA_PHONE, phone);
fragment.setArguments(bundle);
return fragment;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final SupportPhone phone = getArguments().getParcelable(EXTRA_PHONE);
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
.setTitle(R.string.support_international_phone_title);
final View content = LayoutInflater.from(builder.getContext())
.inflate(R.layout.support_phone_dialog_content, null);
final View phoneNumberContainer = content.findViewById(R.id.phone_number_container);
final TextView phoneView = (TextView) content.findViewById(R.id.phone_number);
final String formattedPhoneNumber = getContext().getString(
R.string.support_phone_international_format,
new Locale(phone.language).getDisplayLanguage(), phone.number);
phoneView.setText(formattedPhoneNumber);
phoneNumberContainer.setOnClickListener(this);
return builder
.setView(content)
.create();
}
@Override
public void onClick(View v) {
final SupportPhone phone = getArguments().getParcelable(EXTRA_PHONE);
final Activity activity = getActivity();
final Intent intent = phone.getDialIntent();
final boolean canDial = !activity.getPackageManager()
.queryIntentActivities(intent, 0)
.isEmpty();
if (canDial) {
mMetricsFeatureProvider.action(getActivity(),
MetricsProto.MetricsEvent.ACTION_SUPPORT_DIAL_TOLLED);
getActivity().startActivity(intent);
}
dismiss();
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.DIALOG_SUPPORT_PHONE;
}
}

View File

@@ -17,10 +17,11 @@
package com.android.settings.dashboard;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.dashboard.SupportItemAdapter.ViewHolder;
import com.android.settingslib.drawer.Tile;
import org.junit.Before;
import org.junit.Test;
@@ -68,4 +69,12 @@ public class DashboardItemAnimatorTest {
.animateChange(mViewHolder, mViewHolder, 0, 1, 0, 1);
assertThat(hasPendingAnimation).isFalse();
}
// Sample viewholder to use for test
static final class ViewHolder extends RecyclerView.ViewHolder {
ViewHolder(View itemView) {
super(itemView);
}
}
}

View File

@@ -1,189 +0,0 @@
/*
* 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.dashboard;
import android.accounts.Account;
import android.app.Activity;
import android.content.Intent;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.SupportItemAdapter.EscalationData;
import com.android.settings.overlay.SupportFeatureProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowActivity;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class SupportItemAdapterTest {
private static final String ACCOUNT_TYPE = "com.google";
private final Account USER_1 = new Account("user1", ACCOUNT_TYPE);
private final Account USER_2 = new Account("user2", ACCOUNT_TYPE);
private final Account TWO_ACCOUNTS[] = {USER_1, USER_2};
private final Account ONE_ACCOUNT[] = {USER_1};
private final Account ZERO_ACCOUNT[] = {};
private ShadowActivity mShadowActivity;
private Activity mActivity;
private SupportItemAdapter mSupportItemAdapter;
private SupportItemAdapter.ViewHolder mViewHolder;
@Mock
private SupportFeatureProvider mSupportFeatureProvider;
@Mock
private MetricsFeatureProvider mMetricsFeatureProvider;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mActivity = Robolectric.setupActivity(Activity.class);
mShadowActivity = shadowOf(mActivity);
final View itemView = LayoutInflater.from(mActivity).inflate(
R.layout.support_escalation_options, null);
mViewHolder = new SupportItemAdapter.ViewHolder(itemView);
// Mock this to prevent crash in testing
when(mSupportFeatureProvider.getAccountLoginIntent()).thenReturn(
new Intent(Settings.ACTION_ADD_ACCOUNT));
}
@Test
public void testBindAccountPicker_TwoAccounts_ShouldHaveTwoAccounts() {
testBindAccountPickerInner(mViewHolder, TWO_ACCOUNTS);
}
@Test
public void testBindAccountPicker_OneAccount_ShouldHaveOneAccount() {
testBindAccountPickerInner(mViewHolder, ONE_ACCOUNT);
}
@Test
public void testOnSpinnerItemClick_AddAccountClicked_AccountLoginIntentInvoked() {
bindAccountPickerInner(mViewHolder, TWO_ACCOUNTS);
final Spinner spinner = (Spinner) mViewHolder.itemView.findViewById(R.id.account_spinner);
spinner.setSelection(TWO_ACCOUNTS.length);
Robolectric.flushForegroundThreadScheduler();
verify(mSupportFeatureProvider).getAccountLoginIntent();
}
@Test
public void testSetAccount_AccountEmpty_NotCrash() {
when(mSupportFeatureProvider.getSupportEligibleAccounts(mActivity)).thenReturn(
ZERO_ACCOUNT);
mSupportItemAdapter = new SupportItemAdapter(mActivity, null, mSupportFeatureProvider,
mMetricsFeatureProvider, null);
// Should not crash in this method
mSupportItemAdapter.setAccounts(ONE_ACCOUNT);
verify(mSupportFeatureProvider).getSupportEligibleAccounts(mActivity);
}
@Test
public void testRefreshData_CardUpdatedOnEnteringOrLeavingSupportHours() {
// pretend we have support right now
when(mSupportFeatureProvider.isSupportTypeEnabled(any(), anyInt()))
.thenReturn(true);
when(mSupportFeatureProvider.isOperatingNow(anyInt())).thenReturn(true);
when(mSupportFeatureProvider.getSupportEligibleAccounts(any())).thenReturn(ONE_ACCOUNT);
mSupportItemAdapter = new SupportItemAdapter(mActivity, null, mSupportFeatureProvider,
mMetricsFeatureProvider, null);
// If this doesn't return escalation data something has gone wrong
EscalationData data = (EscalationData) mSupportItemAdapter.getSupportData().get(0);
// precondition, support is enabled
assertThat(data.enabled1).isTrue();
// pretend we support hours are over
when(mSupportFeatureProvider.isOperatingNow(anyInt())).thenReturn(false);
mSupportItemAdapter.refreshData();
data = (EscalationData) mSupportItemAdapter.getSupportData().get(0);
assertThat(data.enabled1).isFalse();
// pretend support hours have started again
when(mSupportFeatureProvider.isOperatingNow(anyInt())).thenReturn(true);
mSupportItemAdapter.refreshData();
data = (EscalationData) mSupportItemAdapter.getSupportData().get(0);
assertThat(data.enabled1).isTrue();
}
/**
* Check after {@link SupportItemAdapter#bindAccountPicker(SupportItemAdapter.ViewHolder)} is
* invoked, whether the spinner in {@paramref viewHolder} has all the data from {@paramref
* accounts}
*
* @param viewHolder holds the view that contains the spinner to test
* @param accounts holds the accounts info to be showed in spinner.
*/
private void testBindAccountPickerInner(SupportItemAdapter.ViewHolder viewHolder,
Account accounts[]) {
bindAccountPickerInner(viewHolder, accounts);
final Spinner spinner = (Spinner) viewHolder.itemView.findViewById(R.id.account_spinner);
final SpinnerAdapter adapter = spinner.getAdapter();
// Contains "Add account" option, so should be 'count+1'
assertThat(adapter.getCount()).isEqualTo(accounts.length + 1);
for (int i = 0; i < accounts.length; i++) {
assertThat(adapter.getItem(i)).isEqualTo(accounts[i].name);
}
}
/**
* Create {@link SupportItemAdapter} and bind the account picker view into
* {@paramref viewholder}
*
* @param viewHolder holds the view that contains the spinner to test
* @param accounts holds the accounts info to be showed in spinner.
*/
private void bindAccountPickerInner(SupportItemAdapter.ViewHolder viewHolder,
Account accounts[]) {
when(mSupportFeatureProvider.getSupportEligibleAccounts(mActivity)).thenReturn(accounts);
mSupportItemAdapter = new SupportItemAdapter(mActivity, null, mSupportFeatureProvider,
mMetricsFeatureProvider, null);
mSupportItemAdapter.bindAccountPicker(viewHolder);
}
}

View File

@@ -1,119 +0,0 @@
package com.android.settings.support;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.shadow.api.Shadow.directlyOn;
import android.accounts.Account;
import android.annotation.NonNull;
import android.annotation.StringRes;
import android.app.Dialog;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.text.Spannable;
import android.text.style.URLSpan;
import android.widget.CheckBox;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.SupportFeatureProvider;
import com.android.settings.overlay.SupportFeatureProvider.SupportType;
import com.android.settings.support.SupportDisclaimerDialogFragmentTest.SupportDisclaimerShadowResources;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.util.FragmentTestUtil;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
shadows = {SupportDisclaimerShadowResources.class})
public class SupportDisclaimerDialogFragmentTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
Context mContext;
private FakeFeatureFactory mFakeFeatureFactory;
private MetricsFeatureProvider mMetricsFeatureProvider;
private SupportFeatureProvider mSupportFeatureProvider;
private final Account mFakeAccount = new Account("user1", "fake_type");
private static final int FAKE_RES_ID = -1000;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mMetricsFeatureProvider = mFakeFeatureFactory.getMetricsFeatureProvider();
mSupportFeatureProvider = mFakeFeatureFactory.getSupportFeatureProvider(mContext);
when(mSupportFeatureProvider.getDisclaimerStringResId())
.thenReturn(FAKE_RES_ID);
}
@Test
public void onClick_DoNotShowCheckedLogsAction() {
SupportDisclaimerDialogFragment fragment =
SupportDisclaimerDialogFragment.newInstance(mFakeAccount, SupportType.CHAT);
FragmentTestUtil.startFragment(fragment);
// pretend the user selected to skip the dialog in the future
CheckBox doNotShow = (CheckBox) fragment.getDialog()
.findViewById(R.id.support_disclaimer_do_not_show_again);
doNotShow.setChecked(true);
// verify we logged the action
fragment.onClick(fragment.getDialog(), Dialog.BUTTON_POSITIVE);
verify(mMetricsFeatureProvider, times(1)).action(any(),
eq(MetricsProto.MetricsEvent.ACTION_SKIP_DISCLAIMER_SELECTED));
}
@Test
public void onClick_DoNotShowUncheckedDoesNotLogAction() {
SupportDisclaimerDialogFragment fragment =
SupportDisclaimerDialogFragment.newInstance(mFakeAccount, SupportType.CHAT);
FragmentTestUtil.startFragment(fragment);
// pretend the user selected to skip the dialog in the future
CheckBox doNotShow = (CheckBox) fragment.getDialog()
.findViewById(R.id.support_disclaimer_do_not_show_again);
doNotShow.setChecked(false);
// verify we logged the action
fragment.onClick(fragment.getDialog(), Dialog.BUTTON_POSITIVE);
verify(mMetricsFeatureProvider, never()).action(any(),
eq(MetricsProto.MetricsEvent.ACTION_SKIP_DISCLAIMER_SELECTED));
}
@Implements(Resources.class)
public static class SupportDisclaimerShadowResources extends SettingsShadowResources {
@Implementation
@NonNull public CharSequence getText(@StringRes int id) throws NotFoundException {
if (id == FAKE_RES_ID) {
Spannable text = Spannable.Factory.getInstance()
.newSpannable("string with url");
text.setSpan(new URLSpan("https://google.com"), 0, 1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return text;
}
return directlyOn(realResources, Resources.class).getText(id);
}
}
}