Snap for 4598635 from 08addde8b5 to pi-release

Change-Id: I0dd217b846bf0a4ebb0b3e345fbec2f2be8ecc4a
This commit is contained in:
android-build-team Robot
2018-02-11 08:22:47 +00:00
69 changed files with 2797 additions and 646 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,112 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 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:paddingStart="@dimen/preference_no_icon_padding_start"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:orientation="vertical"
android:background="@drawable/selectable_card_grey"
android:selectable="false"
style="@style/EntityHeader">
<TextView
android:id="@+id/usage_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:paddingBottom="5dp"
android:text="@string/data_usage_title" />
<TextView
android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:fontFamily="@*android:string/config_headlineFontFamily"
android:textColor="?android:attr/colorAccent"
android:textAppearance="@android:style/TextAppearance.Material.Large" />
<TextView
android:id="@android:id/summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:paddingBottom="5dp" />
<com.android.settings.widget.LinearColorBar
android:id="@+id/color_bar"
android:layout_width="match_parent"
android:layout_height="28dp" />
<LinearLayout
android:id="@+id/label_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="2dp"
android:orientation="horizontal">
<TextView android:id="@android:id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView android:id="@android:id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary" />
</LinearLayout>
<TextView
android:id="@+id/cycle_left_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="5dp" />
<TextView
android:id="@+id/carrier_and_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="5dp" />
<Button
android:id="@+id/launch_mdp_app_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:text="@string/launch_mdp_app_text"
style="@style/ActionPrimaryButton" />
<TextView
android:id="@+id/data_limits"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="5dp" />
</LinearLayout>

View File

@@ -25,23 +25,21 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<Button <Button
android:id="@+id/battery_saver_on_button" android:id="@+id/state_on_button"
style="@style/ActionPrimaryButton" style="@style/ActionPrimaryButton"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_weight="1" android:layout_weight="1"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:text="@string/battery_saver_button_turn_on"
android:paddingEnd="8dp" /> android:paddingEnd="8dp" />
<Button <Button
android:id="@+id/battery_saver_off_button" android:id="@+id/state_off_button"
style="@style/ActionSecondaryButton" style="@style/ActionSecondaryButton"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_weight="1" android:layout_weight="1"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:text="@string/battery_saver_button_turn_off"
android:paddingEnd="8dp" /> android:paddingEnd="8dp" />
</LinearLayout> </LinearLayout>

View File

@@ -162,4 +162,12 @@
<attr name="showPercentString" format="boolean" /> <attr name="showPercentString" format="boolean" />
<attr name="thickness" format="dimension" /> <attr name="thickness" format="dimension" />
</declare-styleable> </declare-styleable>
<!-- For TwoStatesButtonPreference -->
<declare-styleable name="TwoStateButtonPreference">
<attr name="textOn" format="reference" />
<attr name="textOff" format="reference" />
</declare-styleable>
<attr name="twoStateButtonPreferenceStyle" format="reference" />
</resources> </resources>

View File

@@ -5844,6 +5844,8 @@
<string name="data_usage_enable_3g">2G-3G data</string> <string name="data_usage_enable_3g">2G-3G data</string>
<!-- Toggle switch title for enabling 4G data network connection. [CHAR LIMIT=32] --> <!-- Toggle switch title for enabling 4G data network connection. [CHAR LIMIT=32] -->
<string name="data_usage_enable_4g">4G data</string> <string name="data_usage_enable_4g">4G data</string>
<!-- Toggle switch title for enabling roaming on the primary data SIM card. [CHAR LIMIT=32] -->
<string name="data_roaming_enable_mobile">Roaming</string>
<!-- Data Usage Foreground label. [CHAR LIMIT=40] --> <!-- Data Usage Foreground label. [CHAR LIMIT=40] -->
<string name="data_usage_forground_label">Foreground:</string> <string name="data_usage_forground_label">Foreground:</string>
@@ -6476,6 +6478,7 @@
<string name="help_uri_process_stats_apps" translatable="false"></string> <string name="help_uri_process_stats_apps" translatable="false"></string>
<string name="help_uri_private_dns" translatable="false"></string> <string name="help_uri_private_dns" translatable="false"></string>
<string name="help_uri_about_phone_v2" translatable="false"></string> <string name="help_uri_about_phone_v2" translatable="false"></string>
<string name="help_uri_wifi_calling" translatable="false"></string>
<!-- User account title [CHAR LIMIT=30] --> <!-- User account title [CHAR LIMIT=30] -->
<string name="user_account_title">Account for content</string> <string name="user_account_title">Account for content</string>
@@ -8655,6 +8658,27 @@
<item quantity="other"><xliff:g id="count" example="10">%1$d</xliff:g> apps allowed to use unrestricted data when Data Saver is on</item> <item quantity="other"><xliff:g id="count" example="10">%1$d</xliff:g> apps allowed to use unrestricted data when Data Saver is on</item>
</plurals> </plurals>
<!-- Data usage title text [CHAR LIMIT=30] -->
<string name="data_usage_title">Primary data</string>
<!-- Data usage string [CHAR LIMIT=30] -->
<string name="data_used"><xliff:g name="bytes" example="2 GB">^1</xliff:g> used</string>
<!-- Optional part of data usage showing the remaining amount [CHAR LIMIT=30] -->
<string name="data_remaining"><xliff:g name="bytes" example="2 GB">, ^1</xliff:g> left</string>
<!-- Informational text about time left in billing cycle [CHAR LIMIT=30] -->
<string name="cycle_left_time_text"><xliff:g name="time" example="2d">%1$s</xliff:g> left in this cycle</string>
<!-- Informational text about carrier and update time [CHAR LIMIT=30] -->
<string name="carrier_and_update_text">Updated by <xliff:g name="carrier" example="T-mobile">%1$s</xliff:g> <xliff:g name="time" example="3m">%2$s</xliff:g></string>
<!-- Informational text about update time only, without carrier [CHAR LIMIT=30] -->
<string name="no_carrier_update_text">Updated <xliff:g name="time" example="3m">%1$s</xliff:g></string>
<!-- Button to launch external data plan app [CHAR LIMIT=30] -->
<string name="launch_mdp_app_text">VIEW PLAN</string>
<!-- Name of Data Saver screens [CHAR LIMIT=30] --> <!-- Name of Data Saver screens [CHAR LIMIT=30] -->
<string name="data_saver_title">Data saver</string> <string name="data_saver_title">Data saver</string>

View File

@@ -36,4 +36,8 @@
<item name="android:widgetLayout">@layout/preference_widget_sync_toggle</item> <item name="android:widgetLayout">@layout/preference_widget_sync_toggle</item>
</style> </style>
<style name="TwoStateButtonPreference" parent="Preference.SettingsBase">
<item name="android:layout">@layout/two_state_button</item>
</style>
</resources> </resources>

View File

@@ -176,6 +176,7 @@
<item name="preferenceFragmentStyle">@style/SettingsPreferenceFragmentStyle</item> <item name="preferenceFragmentStyle">@style/SettingsPreferenceFragmentStyle</item>
<item name="apnPreferenceStyle">@style/ApnPreference</item> <item name="apnPreferenceStyle">@style/ApnPreference</item>
<item name="seekBarPreferenceStyle">@style/SettingsSeekBarPreference</item> <item name="seekBarPreferenceStyle">@style/SettingsSeekBarPreference</item>
<item name="twoStateButtonPreferenceStyle">@style/TwoStateButtonPreference</item>
</style> </style>
<style name="PreferenceTheme.SetupWizard" parent="PreferenceTheme"> <style name="PreferenceTheme.SetupWizard" parent="PreferenceTheme">

View File

@@ -16,6 +16,7 @@
<PreferenceScreen <PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/battery_saver" android:title="@string/battery_saver"
android:key="battery_saver"> android:key="battery_saver">
@@ -23,16 +24,20 @@
<SwitchPreference <SwitchPreference
android:key="auto_battery_saver" android:key="auto_battery_saver"
android:title="@string/battery_saver_auto_title" android:title="@string/battery_saver_auto_title"
android:summary="@string/battery_saver_auto_summary"/> android:summary="@string/battery_saver_auto_summary"
settings:controller="com.android.settings.fuelgauge.batterysaver.AutoBatterySaverPreferenceController"/>
<com.android.settings.widget.SeekBarPreference <com.android.settings.widget.SeekBarPreference
android:key="battery_saver_seek_bar" android:key="battery_saver_seek_bar"
android:title="@string/battery_saver_seekbar_title" android:title="@string/battery_saver_seekbar_title"
android:max="75" android:max="75"
android:min="5"/> android:min="5"/>
<com.android.settings.applications.LayoutPreference
<com.android.settings.widget.TwoStateButtonPreference
android:key="battery_saver_button_container" android:key="battery_saver_button_container"
android:selectable="false" android:selectable="false"
android:layout="@layout/battery_saver_settings_button"/> settings:textOn="@string/battery_saver_button_turn_on"
settings:textOff="@string/battery_saver_button_turn_off"/>
<PreferenceCategory <PreferenceCategory
android:key="battery_saver_footer"> android:key="battery_saver_footer">

View File

@@ -25,8 +25,8 @@
android:title="@string/bluetooth_settings_title" android:title="@string/bluetooth_settings_title"
android:icon="@drawable/ic_settings_bluetooth" android:icon="@drawable/ic_settings_bluetooth"
android:summary="@string/bluetooth_pref_summary" android:summary="@string/bluetooth_pref_summary"
settings:controller="com.android.settings.bluetooth.BluetoothSwitchPreferenceController" android:order="-7"
android:order="-7"/> settings:controller="com.android.settings.bluetooth.BluetoothSwitchPreferenceController"/>
<SwitchPreference <SwitchPreference
android:key="toggle_nfc" android:key="toggle_nfc"
@@ -54,6 +54,7 @@
android:title="@string/bluetooth_on_while_driving_pref" android:title="@string/bluetooth_on_while_driving_pref"
android:icon="@drawable/ic_settings_bluetooth" android:icon="@drawable/ic_settings_bluetooth"
android:summary="@string/bluetooth_on_while_driving_summary" android:summary="@string/bluetooth_on_while_driving_summary"
settings:controller="com.android.settings.connecteddevice.BluetoothOnWhileDrivingPreferenceController"
android:order="-2"/> android:order="-2"/>
<Preference <Preference

View File

@@ -20,24 +20,8 @@
android:key="data_usage_screen" android:key="data_usage_screen"
android:title="@string/data_usage_summary_title"> android:title="@string/data_usage_summary_title">
<PreferenceCategory <com.android.settings.datausage.DataUsageSummaryPreference
android:key="data_usage_category"
android:title="@string/usage">
<com.android.settings.SummaryPreference
android:key="status_header" android:key="status_header"
android:selectable="false" /> android:selectable="false" />
<Preference
android:key="limit_summary"
android:selectable="false"
settings:allowDividerBelow="true" />
<com.android.settings.datausage.DataSaverPreference
android:key="restrict_background"
android:title="@string/data_saver_title"
android:fragment="com.android.settings.datausage.DataSaverSummary" />
</PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>

View File

@@ -43,8 +43,9 @@
<com.android.settingslib.RestrictedSwitchPreference <com.android.settingslib.RestrictedSwitchPreference
android:key="auto_brightness" android:key="auto_brightness"
android:title="@string/auto_brightness_title" android:title="@string/auto_brightness_title"
settings:keywords="@string/keywords_display_auto_brightness"
android:summary="@string/auto_brightness_summary" android:summary="@string/auto_brightness_summary"
settings:keywords="@string/keywords_display_auto_brightness"
settings:controller="com.android.settings.display.AutoBrightnessPreferenceController"
settings:useAdminDisabledSummary="true" settings:useAdminDisabledSummary="true"
settings:userRestriction="no_config_brightness" /> settings:userRestriction="no_config_brightness" />

View File

@@ -79,7 +79,8 @@
<SwitchPreference <SwitchPreference
android:key="visiblepattern_profile" android:key="visiblepattern_profile"
android:summary="@string/summary_placeholder" android:summary="@string/summary_placeholder"
android:title="@string/lockpattern_settings_enable_visible_pattern_title_profile" /> android:title="@string/lockpattern_settings_enable_visible_pattern_title_profile"
settings:controller="com.android.settings.security.VisiblePatternProfilePreferenceController"/>
<Preference <Preference
android:key="fingerprint_settings_profile" android:key="fingerprint_settings_profile"
@@ -103,7 +104,8 @@
<SwitchPreference <SwitchPreference
android:key="show_password" android:key="show_password"
android:title="@string/show_password" android:title="@string/show_password"
android:summary="@string/show_password_summary" /> android:summary="@string/show_password_summary"
settings:controller="com.android.settings.security.ShowPasswordPreferenceController"/>
</PreferenceCategory> </PreferenceCategory>

View File

@@ -16,6 +16,7 @@
<PreferenceScreen <PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="security_lockscreen_settings_screen" android:key="security_lockscreen_settings_screen"
android:title="@string/lockscreen_settings_title"> android:title="@string/lockscreen_settings_title">
@@ -36,7 +37,8 @@
<SwitchPreference <SwitchPreference
android:key="security_setting_lockdown_enabled" android:key="security_setting_lockdown_enabled"
android:title="@string/lockdown_settings_title" android:title="@string/lockdown_settings_title"
android:summary="@string/lockdown_settings_summary" /> android:summary="@string/lockdown_settings_summary"
settings:controller="com.android.settings.security.LockdownButtonPreferenceController"/>
<PreferenceCategory <PreferenceCategory
android:key="security_setting_lock_screen_notif_work_header" android:key="security_setting_lock_screen_notif_work_header"

View File

@@ -808,7 +808,6 @@ public class SettingsActivity extends SettingsDrawerActivity
|| somethingChanged; || somethingChanged;
final boolean showDev = DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(this) final boolean showDev = DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(this)
&& !um.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES)
&& !Utils.isMonkeyRunning(); && !Utils.isMonkeyRunning();
somethingChanged = setTileEnabled(new ComponentName(packageName, somethingChanged = setTileEnabled(new ComponentName(packageName,

View File

@@ -42,6 +42,24 @@ public class LayoutPreference extends Preference {
public LayoutPreference(Context context, AttributeSet attrs) { public LayoutPreference(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
init(context, attrs, 0 /* defStyleAttr */);
}
public LayoutPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
public LayoutPreference(Context context, int resource) {
this(context, LayoutInflater.from(context).inflate(resource, null, false));
}
public LayoutPreference(Context context, View view) {
super(context);
setView(view);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Preference); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Preference);
mAllowDividerAbove = TypedArrayUtils.getBoolean(a, R.styleable.Preference_allowDividerAbove, mAllowDividerAbove = TypedArrayUtils.getBoolean(a, R.styleable.Preference_allowDividerAbove,
R.styleable.Preference_allowDividerAbove, false); R.styleable.Preference_allowDividerAbove, false);
@@ -50,7 +68,7 @@ public class LayoutPreference extends Preference {
a.recycle(); a.recycle();
a = context.obtainStyledAttributes( a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.Preference, 0, 0); attrs, com.android.internal.R.styleable.Preference, defStyleAttr, 0);
int layoutResource = a.getResourceId(com.android.internal.R.styleable.Preference_layout, int layoutResource = a.getResourceId(com.android.internal.R.styleable.Preference_layout,
0); 0);
if (layoutResource == 0) { if (layoutResource == 0) {
@@ -64,15 +82,6 @@ public class LayoutPreference extends Preference {
setView(view); setView(view);
} }
public LayoutPreference(Context context, int resource) {
this(context, LayoutInflater.from(context).inflate(resource, null, false));
}
public LayoutPreference(Context context, View view) {
super(context);
setView(view);
}
private void setView(View view) { private void setView(View view) {
setLayoutResource(R.layout.layout_preference_frame); setLayoutResource(R.layout.layout_preference_frame);
final ViewGroup allDetails = view.findViewById(R.id.all_details); final ViewGroup allDetails = view.findViewById(R.id.all_details);

View File

@@ -30,6 +30,8 @@ import java.util.List;
* Abstract class to consolidate utility between preference controllers and act as an interface * Abstract class to consolidate utility between preference controllers and act as an interface
* for Slices. The abstract classes that inherit from this class will act as the direct interfaces * for Slices. The abstract classes that inherit from this class will act as the direct interfaces
* for each type when plugging into Slices. * for each type when plugging into Slices.
*
* TODO (b/73074893) Add Lifecycle Setting method.
*/ */
public abstract class BasePreferenceController extends AbstractPreferenceController { public abstract class BasePreferenceController extends AbstractPreferenceController {

View File

@@ -28,7 +28,7 @@ import com.android.settings.Settings;
import com.android.settings.TestingSettings; import com.android.settings.TestingSettings;
import com.android.settings.TetherSettings; import com.android.settings.TetherSettings;
import com.android.settings.TrustedCredentialsSettings; import com.android.settings.TrustedCredentialsSettings;
import com.android.settings.WifiCallingSettings; import com.android.settings.wifi.calling.WifiCallingSettings;
import com.android.settings.accessibility.AccessibilitySettings; import com.android.settings.accessibility.AccessibilitySettings;
import com.android.settings.accessibility.AccessibilitySettingsForSetupWizard; import com.android.settings.accessibility.AccessibilitySettingsForSetupWizard;
import com.android.settings.accessibility.CaptionPropertiesFragment; import com.android.settings.accessibility.CaptionPropertiesFragment;

View File

@@ -55,7 +55,7 @@ public class DashboardSummary extends InstrumentedFragment
FocusListener, SuggestionControllerMixin.SuggestionControllerHost { FocusListener, SuggestionControllerMixin.SuggestionControllerHost {
public static final boolean DEBUG = false; public static final boolean DEBUG = false;
private static final boolean DEBUG_TIMING = false; private static final boolean DEBUG_TIMING = false;
private static final int MAX_WAIT_MILLIS = 700; private static final int MAX_WAIT_MILLIS = 3000;
private static final String TAG = "DashboardSummary"; private static final String TAG = "DashboardSummary";
private static final String EXTRA_SCROLL_POSITION = "scroll_position"; private static final String EXTRA_SCROLL_POSITION = "scroll_position";

View File

@@ -37,7 +37,7 @@ import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ScreenLockSuggestionActivity; import com.android.settings.password.ScreenLockSuggestionActivity;
import com.android.settings.support.NewDeviceIntroSuggestionActivity; import com.android.settings.support.NewDeviceIntroSuggestionActivity;
import com.android.settings.wallpaper.WallpaperSuggestionActivity; import com.android.settings.wallpaper.WallpaperSuggestionActivity;
import com.android.settings.wifi.WifiCallingSuggestionActivity; import com.android.settings.wifi.calling.WifiCallingSuggestionActivity;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.drawer.Tile; import com.android.settingslib.drawer.Tile;
import com.android.settingslib.suggestions.SuggestionControllerMixin; import com.android.settingslib.suggestions.SuggestionControllerMixin;

View File

@@ -18,7 +18,6 @@ import android.app.Activity;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.NetworkPolicyManager;
import android.net.NetworkTemplate; import android.net.NetworkTemplate;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserManager; import android.os.UserManager;
@@ -28,6 +27,7 @@ import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.PreferenceScreen;
import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionPlan;
import android.text.BidiFormatter; import android.text.BidiFormatter;
import android.text.Spannable; import android.text.Spannable;
import android.text.SpannableString; import android.text.SpannableString;
@@ -40,7 +40,6 @@ import android.view.MenuItem;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SummaryPreference;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.dashboard.SummaryLoader; import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.BaseSearchIndexProvider;
@@ -65,7 +64,6 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
public static final String KEY_RESTRICT_BACKGROUND = "restrict_background"; public static final String KEY_RESTRICT_BACKGROUND = "restrict_background";
private static final String KEY_STATUS_HEADER = "status_header"; private static final String KEY_STATUS_HEADER = "status_header";
private static final String KEY_LIMIT_SUMMARY = "limit_summary";
// Mobile data keys // Mobile data keys
public static final String KEY_MOBILE_USAGE_TITLE = "mobile_category"; public static final String KEY_MOBILE_USAGE_TITLE = "mobile_category";
@@ -77,13 +75,9 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
public static final String KEY_WIFI_USAGE_TITLE = "wifi_category"; public static final String KEY_WIFI_USAGE_TITLE = "wifi_category";
public static final String KEY_WIFI_DATA_USAGE = "wifi_data_usage"; public static final String KEY_WIFI_DATA_USAGE = "wifi_data_usage";
private DataUsageController mDataUsageController; private DataUsageSummaryPreference mSummaryPreference;
private DataUsageInfoController mDataInfoController; private DataUsageSummaryPreferenceController mSummaryController;
private SummaryPreference mSummaryPreference;
private Preference mLimitPreference;
private NetworkTemplate mDefaultTemplate; private NetworkTemplate mDefaultTemplate;
private int mDataUsageTemplate;
private NetworkPolicyEditor mPolicyEditor;
@Override @Override
public int getHelpResource() { public int getHelpResource() {
@@ -95,25 +89,20 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
super.onCreate(icicle); super.onCreate(icicle);
final Context context = getContext(); final Context context = getContext();
NetworkPolicyManager policyManager = NetworkPolicyManager.from(context);
mPolicyEditor = new NetworkPolicyEditor(policyManager);
boolean hasMobileData = DataUsageUtils.hasMobileData(context); boolean hasMobileData = DataUsageUtils.hasMobileData(context);
mDataUsageController = new DataUsageController(context);
mDataInfoController = new DataUsageInfoController();
int defaultSubId = DataUsageUtils.getDefaultSubscriptionId(context); int defaultSubId = DataUsageUtils.getDefaultSubscriptionId(context);
if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
hasMobileData = false; hasMobileData = false;
} }
mDefaultTemplate = DataUsageUtils.getDefaultTemplate(context, defaultSubId); mDefaultTemplate = DataUsageUtils.getDefaultTemplate(context, defaultSubId);
mSummaryPreference = (SummaryPreference) findPreference(KEY_STATUS_HEADER); mSummaryPreference = (DataUsageSummaryPreference) findPreference(KEY_STATUS_HEADER);
if (!hasMobileData || !isAdmin()) { if (!hasMobileData || !isAdmin()) {
removePreference(KEY_RESTRICT_BACKGROUND); removePreference(KEY_RESTRICT_BACKGROUND);
} }
if (hasMobileData) { if (hasMobileData) {
mLimitPreference = findPreference(KEY_LIMIT_SUMMARY);
List<SubscriptionInfo> subscriptions = List<SubscriptionInfo> subscriptions =
services.mSubscriptionManager.getActiveSubscriptionInfoList(); services.mSubscriptionManager.getActiveSubscriptionInfoList();
if (subscriptions == null || subscriptions.size() == 0) { if (subscriptions == null || subscriptions.size() == 0) {
@@ -127,10 +116,6 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
addMobileSection(subInfo.getSubscriptionId()); addMobileSection(subInfo.getSubscriptionId());
} }
} }
mSummaryPreference.setSelectable(true);
} else {
removePreference(KEY_LIMIT_SUMMARY);
mSummaryPreference.setSelectable(false);
} }
boolean hasWifiRadio = DataUsageUtils.hasWifiRadio(context); boolean hasWifiRadio = DataUsageUtils.hasWifiRadio(context);
if (hasWifiRadio) { if (hasWifiRadio) {
@@ -139,10 +124,6 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
if (hasEthernet(context)) { if (hasEthernet(context)) {
addEthernetSection(); addEthernetSection();
} }
mDataUsageTemplate = hasMobileData ? R.string.cell_data_template
: hasWifiRadio ? R.string.wifi_data_template
: R.string.ethernet_data_template;
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }
@@ -189,7 +170,11 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
@Override @Override
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) { protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
return null; final ArrayList<AbstractPreferenceController> controllers = new ArrayList<>();
mSummaryController =
new DataUsageSummaryPreferenceController(context);
controllers.add(mSummaryController);
return controllers;
} }
private void addMobileSection(int subId) { private void addMobileSection(int subId) {
@@ -269,36 +254,6 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
} }
private void updateState() { private void updateState() {
DataUsageController.DataUsageInfo info = mDataUsageController.getDataUsageInfo(
mDefaultTemplate);
Context context = getContext();
mDataInfoController.updateDataLimit(info,
services.mPolicyEditor.getPolicy(mDefaultTemplate));
if (mSummaryPreference != null) {
mSummaryPreference.setTitle(
formatUsage(context, getString(mDataUsageTemplate), info.usageLevel));
final long limit = mDataInfoController.getSummaryLimit(info);
mSummaryPreference.setSummary(info.period);
if (limit <= 0) {
mSummaryPreference.setChartEnabled(false);
} else {
mSummaryPreference.setChartEnabled(true);
mSummaryPreference.setLabels(Formatter.formatFileSize(context, 0),
Formatter.formatFileSize(context, limit));
mSummaryPreference.setRatios(info.usageLevel / (float) limit, 0,
(limit - info.usageLevel) / (float) limit);
}
}
if (mLimitPreference != null && (info.warningLevel > 0 || info.limitLevel > 0)) {
String warning = Formatter.formatFileSize(context, info.warningLevel);
String limit = Formatter.formatFileSize(context, info.limitLevel);
mLimitPreference.setSummary(getString(info.limitLevel <= 0 ? R.string.cell_warning_only
: R.string.cell_warning_and_limit, warning, limit));
} else if (mLimitPreference != null) {
mLimitPreference.setSummary(null);
}
PreferenceScreen screen = getPreferenceScreen(); PreferenceScreen screen = getPreferenceScreen();
for (int i = 1; i < screen.getPreferenceCount(); i++) { for (int i = 1; i < screen.getPreferenceCount(); i++) {
((TemplatePreferenceCategory) screen.getPreference(i)).pushTemplates(services); ((TemplatePreferenceCategory) screen.getPreference(i)).pushTemplates(services);
@@ -323,6 +278,7 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
@Override @Override
public void updateDataUsage() { public void updateDataUsage() {
updateState(); updateState();
mSummaryController.updateState(mSummaryPreference);
} }
private static class SummaryProvider private static class SummaryProvider
@@ -341,17 +297,39 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
@Override @Override
public void setListening(boolean listening) { public void setListening(boolean listening) {
if (listening) { if (listening) {
DataUsageController.DataUsageInfo info = mDataController.getDataUsageInfo();
String used;
if (info == null) {
used = Formatter.formatFileSize(mActivity, 0);
} else if (info.limitLevel <= 0) {
used = Formatter.formatFileSize(mActivity, info.usageLevel);
} else {
used = Utils.formatPercentage(info.usageLevel, info.limitLevel);
}
mSummaryLoader.setSummary(this, mSummaryLoader.setSummary(this,
mActivity.getString(R.string.data_usage_summary_format, used)); mActivity.getString(R.string.data_usage_summary_format, formatUsedData()));
}
}
private String formatUsedData() {
SubscriptionManager subscriptionManager = (SubscriptionManager) mActivity
.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
int defaultSubId = subscriptionManager.getDefaultSubscriptionId();
if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
return formatFallbackData();
}
SubscriptionPlan dfltPlan = DataUsageSummaryPreferenceController
.getPrimaryPlan(subscriptionManager, defaultSubId);
if (dfltPlan == null) {
return formatFallbackData();
}
if (DataUsageSummaryPreferenceController.unlimited(dfltPlan.getDataLimitBytes())) {
return Formatter.formatFileSize(mActivity, dfltPlan.getDataUsageBytes());
} else {
return Utils.formatPercentage(dfltPlan.getDataUsageBytes(),
dfltPlan.getDataLimitBytes());
}
}
private String formatFallbackData() {
DataUsageController.DataUsageInfo info = mDataController.getDataUsageInfo();
if (info == null) {
return Formatter.formatFileSize(mActivity, 0);
} else if (info.limitLevel <= 0) {
return Formatter.formatFileSize(mActivity, info.usageLevel);
} else {
return Utils.formatPercentage(info.usageLevel, info.limitLevel);
} }
} }
} }

View File

@@ -0,0 +1,117 @@
/*
* Copyright (C) 2018 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.datausage;
import android.content.Context;
import android.content.Intent;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.SummaryPreference;
import com.android.settingslib.utils.StringUtil;
import libcore.util.Objects;
/**
* Provides a summary of data usage.
*/
public class DataUsageSummaryPreference extends SummaryPreference {
private int mNumPlans;
/** The ending time of the billing cycle in milliseconds since epoch. */
private long mCycleEndTimeMs;
/** The time of the last update in standard milliseconds since the epoch */
private long mSnapshotTimeMs;
/** Name of carrier, or null if not available */
private CharSequence mCarrierName;
private String mLimitInfoText;
private Intent mLaunchIntent;
public DataUsageSummaryPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.data_usage_summary_preference);
}
public void setLimitInfo(String text) {
if (!Objects.equal(text, mLimitInfoText)) {
mLimitInfoText = text;
notifyChanged();
}
}
public void setUsageInfo(long cycleEnd, long snapshotTime, CharSequence carrierName,
int numPlans, Intent launchIntent) {
mCycleEndTimeMs = cycleEnd;
mSnapshotTimeMs = snapshotTime;
mCarrierName = carrierName;
mNumPlans = numPlans;
mLaunchIntent = launchIntent;
notifyChanged();
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
TextView usageTitle = (TextView) holder.findViewById(R.id.usage_title);
usageTitle.setVisibility(mNumPlans > 1 ? View.VISIBLE : View.GONE);
TextView cycleTime = (TextView) holder.findViewById(R.id.cycle_left_time);
cycleTime.setText(getContext().getString(R.string.cycle_left_time_text,
StringUtil.formatElapsedTime(getContext(),
mCycleEndTimeMs - System.currentTimeMillis(),false /* withSeconds */)));
TextView carrierInfo = (TextView) holder.findViewById(R.id.carrier_and_update);
setCarrierInfo(carrierInfo, mCarrierName, mSnapshotTimeMs);
Button launchButton = (Button) holder.findViewById(R.id.launch_mdp_app_button);
launchButton.setOnClickListener((view) -> {
getContext().sendBroadcast(mLaunchIntent);
});
if (mLaunchIntent != null) {
launchButton.setVisibility(View.VISIBLE);
} else {
launchButton.setVisibility(View.GONE);
}
TextView limitInfo = (TextView) holder.findViewById(R.id.data_limits);
limitInfo.setVisibility(
mLimitInfoText == null || mLimitInfoText.isEmpty() ? View.GONE : View.VISIBLE);
limitInfo.setText(mLimitInfoText);
}
private void setCarrierInfo(TextView carrierInfo, CharSequence carrierName, long updateAge) {
if (mNumPlans > 0 && updateAge >= 0L) {
carrierInfo.setVisibility(View.VISIBLE);
if (carrierName != null) {
carrierInfo.setText(getContext().getString(R.string.carrier_and_update_text,
carrierName, StringUtil.formatRelativeTime(
getContext(), updateAge, false /* withSeconds */)));
} else {
carrierInfo.setText(getContext().getString(R.string.no_carrier_update_text,
StringUtil.formatRelativeTime(
getContext(), updateAge, false /* withSeconds */)));
}
} else {
carrierInfo.setVisibility(View.GONE);
}
}
}

View File

@@ -0,0 +1,286 @@
/*
* Copyright (C) 2018 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.datausage;
import android.content.Context;
import android.content.Intent;
import android.net.NetworkPolicyManager;
import android.net.NetworkTemplate;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionPlan;
import android.text.BidiFormatter;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.text.style.RelativeSizeSpan;
import android.util.Log;
import android.util.RecurrenceRule;
import com.android.internal.util.CollectionUtils;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.NetworkPolicyEditor;
import com.android.settingslib.net.DataUsageController;
import java.util.List;
/**
* This is the controller for the top of the data usage screen that retrieves carrier data from the
* new subscriptions framework API if available. The controller reads subscription information from
* the framework and falls back to legacy usage data if none are available.
*/
public class DataUsageSummaryPreferenceController extends BasePreferenceController {
private static final String TAG = "DataUsageController";
private static final String KEY = "status_header";
private static final long PETA = 1000000000000000L;
private static final float RELATIVE_SIZE_LARGE = 1.25f * 1.25f; // (1/0.8)^2
private static final float RELATIVE_SIZE_SMALL = 1.0f / RELATIVE_SIZE_LARGE; // 0.8^2
private final DataUsageController mDataUsageController;
private final DataUsageInfoController mDataInfoController;
private final NetworkTemplate mDefaultTemplate;
private final NetworkPolicyEditor mPolicyEditor;
private final int mDataUsageTemplate;
private final boolean mHasMobileData;
private final SubscriptionManager mSubscriptionManager;
/** Name of the carrier, or null if not available */
private CharSequence mCarrierName;
/** The number of registered plans, [0,N] */
private int mDataplanCount;
/** The time of the last update in milliseconds since the epoch, or -1 if unknown */
private long mSnapshotTime;
/**
* The size of the first registered plan if one exists or the size of the warning if it is set.
* -1 if no information is available.
*/
private long mDataplanSize;
/** The number of bytes used since the start of the cycle. */
private long mDataplanUse;
/** The starting time of the billing cycle in ms since the epoch */
private long mCycleStart;
/** The ending time of the billing cycle in ms since the epoch */
private long mCycleEnd;
private Intent mManageSubscriptionIntent;
public DataUsageSummaryPreferenceController(Context context) {
super(context, KEY);
final int defaultSubId = DataUsageUtils.getDefaultSubscriptionId(context);
mDefaultTemplate = DataUsageUtils.getDefaultTemplate(context, defaultSubId);
NetworkPolicyManager policyManager = NetworkPolicyManager.from(context);
mPolicyEditor = new NetworkPolicyEditor(policyManager);
mHasMobileData = DataUsageUtils.hasMobileData(context)
&& defaultSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID;
mDataUsageController = new DataUsageController(context);
mDataInfoController = new DataUsageInfoController();
if (mHasMobileData) {
mDataUsageTemplate = R.string.cell_data_template;
} else if (DataUsageUtils.hasWifiRadio(context)) {
mDataUsageTemplate = R.string.wifi_data_template;
} else {
mDataUsageTemplate = R.string.ethernet_data_template;
}
mSubscriptionManager = (SubscriptionManager)
mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
}
@VisibleForTesting
DataUsageSummaryPreferenceController(
Context context,
DataUsageController dataUsageController,
DataUsageInfoController dataInfoController,
NetworkTemplate defaultTemplate,
NetworkPolicyEditor policyEditor,
int dataUsageTemplate,
boolean hasMobileData,
SubscriptionManager subscriptionManager) {
super(context, KEY);
mDataUsageController = dataUsageController;
mDataInfoController = dataInfoController;
mDefaultTemplate = defaultTemplate;
mPolicyEditor = policyEditor;
mDataUsageTemplate = dataUsageTemplate;
mHasMobileData = hasMobileData;
mSubscriptionManager = subscriptionManager;
}
@VisibleForTesting
void setPlanValues(int dataPlanCount, long dataPlanSize, long dataPlanUse) {
mDataplanCount = dataPlanCount;
mDataplanSize = dataPlanSize;
mDataplanUse = dataPlanUse;
}
@VisibleForTesting
void setCarrierValues(String carrierName, long snapshotTime, long cycleEnd, Intent intent) {
mCarrierName = carrierName;
mSnapshotTime = snapshotTime;
mCycleEnd = cycleEnd;
mManageSubscriptionIntent = intent;
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
@Override
public void updateState(Preference preference) {
DataUsageSummaryPreference summaryPreference = (DataUsageSummaryPreference) preference;
DataUsageController.DataUsageInfo info = mDataUsageController.getDataUsageInfo(
mDefaultTemplate);
mDataInfoController.updateDataLimit(info, mPolicyEditor.getPolicy(mDefaultTemplate));
if (mSubscriptionManager != null) {
refreshDataplanInfo(info);
}
if (mDataplanCount == 0 && (info.warningLevel > 0 || info.limitLevel > 0)) {
final String warning = Formatter.formatFileSize(mContext, info.warningLevel);
final String limit = Formatter.formatFileSize(mContext, info.limitLevel);
summaryPreference.setLimitInfo(mContext.getString(info.limitLevel <= 0
? R.string.cell_warning_only
: R.string.cell_warning_and_limit, warning, limit));
} else {
summaryPreference.setLimitInfo(null);
}
final StringBuilder title = new StringBuilder();
if (mHasMobileData) {
title.append(formatUsage(mContext, mContext.getString(R.string.data_used),
mDataplanUse));
if (mDataplanCount >= 0 && mDataplanSize > 0L) {
title.append(formatUsage(mContext, mContext.getString(R.string.data_remaining),
mDataplanSize - mDataplanUse));
}
} else {
title.append(formatUsage(mContext, mContext.getString(mDataUsageTemplate),
mDataplanUse));
}
summaryPreference.setTitle(title.toString());
if (mDataplanSize <= 0) {
summaryPreference.setChartEnabled(false);
} else {
summaryPreference.setChartEnabled(true);
summaryPreference.setLabels(Formatter.formatFileSize(mContext, 0 /* sizeBytes */),
Formatter.formatFileSize(mContext, mDataplanSize));
summaryPreference.setRatios(mDataplanUse / (float) mDataplanSize, 0 /* middle */,
(mDataplanSize - mDataplanUse) / (float) mDataplanSize);
}
summaryPreference.setUsageInfo(mCycleEnd, mSnapshotTime, mCarrierName,
mDataplanCount, mManageSubscriptionIntent);
}
// TODO(b/70950124) add test for this method once the robolectric shadow run script is
// completed (b/3526807)
private void refreshDataplanInfo(DataUsageController.DataUsageInfo info) {
// reset data before overwriting
mCarrierName = null;
mDataplanCount = 0;
mDataplanSize = mDataInfoController.getSummaryLimit(info);
mDataplanUse = info.usageLevel;
mCycleStart = info.cycleStart;
mCycleEnd = info.cycleEnd;
mSnapshotTime = -1L;
final int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
final SubscriptionInfo subInfo = mSubscriptionManager.getDefaultDataSubscriptionInfo();
if (subInfo != null && mHasMobileData) {
mCarrierName = subInfo.getCarrierName();
List<SubscriptionPlan> plans = mSubscriptionManager.getSubscriptionPlans(defaultSubId);
final SubscriptionPlan primaryPlan = getPrimaryPlan(mSubscriptionManager, defaultSubId);
if (primaryPlan != null) {
mDataplanCount = plans.size();
mDataplanSize = primaryPlan.getDataLimitBytes();
if (unlimited(mDataplanSize)) {
mDataplanSize = 0L;
}
mDataplanUse = primaryPlan.getDataUsageBytes();
RecurrenceRule rule = primaryPlan.getCycleRule();
if (rule != null && rule.start != null && rule.end != null) {
mCycleStart = rule.start.toEpochSecond() * 1000L;
mCycleEnd = rule.end.toEpochSecond() * 1000L;
}
mSnapshotTime = System.currentTimeMillis() - primaryPlan.getDataUsageTime();
}
}
mManageSubscriptionIntent =
mSubscriptionManager.createManageSubscriptionIntent(defaultSubId);
Log.i(TAG, "Have " + mDataplanCount + " plans, dflt sub-id " + defaultSubId
+ ", intent " + mManageSubscriptionIntent);
}
public static SubscriptionPlan getPrimaryPlan(SubscriptionManager subManager, int primaryId) {
List<SubscriptionPlan> plans = subManager.getSubscriptionPlans(primaryId);
if (CollectionUtils.isEmpty(plans)) {
return null;
}
// First plan in the list is the primary plan
SubscriptionPlan plan = plans.get(0);
return plan.getDataLimitBytes() > 0
&& saneSize(plan.getDataUsageBytes())
&& plan.getCycleRule() != null ? plan : null;
}
private static boolean saneSize(long value) {
return value >= 0L && value < PETA;
}
public static boolean unlimited(long size) {
return size == SubscriptionPlan.BYTES_UNLIMITED;
}
@VisibleForTesting
private static CharSequence formatUsage(Context context, String template, long usageLevel) {
final int FLAGS = Spannable.SPAN_INCLUSIVE_INCLUSIVE;
final Formatter.BytesResult usedResult = Formatter.formatBytes(context.getResources(),
usageLevel, Formatter.FLAG_CALCULATE_ROUNDED);
final SpannableString enlargedValue = new SpannableString(usedResult.value);
enlargedValue.setSpan(
new RelativeSizeSpan(RELATIVE_SIZE_LARGE), 0, enlargedValue.length(), FLAGS);
final SpannableString amountTemplate = new SpannableString(
context.getString(com.android.internal.R.string.fileSizeSuffix)
.replace("%1$s", "^1").replace("%2$s", "^2"));
final CharSequence formattedUsage = TextUtils.expandTemplate(amountTemplate,
enlargedValue, usedResult.units);
final SpannableString fullTemplate = new SpannableString(template);
fullTemplate.setSpan(
new RelativeSizeSpan(RELATIVE_SIZE_SMALL), 0, fullTemplate.length(), FLAGS);
return TextUtils.expandTemplate(fullTemplate,
BidiFormatter.getInstance().unicodeWrap(formattedUsage.toString()));
}
}

View File

@@ -21,6 +21,7 @@ import static com.android.settings.bluetooth.Utils.getLocalBtManager;
import android.app.Activity; import android.app.Activity;
import android.app.Fragment; import android.app.Fragment;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.pm.UserInfo; import android.content.pm.UserInfo;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserManager; import android.os.UserManager;
@@ -126,6 +127,16 @@ public class MyDeviceInfoFragment extends DashboardFragment {
return controllers; return controllers;
} }
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
final BuildNumberPreferenceController buildNumberPreferenceController =
getPreferenceController(BuildNumberPreferenceController.class);
if (buildNumberPreferenceController.onActivityResult(requestCode, resultCode, data)) {
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
private void initHeader() { private void initHeader() {
// TODO: Migrate into its own controller. // TODO: Migrate into its own controller.
final LayoutPreference headerPreference = final LayoutPreference headerPreference =

View File

@@ -62,7 +62,8 @@ import java.util.List;
*/ */
public class BatteryAppListPreferenceController extends AbstractPreferenceController public class BatteryAppListPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin, LifecycleObserver, OnPause, OnDestroy { implements PreferenceControllerMixin, LifecycleObserver, OnPause, OnDestroy {
private static final boolean USE_FAKE_DATA = true; @VisibleForTesting
static final boolean USE_FAKE_DATA = false;
private static final int MAX_ITEMS_TO_LIST = USE_FAKE_DATA ? 30 : 10; private static final int MAX_ITEMS_TO_LIST = USE_FAKE_DATA ? 30 : 10;
private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10; private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
private static final int STATS_TYPE = BatteryStats.STATS_SINCE_CHARGED; private static final int STATS_TYPE = BatteryStats.STATS_SINCE_CHARGED;

View File

@@ -27,7 +27,7 @@ import com.android.settings.Utils;
/** /**
* Use this broadcastReceiver to listen to the battery change, and it will invoke * Use this broadcastReceiver to listen to the battery change, and it will invoke
* {@link OnBatteryChangedListener} if any of the followings has been changed: * {@link OnBatteryChangedListener} if any of the following has been changed:
* *
* 1. Battery level(e.g. 100%->99%) * 1. Battery level(e.g. 100%->99%)
* 2. Battery status(e.g. plugged->unplugged) * 2. Battery status(e.g. plugged->unplugged)
@@ -35,7 +35,14 @@ import com.android.settings.Utils;
*/ */
public class BatteryBroadcastReceiver extends BroadcastReceiver { public class BatteryBroadcastReceiver extends BroadcastReceiver {
interface OnBatteryChangedListener { /**
* Callback when the following has been changed:
*
* Battery level(e.g. 100%->99%)
* Battery status(e.g. plugged->unplugged)
* Battery saver(e.g. off->on)
*/
public interface OnBatteryChangedListener {
void onBatteryChanged(); void onBatteryChanged();
} }

View File

@@ -69,7 +69,7 @@ public class BatterySaverReceiver extends BroadcastReceiver {
mBatterySaverListener = lsn; mBatterySaverListener = lsn;
} }
interface BatterySaverListener { public interface BatterySaverListener {
void onPowerSaveModeChanged(); void onPowerSaveModeChanged();
void onBatteryChanged(boolean pluggedIn); void onBatteryChanged(boolean pluggedIn);
} }

View File

@@ -16,12 +16,21 @@
package com.android.settings.fuelgauge; package com.android.settings.fuelgauge;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
import android.app.usage.UsageStatsManager; import android.app.usage.UsageStatsManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceClickListener; import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.support.v7.preference.PreferenceGroup; import android.support.v7.preference.PreferenceGroup;
@@ -29,10 +38,22 @@ import android.support.v7.preference.PreferenceGroup;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment; import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.widget.RadioButtonPreference;
import java.util.List; import java.util.List;
public class InactiveApps extends SettingsPreferenceFragment implements OnPreferenceClickListener { public class InactiveApps extends SettingsPreferenceFragment
implements Preference.OnPreferenceChangeListener {
private static final CharSequence[] SETTABLE_BUCKETS_NAMES =
{"ACTIVE", "WORKING_SET", "FREQUENT", "RARE"};
private static final CharSequence[] SETTABLE_BUCKETS_VALUES = {
Integer.toString(STANDBY_BUCKET_ACTIVE),
Integer.toString(STANDBY_BUCKET_WORKING_SET),
Integer.toString(STANDBY_BUCKET_FREQUENT),
Integer.toString(STANDBY_BUCKET_RARE)
};
private UsageStatsManager mUsageStats; private UsageStatsManager mUsageStats;
@@ -68,29 +89,51 @@ public class InactiveApps extends SettingsPreferenceFragment implements OnPrefer
List<ResolveInfo> apps = pm.queryIntentActivities(launcherIntent, 0); List<ResolveInfo> apps = pm.queryIntentActivities(launcherIntent, 0);
for (ResolveInfo app : apps) { for (ResolveInfo app : apps) {
String packageName = app.activityInfo.applicationInfo.packageName; String packageName = app.activityInfo.applicationInfo.packageName;
Preference p = new Preference(getPrefContext()); ListPreference p = new ListPreference(getPrefContext());
p.setTitle(app.loadLabel(pm)); p.setTitle(app.loadLabel(pm));
p.setIcon(app.loadIcon(pm)); p.setIcon(app.loadIcon(pm));
p.setKey(packageName); p.setKey(packageName);
p.setEntries(SETTABLE_BUCKETS_NAMES);
p.setEntryValues(SETTABLE_BUCKETS_VALUES);
updateSummary(p); updateSummary(p);
p.setOnPreferenceClickListener(this); p.setOnPreferenceChangeListener(this);
screen.addPreference(p); screen.addPreference(p);
} }
} }
private void updateSummary(Preference p) { static String bucketToName(int bucket) {
boolean inactive = mUsageStats.isAppInactive(p.getKey()); switch (bucket) {
p.setSummary(inactive case STANDBY_BUCKET_EXEMPTED: return "EXEMPTED";
? R.string.inactive_app_inactive_summary case STANDBY_BUCKET_ACTIVE: return "ACTIVE";
: R.string.inactive_app_active_summary); case STANDBY_BUCKET_WORKING_SET: return "WORKING_SET";
case STANDBY_BUCKET_FREQUENT: return "FREQUENT";
case STANDBY_BUCKET_RARE: return "RARE";
case STANDBY_BUCKET_NEVER: return "NEVER";
}
return "";
}
private void updateSummary(ListPreference p) {
final Resources res = getActivity().getResources();
final int appBucket = mUsageStats.getAppStandbyBucket(p.getKey());
final String bucketName = bucketToName(appBucket);
p.setSummary(res.getString(R.string.standby_bucket_summary, bucketName));
// Buckets outside of the range of the dynamic ones are only used for special
// purposes and can either not be changed out of, or might have undesirable
// side-effects in combination with other assumptions.
final boolean changeable = appBucket >= STANDBY_BUCKET_ACTIVE
&& appBucket <= STANDBY_BUCKET_RARE;
if (changeable) {
p.setValue(Integer.toString(appBucket));
}
p.setEnabled(changeable);
} }
@Override @Override
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceChange(Preference preference, Object newValue) {
String packageName = preference.getKey(); mUsageStats.setAppStandbyBucket(preference.getKey(), Integer.parseInt((String) newValue));
mUsageStats.setAppInactive(packageName, !mUsageStats.isAppInactive(packageName)); updateSummary((ListPreference) preference);
updateSummary(preference);
return false; return false;
} }
} }

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2018 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.fuelgauge.batterysaver;
import android.content.Context;
import android.os.PowerManager;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import com.android.settings.fuelgauge.BatteryBroadcastReceiver;
import com.android.settings.fuelgauge.BatterySaverReceiver;
import com.android.settings.widget.TwoStateButtonPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
/**
* Controller to update the battery saver button
*/
public class BatterySaverButtonPreferenceController extends
TwoStateButtonPreferenceController implements
LifecycleObserver, OnStart, OnStop, BatterySaverReceiver.BatterySaverListener {
private static final String KEY = "battery_saver_button_container";
private BatterySaverReceiver mBatterySaverReceiver;
@VisibleForTesting
PowerManager mPowerManager;
public BatterySaverButtonPreferenceController(Context context, Lifecycle lifecycle) {
super(context, KEY);
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mBatterySaverReceiver = new BatterySaverReceiver(context);
mBatterySaverReceiver.setBatterySaverListener(this);
if (lifecycle != null) {
lifecycle.addObserver(this);
}
}
@Override
public void onStart() {
mBatterySaverReceiver.setListening(true);
}
@Override
public void onStop() {
mBatterySaverReceiver.setListening(false);
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
setButtonVisibility(!mPowerManager.isPowerSaveMode());
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
@Override
public void onButtonClicked(boolean stateOn) {
mPowerManager.setPowerSaveMode(stateOn);
}
@Override
public void onPowerSaveModeChanged() {
setButtonVisibility(!mPowerManager.isPowerSaveMode());
}
@Override
public void onBatteryChanged(boolean pluggedIn) {
setButtonEnabled(!pluggedIn);
}
}

View File

@@ -78,6 +78,7 @@ public class BatterySaverSettings extends DashboardFragment {
final List<AbstractPreferenceController> controllers = new ArrayList<>(); final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new AutoBatterySaverPreferenceController(context)); controllers.add(new AutoBatterySaverPreferenceController(context));
controllers.add(new AutoBatterySeekBarPreferenceController(context, lifecycle)); controllers.add(new AutoBatterySeekBarPreferenceController(context, lifecycle));
controllers.add(new BatterySaverButtonPreferenceController(context, lifecycle));
return controllers; return controllers;
} }

View File

@@ -28,6 +28,7 @@ import com.android.settings.R;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.SearchFeatureProvider; import com.android.settings.search.SearchFeatureProvider;
import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.ObservableFragment;
import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment; import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment;
import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu; import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu;
@@ -41,6 +42,10 @@ public class SearchMenuController implements LifecycleObserver, OnCreateOptionsM
host.getLifecycle().addObserver(new SearchMenuController(host)); host.getLifecycle().addObserver(new SearchMenuController(host));
} }
public static void init(@NonNull ObservableFragment host) {
host.getLifecycle().addObserver(new SearchMenuController(host));
}
private SearchMenuController(@NonNull Fragment host) { private SearchMenuController(@NonNull Fragment host) {
mHost = host; mHost = host;
} }

View File

@@ -44,6 +44,11 @@ public class VisiblePatternProfilePreferenceController extends TogglePreferenceC
private Preference mPreference; private Preference mPreference;
public VisiblePatternProfilePreferenceController(Context context) {
this(context, null /* lifecycle */);
}
// TODO (b/73074893) Replace this constructor without Lifecycle using setter method instead.
public VisiblePatternProfilePreferenceController(Context context, Lifecycle lifecycle) { public VisiblePatternProfilePreferenceController(Context context, Lifecycle lifecycle) {
super(context, KEY_VISIBLE_PATTERN_PROFILE); super(context, KEY_VISIBLE_PATTERN_PROFILE);
mUm = (UserManager) context.getSystemService(Context.USER_SERVICE); mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);

View File

@@ -27,6 +27,7 @@ import android.view.MenuInflater;
import com.android.settingslib.HelpUtils; import com.android.settingslib.HelpUtils;
import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.ObservableFragment;
import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment; import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment;
import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu; import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu;
@@ -41,6 +42,10 @@ public class HelpMenuController implements LifecycleObserver, OnCreateOptionsMen
host.getLifecycle().addObserver(new HelpMenuController(host)); host.getLifecycle().addObserver(new HelpMenuController(host));
} }
public static void init(@NonNull ObservableFragment host) {
host.getLifecycle().addObserver(new HelpMenuController(host));
}
private HelpMenuController(@NonNull Fragment host) { private HelpMenuController(@NonNull Fragment host) {
mHost = host; mHost = host;
} }

View File

@@ -83,6 +83,7 @@ public class MasterCheckBoxPreference extends TwoTargetPreference {
if (mCheckBox != null) { if (mCheckBox != null) {
mCheckBox.setContentDescription(getTitle()); mCheckBox.setContentDescription(getTitle());
mCheckBox.setChecked(mChecked); mCheckBox.setChecked(mChecked);
mCheckBox.setEnabled(mEnableCheckBox);
} }
} }

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2018 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.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.v4.content.res.TypedArrayUtils;
import android.util.AttributeSet;
import android.widget.Button;
import com.android.settings.R;
import com.android.settings.applications.LayoutPreference;
/**
* Preference that presents a button with two states(On vs Off)
*/
public class TwoStateButtonPreference extends LayoutPreference {
public TwoStateButtonPreference(Context context, AttributeSet attrs) {
super(context, attrs, TypedArrayUtils.getAttr(
context, R.attr.twoStateButtonPreferenceStyle, android.R.attr.preferenceStyle));
if (attrs != null) {
final TypedArray styledAttrs = context.obtainStyledAttributes(attrs,
R.styleable.TwoStateButtonPreference);
final int textOnId = styledAttrs.getResourceId(
R.styleable.TwoStateButtonPreference_textOn,
R.string.summary_placeholder);
final int textOffId = styledAttrs.getResourceId(
R.styleable.TwoStateButtonPreference_textOff,
R.string.summary_placeholder);
styledAttrs.recycle();
final Button buttonOn = getStateOnButton();
buttonOn.setText(textOnId);
final Button buttonOff = getStateOffButton();
buttonOff.setText(textOffId);
}
}
public Button getStateOnButton() {
return findViewById(R.id.state_on_button);
}
public Button getStateOffButton() {
return findViewById(R.id.state_off_button);
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2018 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.widget;
import android.content.Context;
import android.support.v7.preference.PreferenceScreen;
import android.view.View;
import android.widget.Button;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
/**
* Controller to update the button with two states(On vs Off).
*/
public abstract class TwoStateButtonPreferenceController extends BasePreferenceController
implements View.OnClickListener {
private Button mButtonOn;
private Button mButtonOff;
public TwoStateButtonPreferenceController(Context context, String key) {
super(context, key);
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
final TwoStateButtonPreference preference =
(TwoStateButtonPreference) screen.findPreference(getPreferenceKey());
mButtonOn = preference.getStateOnButton();
mButtonOn.setOnClickListener(this);
mButtonOff = preference.getStateOffButton();
mButtonOff.setOnClickListener(this);
}
protected void setButtonVisibility(boolean stateOn) {
if (stateOn) {
mButtonOff.setVisibility(View.GONE);
mButtonOn.setVisibility(View.VISIBLE);
} else {
mButtonOff.setVisibility(View.VISIBLE);
mButtonOn.setVisibility(View.GONE);
}
}
protected void setButtonEnabled(boolean enabled) {
mButtonOn.setEnabled(enabled);
mButtonOff.setEnabled(enabled);
}
@Override
public void onClick(View v) {
final boolean stateOn = v.getId() == R.id.state_on_button;
onButtonClicked(stateOn);
}
/**
* Callback when button is clicked
*
* @param stateOn {@code true} if stateOn button is clicked, otherwise it means stateOff
* button is clicked
*/
public abstract void onButtonClicked(boolean stateOn);
}

View File

@@ -14,11 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.settings; package com.android.settings.wifi.calling;
import android.app.Fragment; import android.app.Fragment;
import android.app.FragmentManager; import android.app.FragmentManager;
import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.support.v13.app.FragmentPagerAdapter; import android.support.v13.app.FragmentPagerAdapter;
import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionInfo;
@@ -28,9 +27,13 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.android.ims.ImsConfig;
import com.android.ims.ImsManager; import com.android.ims.ImsManager;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.core.InstrumentedFragment;
import com.android.settings.search.actionbar.SearchMenuController;
import com.android.settings.support.actionbar.HelpMenuController;
import com.android.settings.support.actionbar.HelpResourceProvider;
import com.android.settings.widget.RtlCompatibleViewPager; import com.android.settings.widget.RtlCompatibleViewPager;
import com.android.settings.widget.SlidingTabLayout; import com.android.settings.widget.SlidingTabLayout;
@@ -40,7 +43,7 @@ import java.util.List;
* "Wi-Fi Calling settings" screen. This is the container fragment which holds * "Wi-Fi Calling settings" screen. This is the container fragment which holds
* {@link WifiCallingSettingsForSub} fragments. * {@link WifiCallingSettingsForSub} fragments.
*/ */
public class WifiCallingSettings extends SettingsPreferenceFragment { public class WifiCallingSettings extends InstrumentedFragment implements HelpResourceProvider {
private static final String TAG = "WifiCallingSettings"; private static final String TAG = "WifiCallingSettings";
private List<SubscriptionInfo> mSil; private List<SubscriptionInfo> mSil;
@@ -71,6 +74,10 @@ public class WifiCallingSettings extends SettingsPreferenceFragment {
@Override @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle icicle) {
super.onCreate(icicle); super.onCreate(icicle);
setHasOptionsMenu(true);
SearchMenuController.init(this /* host */);
HelpMenuController.init(this /* host */);
// TODO: besides in onCreate, we should also update subList when SIM / Sub status // TODO: besides in onCreate, we should also update subList when SIM / Sub status
// changes. // changes.
updateSubList(); updateSubList();
@@ -87,6 +94,11 @@ public class WifiCallingSettings extends SettingsPreferenceFragment {
} }
} }
@Override
public int getHelpResource() {
return R.string.help_uri_wifi_calling;
}
private final class WifiCallingViewPagerAdapter extends FragmentPagerAdapter { private final class WifiCallingViewPagerAdapter extends FragmentPagerAdapter {
private final RtlCompatibleViewPager mViewPager; private final RtlCompatibleViewPager mViewPager;
@@ -105,6 +117,7 @@ public class WifiCallingSettings extends SettingsPreferenceFragment {
public Fragment getItem(int position) { public Fragment getItem(int position) {
Log.d(TAG, "Adapter getItem " + position); Log.d(TAG, "Adapter getItem " + position);
final Bundle args = new Bundle(); final Bundle args = new Bundle();
args.putBoolean(SearchMenuController.NEED_SEARCH_ICON_IN_ACTION_BAR, false);
args.putInt(WifiCallingSettingsForSub.FRAGMENT_BUNDLE_SUBID, args.putInt(WifiCallingSettingsForSub.FRAGMENT_BUNDLE_SUBID,
mSil.get(position).getSubscriptionId()); mSil.get(position).getSubscriptionId());
WifiCallingSettingsForSub fragment = new WifiCallingSettingsForSub(); WifiCallingSettingsForSub fragment = new WifiCallingSettingsForSub();
@@ -132,26 +145,6 @@ public class WifiCallingSettings extends SettingsPreferenceFragment {
} }
} }
public static int getWfcModeSummary(Context context, int wfcMode) {
int resId = com.android.internal.R.string.wifi_calling_off_summary;
if (ImsManager.isWfcEnabledByUser(context)) {
switch (wfcMode) {
case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY:
resId = com.android.internal.R.string.wfc_mode_wifi_only_summary;
break;
case ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED:
resId = com.android.internal.R.string.wfc_mode_cellular_preferred_summary;
break;
case ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED:
resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary;
break;
default:
Log.e(TAG, "Unexpected WFC mode value: " + wfcMode);
}
}
return resId;
}
private void updateSubList() { private void updateSubList() {
mSil = SubscriptionManager.from(getActivity()).getActiveSubscriptionInfoList(); mSil = SubscriptionManager.from(getActivity()).getActiveSubscriptionInfoList();
@@ -159,7 +152,7 @@ public class WifiCallingSettings extends SettingsPreferenceFragment {
if (mSil == null) { if (mSil == null) {
return; return;
} }
for (int i = 0; i < mSil.size();) { for (int i = 0; i < mSil.size(); ) {
ImsManager imsManager = ImsManager.getInstance(getActivity(), ImsManager imsManager = ImsManager.getInstance(getActivity(),
mSil.get(i).getSimSlotIndex()); mSil.get(i).getSimSlotIndex());
if (!imsManager.isWfcEnabledByPlatform()) { if (!imsManager.isWfcEnabledByPlatform()) {

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.settings; package com.android.settings.wifi.calling;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
@@ -45,6 +45,10 @@ import com.android.ims.ImsConfig;
import com.android.ims.ImsManager; import com.android.ims.ImsManager;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.telephony.Phone; import com.android.internal.telephony.Phone;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import com.android.settings.widget.SwitchBar; import com.android.settings.widget.SwitchBar;
/** /**
@@ -54,7 +58,7 @@ import com.android.settings.widget.SwitchBar;
public class WifiCallingSettingsForSub extends SettingsPreferenceFragment public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
implements SwitchBar.OnSwitchChangeListener, implements SwitchBar.OnSwitchChangeListener,
Preference.OnPreferenceChangeListener { Preference.OnPreferenceChangeListener {
private static final String TAG = "WifiCallingSettingsForSub"; private static final String TAG = "WifiCallingForSub";
//String keys for preference lookup //String keys for preference lookup
private static final String BUTTON_WFC_MODE = "wifi_calling_mode"; private static final String BUTTON_WFC_MODE = "wifi_calling_mode";
@@ -130,12 +134,6 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
} }
}; };
@Override
public int getHelpResource() {
// Helper resource is already defined in the container fragment.
return 0;
}
private final OnPreferenceClickListener mUpdateAddressListener = private final OnPreferenceClickListener mUpdateAddressListener =
new OnPreferenceClickListener() { new OnPreferenceClickListener() {
/* /*
@@ -226,8 +224,7 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
// SubId should always be specified when creating this fragment. Either through // SubId should always be specified when creating this fragment. Either through
// fragment.setArguments() or through savedInstanceState. // fragment.setArguments() or through savedInstanceState.
if (getArguments() != null && getArguments().containsKey(FRAGMENT_BUNDLE_SUBID)) if (getArguments() != null && getArguments().containsKey(FRAGMENT_BUNDLE_SUBID)) {
{
mSubId = getArguments().getInt(FRAGMENT_BUNDLE_SUBID); mSubId = getArguments().getInt(FRAGMENT_BUNDLE_SUBID);
} else if (savedInstanceState != null) { } else if (savedInstanceState != null) {
mSubId = savedInstanceState.getInt( mSubId = savedInstanceState.getInt(

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.settings.wifi; package com.android.settings.wifi.calling;
import android.content.Context; import android.content.Context;

View File

@@ -60,8 +60,7 @@ com.android.settings.applications.appinfo.PictureInPictureSettings
com.android.settings.applications.appinfo.PictureInPictureDetails com.android.settings.applications.appinfo.PictureInPictureDetails
com.android.settings.ApnSettings com.android.settings.ApnSettings
com.android.settings.PrivacySettings com.android.settings.PrivacySettings
com.android.settings.WifiCallingSettings com.android.settings.wifi.calling.WifiCallingSettingsForSub
com.android.settings.WifiCallingSettingsForSub
com.android.settings.password.SetupChooseLockGeneric$SetupChooseLockGenericFragment com.android.settings.password.SetupChooseLockGeneric$SetupChooseLockGenericFragment
com.android.settings.SetupRedactionInterstitial$SetupRedactionInterstitialFragment com.android.settings.SetupRedactionInterstitial$SetupRedactionInterstitialFragment
com.android.settings.security.trustagent.TrustAgentSettings com.android.settings.security.trustagent.TrustAgentSettings

View File

@@ -0,0 +1 @@
com.android.settings.testutils.FakeToggleController

View File

@@ -37,7 +37,9 @@ import com.android.settings.TestConfig;
import com.android.settings.applications.ProcStatsData; import com.android.settings.applications.ProcStatsData;
import com.android.settings.applications.ProcessStatsDetail; import com.android.settings.applications.ProcessStatsDetail;
import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowUserManager;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -48,7 +50,9 @@ import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class) @RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, shadows = {
ShadowUserManager.class
})
public class AppMemoryPreferenceControllerTest { public class AppMemoryPreferenceControllerTest {
@Mock @Mock
@@ -67,6 +71,7 @@ public class AppMemoryPreferenceControllerTest {
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application; mContext = RuntimeEnvironment.application;
ShadowUserManager.getShadow().setIsAdminUser(true);
mController = mController =
spy(new AppMemoryPreferenceController(mContext, mFragment, null /* lifecycle */)); spy(new AppMemoryPreferenceController(mContext, mFragment, null /* lifecycle */));
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
@@ -75,6 +80,11 @@ public class AppMemoryPreferenceControllerTest {
when(mFragment.getActivity()).thenReturn(mActivity); when(mFragment.getActivity()).thenReturn(mActivity);
} }
@After
public void tearDown() {
ShadowUserManager.getShadow().reset();
}
@Test @Test
public void getAvailabilityStatus_developmentSettingsEnabled_shouldReturnAvailable() { public void getAvailabilityStatus_developmentSettingsEnabled_shouldReturnAvailable() {
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.putInt(mContext.getContentResolver(),

View File

@@ -80,7 +80,7 @@ public class BluetoothDetailsHeaderControllerTest extends BluetoothDetailsContro
*/ */
@Test @Test
public void testContextMock() { public void testContextMock() {
assertThat(mContext.getString(R.string.bluetooth_connected)).isEqualTo("Connected"); assertThat(mContext.getString(R.string.bluetooth_connected)).isNotNull();
} }
@Test @Test

View File

@@ -0,0 +1,175 @@
/*
* Copyright (C) 2018 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.datausage;
import android.content.Context;
import android.content.Intent;
import android.net.NetworkTemplate;
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.NetworkPolicyEditor;
import com.android.settingslib.net.DataUsageController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.util.concurrent.TimeUnit;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class DataUsageSummaryPreferenceControllerTest {
private static final long UPDATE_BACKOFF_MS = TimeUnit.MINUTES.toMillis(13);
private static final long CYCLE_BACKOFF_MS = TimeUnit.DAYS.toMillis(6);
private static final long CYCLE_LENGTH_MS = TimeUnit.DAYS.toMillis(30);
private static final long USAGE1 = 373000000L;
private static final long LIMIT1 = 1000000000L;
private static final String CARRIER_NAME = "z-mobile";
private static final String PERIOD = "Feb";
@Mock
private DataUsageController mDataUsageController;
@Mock
private DataUsageInfoController mDataInfoController;
@Mock
private DataUsageSummaryPreference mSummaryPreference;
@Mock
private NetworkPolicyEditor mPolicyEditor;
@Mock
private NetworkTemplate mNetworkTemplate;
private Context mContext;
private DataUsageSummaryPreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mController = new DataUsageSummaryPreferenceController(
mContext,
mDataUsageController,
mDataInfoController,
mNetworkTemplate,
mPolicyEditor,
R.string.cell_data_template,
true,
null);
}
@Test
public void testSummaryUpdate_onePlan_basic() {
final long now = System.currentTimeMillis();
final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
final Intent intent = new Intent();
when(mDataUsageController.getDataUsageInfo()).thenReturn(info);
mController.setPlanValues(1 /* dataPlanCount */, LIMIT1, USAGE1);
mController.setCarrierValues(CARRIER_NAME, now - UPDATE_BACKOFF_MS, info.cycleEnd, intent);
mController.updateState(mSummaryPreference);
verify(mSummaryPreference).setLimitInfo(null);
verify(mSummaryPreference).setUsageInfo(info.cycleEnd, now - UPDATE_BACKOFF_MS,
CARRIER_NAME, 1 /* numPlans */, intent);
verify(mSummaryPreference).setChartEnabled(true);
}
@Test
public void testSummaryUpdate_noPlan_basic() {
final long now = System.currentTimeMillis();
final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
final Intent intent = new Intent();
when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info);
mController.setPlanValues(0 /* dataPlanCount */, LIMIT1, USAGE1);
mController.setCarrierValues(CARRIER_NAME, now - UPDATE_BACKOFF_MS, info.cycleEnd, intent);
mController.updateState(mSummaryPreference);
verify(mSummaryPreference).setLimitInfo("500 MB Data warning / 1.00 GB Data limit");
verify(mSummaryPreference).setUsageInfo(info.cycleEnd, now - UPDATE_BACKOFF_MS,
CARRIER_NAME, 0 /* numPlans */, intent);
verify(mSummaryPreference).setChartEnabled(true);
}
@Test
public void testSummaryUpdate_noCarrier_basic() {
final long now = System.currentTimeMillis();
final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info);
mController.setPlanValues(0 /* dataPlanCount */, LIMIT1, USAGE1);
mController.setCarrierValues(null /* carrierName */, -1L /* snapshotTime */,
info.cycleEnd, null /* intent */);
mController.updateState(mSummaryPreference);
verify(mSummaryPreference).setLimitInfo("500 MB Data warning / 1.00 GB Data limit");
verify(mSummaryPreference).setUsageInfo(
info.cycleEnd,
-1L /* snapshotTime */,
null /* carrierName */,
0 /* numPlans */,
null /* launchIntent */);
verify(mSummaryPreference).setChartEnabled(true);
}
@Test
public void testSummaryUpdate_noPlanData_basic() {
final long now = System.currentTimeMillis();
final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
when(mDataUsageController.getDataUsageInfo(any())).thenReturn(info);
mController.setPlanValues(0 /* dataPlanCount */, -1L /* dataPlanSize */, USAGE1);
mController.setCarrierValues(null /* carrierName */, -1L /* snapshotTime */,
info.cycleEnd, null /* intent */);
mController.updateState(mSummaryPreference);
verify(mSummaryPreference).setLimitInfo("500 MB Data warning / 1.00 GB Data limit");
verify(mSummaryPreference).setUsageInfo(
info.cycleEnd,
-1L /* snapshotTime */,
null /* carrierName */,
0 /* numPlans */,
null /* launchIntent */);
verify(mSummaryPreference).setChartEnabled(false);
}
private DataUsageController.DataUsageInfo createTestDataUsageInfo(long now) {
DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo();
info.carrier = CARRIER_NAME;
info.period = PERIOD;
info.startDate = now;
info.limitLevel = LIMIT1;
info.warningLevel = LIMIT1 >> 1;
info.usageLevel = USAGE1;
info.cycleStart = now - CYCLE_BACKOFF_MS;
info.cycleEnd = info.cycleStart + CYCLE_LENGTH_MS;
return info;
}
}

View File

@@ -0,0 +1,172 @@
/*
* Copyright (C) 2018 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.datausage;
import android.content.Context;
import android.content.Intent;
import android.support.v7.preference.PreferenceViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResourcesImpl;
import com.android.settingslib.utils.StringUtil;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, shadows =
SettingsShadowResourcesImpl.class)
public class DataUsageSummaryPreferenceTest {
private static final long CYCLE_DURATION_MILLIS = 1000000000L;
private static final long UPDATE_LAG_MILLIS = 10000000L;
private static final String DUMMY_CARRIER = "z-mobile";
private Context mContext;
private PreferenceViewHolder mHolder;
private DataUsageSummaryPreference mSummaryPreference;
private TextView mUsageTitle;
private TextView mCycleTime;
private TextView mCarrierInfo;
private TextView mDataLimits;
private Button mLaunchButton;
private long mCycleEnd;
private long mUpdateTime;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
mSummaryPreference = new DataUsageSummaryPreference(mContext, null /* attrs */);
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(mSummaryPreference.getLayoutResource(), null /* root */,
false /* attachToRoot */);
mHolder = PreferenceViewHolder.createInstanceForTests(view);
final long now = System.currentTimeMillis();
mCycleEnd = now + CYCLE_DURATION_MILLIS;
mUpdateTime = now - UPDATE_LAG_MILLIS;
}
@Test
public void testSetUsageInfo_withLaunchIntent_launchButtonShown() {
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 0 /* numPlans */,
new Intent());
bindViewHolder();
assertThat(mLaunchButton.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void testSetUsageInfo_withoutLaunchIntent_launchButtonNotShown() {
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 0 /* numPlans */,
null /* launchIntent */);
bindViewHolder();
assertThat(mLaunchButton.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void testSetUsageInfo_withDataPlans_carrierInfoShown() {
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 1 /* numPlans */,
new Intent());
bindViewHolder();
assertThat(mCarrierInfo.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void testSetUsageInfo_withNoDataPlans_carrierInfoNotShown() {
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 0 /* numPlans */,
new Intent());
bindViewHolder();
assertThat(mCarrierInfo.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void testSetUsageInfo_withNoDataPlans_usageTitleNotShown() {
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 0 /* numPlans */,
new Intent());
bindViewHolder();
assertThat(mUsageTitle.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void testSetUsageInfo_withMultipleDataPlans_usageTitleShown() {
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 2 /* numPlans */,
new Intent());
bindViewHolder();
assertThat(mUsageTitle.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void testSetUsageInfo_cycleRemainingTimeShown() {
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 0 /* numPlans */,
new Intent());
String cyclePrefix = StringUtil.formatElapsedTime(mContext, CYCLE_DURATION_MILLIS,
false /* withSeconds */).toString();
String text = mContext.getString(R.string.cycle_left_time_text, cyclePrefix);
bindViewHolder();
assertThat(mCycleTime.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mCycleTime.getText()).isEqualTo(text);
}
@Test
public void testSetLimitInfo_withLimitInfo_dataLimitsShown() {
final String limitText = "test limit text";
mSummaryPreference.setLimitInfo(limitText);
bindViewHolder();
assertThat(mDataLimits.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mDataLimits.getText()).isEqualTo(limitText);
}
@Test
public void testSetLimitInfo_withNullLimitInfo_dataLimitsNotShown() {
mSummaryPreference.setLimitInfo(null);
bindViewHolder();
assertThat(mDataLimits.getVisibility()).isEqualTo(View.GONE);
}
private void bindViewHolder() {
mSummaryPreference.onBindViewHolder(mHolder);
mUsageTitle = (TextView) mHolder.findViewById(R.id.usage_title);
mCycleTime = (TextView) mHolder.findViewById(R.id.cycle_left_time);
mCarrierInfo = (TextView) mHolder.findViewById(R.id.carrier_and_update);
mDataLimits = (TextView) mHolder.findViewById(R.id.data_limits);
mLaunchButton = (Button) mHolder.findViewById(R.id.launch_mdp_app_button);
}
}

View File

@@ -17,7 +17,6 @@
package com.android.settings.development; package com.android.settings.development;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
@@ -33,6 +32,7 @@ import com.android.settings.R;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.widget.SwitchBar; import com.android.settings.widget.SwitchBar;
import com.android.settings.widget.ToggleSwitch; import com.android.settings.widget.ToggleSwitch;
import com.android.settingslib.development.AbstractEnableAdbPreferenceController; import com.android.settingslib.development.AbstractEnableAdbPreferenceController;
@@ -52,7 +52,9 @@ import org.robolectric.util.ReflectionHelpers;
import java.util.List; import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class) @RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, shadows = {
ShadowUserManager.class
})
public class DevelopmentSettingsDashboardFragmentTest { public class DevelopmentSettingsDashboardFragmentTest {
private SwitchBar mSwitchBar; private SwitchBar mSwitchBar;
@@ -68,11 +70,13 @@ public class DevelopmentSettingsDashboardFragmentTest {
mSwitch = mSwitchBar.getSwitch(); mSwitch = mSwitchBar.getSwitch();
mDashboard = spy(new DevelopmentSettingsDashboardFragment()); mDashboard = spy(new DevelopmentSettingsDashboardFragment());
ReflectionHelpers.setField(mDashboard, "mSwitchBar", mSwitchBar); ReflectionHelpers.setField(mDashboard, "mSwitchBar", mSwitchBar);
ShadowUserManager.getShadow().setIsAdminUser(true);
} }
@After @After
public void tearDown() { public void tearDown() {
ShadowEnableDevelopmentSettingWarningDialog.reset(); ShadowEnableDevelopmentSettingWarningDialog.reset();
ShadowUserManager.getShadow().reset();
} }
@Test @Test
@@ -101,7 +105,7 @@ public class DevelopmentSettingsDashboardFragmentTest {
SettingsShadowResources.class, SettingsShadowResources.class,
SettingsShadowResources.SettingsShadowTheme.class SettingsShadowResources.SettingsShadowTheme.class
}) })
public void searchIndex_pageDisabled_shouldAddAllKeysToNonIndexable() { public void searchIndex_pageDisabledBySetting_shouldAddAllKeysToNonIndexable() {
final Context appContext = RuntimeEnvironment.application; final Context appContext = RuntimeEnvironment.application;
DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(appContext, false); DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(appContext, false);
@@ -109,7 +113,24 @@ public class DevelopmentSettingsDashboardFragmentTest {
DevelopmentSettingsDashboardFragment.SEARCH_INDEX_DATA_PROVIDER DevelopmentSettingsDashboardFragment.SEARCH_INDEX_DATA_PROVIDER
.getNonIndexableKeys(appContext); .getNonIndexableKeys(appContext);
assertThat(nonIndexableKeys).contains("development_prefs_screen"); assertThat(nonIndexableKeys).contains("enable_adb");
}
@Test
@Config(shadows = {
SettingsShadowResources.class,
SettingsShadowResources.SettingsShadowTheme.class
})
public void searchIndex_pageDisabledForNonAdmin_shouldAddAllKeysToNonIndexable() {
final Context appContext = RuntimeEnvironment.application;
DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(appContext, true);
ShadowUserManager.getShadow().setIsAdminUser(false);
final List<String> nonIndexableKeys =
DevelopmentSettingsDashboardFragment.SEARCH_INDEX_DATA_PROVIDER
.getNonIndexableKeys(appContext);
assertThat(nonIndexableKeys).contains("enable_adb");
} }
@Test @Test

View File

@@ -28,6 +28,7 @@ import android.content.Context;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.testutils.shadow.ShadowUtils; import com.android.settings.testutils.shadow.ShadowUtils;
import com.android.settings.widget.SwitchBar; import com.android.settings.widget.SwitchBar;
import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -47,7 +48,8 @@ import java.util.ArrayList;
@RunWith(SettingsRobolectricTestRunner.class) @RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
shadows = { shadows = {
ShadowUtils.class ShadowUtils.class,
ShadowUserManager.class
}) })
public class DevelopmentSwitchBarControllerTest { public class DevelopmentSwitchBarControllerTest {
@@ -63,6 +65,7 @@ public class DevelopmentSwitchBarControllerTest {
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application; mContext = RuntimeEnvironment.application;
ShadowUserManager.getShadow().setIsAdminUser(true);
mLifecycleOwner = () -> mLifecycle; mLifecycleOwner = () -> mLifecycle;
mLifecycle = new Lifecycle(mLifecycleOwner); mLifecycle = new Lifecycle(mLifecycleOwner);
mSwitchBar = new SwitchBar(mContext); mSwitchBar = new SwitchBar(mContext);
@@ -72,6 +75,7 @@ public class DevelopmentSwitchBarControllerTest {
@After @After
public void tearDown() { public void tearDown() {
ShadowUtils.reset(); ShadowUtils.reset();
ShadowUserManager.getShadow().reset();
} }
@Test @Test

View File

@@ -43,6 +43,7 @@ import com.android.settings.search.DatabaseIndexingManager;
import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowUtils; import com.android.settings.testutils.shadow.ShadowUtils;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.development.DevelopmentSettingsEnabler; import com.android.settingslib.development.DevelopmentSettingsEnabler;
@@ -60,7 +61,8 @@ import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class) @RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
shadows = { shadows = {
ShadowUtils.class ShadowUtils.class,
ShadowUserManager.class,
}) })
public class BuildNumberPreferenceControllerTest { public class BuildNumberPreferenceControllerTest {
@@ -84,6 +86,7 @@ public class BuildNumberPreferenceControllerTest {
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
ShadowUserManager.getShadow().setIsAdminUser(true);
mFactory = FakeFeatureFactory.setupForTest(); mFactory = FakeFeatureFactory.setupForTest();
mLifecycleOwner = () -> mLifecycle; mLifecycleOwner = () -> mLifecycle;
mLifecycle = new Lifecycle(mLifecycleOwner); mLifecycle = new Lifecycle(mLifecycleOwner);
@@ -98,6 +101,7 @@ public class BuildNumberPreferenceControllerTest {
@After @After
public void tearDown() { public void tearDown() {
ShadowUtils.reset(); ShadowUtils.reset();
ShadowUserManager.getShadow().reset();
} }
@Test @Test

View File

@@ -21,15 +21,18 @@ import static com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.PreferenceScreen;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment; import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
@@ -39,6 +42,7 @@ import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settings.testutils.shadow.SettingsShadowSystemProperties; import com.android.settings.testutils.shadow.SettingsShadowSystemProperties;
import com.android.settings.testutils.shadow.ShadowConnectivityManager; import com.android.settings.testutils.shadow.ShadowConnectivityManager;
import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settingslib.core.AbstractPreferenceController;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -48,6 +52,11 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication; import org.robolectric.shadows.ShadowApplication;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@RunWith(SettingsRobolectricTestRunner.class) @RunWith(SettingsRobolectricTestRunner.class)
@Config( @Config(
@@ -97,4 +106,23 @@ public class MyDeviceInfoFragmentTest {
verify(mScreen).setInitialExpandedChildrenCount(Integer.MAX_VALUE); verify(mScreen).setInitialExpandedChildrenCount(Integer.MAX_VALUE);
} }
@Test
public void onActivityResult_shouldCallBuildNumberPreferenceController() {
final BuildNumberPreferenceController controller =
mock(BuildNumberPreferenceController.class);
final Map<Class, List<AbstractPreferenceController>> preferenceControllers =
new ArrayMap<>();
final List<AbstractPreferenceController> controllerList = new ArrayList<>();
controllerList.add(controller);
preferenceControllers.put(BuildNumberPreferenceController.class, controllerList);
ReflectionHelpers.setField(mSettings, "mPreferenceControllers", preferenceControllers);
final int requestCode = 1;
final int resultCode = 2;
final Intent data = new Intent();
mSettings.onActivityResult(requestCode, resultCode, data);
verify(controller).onActivityResult(requestCode, resultCode, data);
}
} }

View File

@@ -220,4 +220,9 @@ public class BatteryAppListPreferenceControllerTest {
assertThat(mPreferenceController.isAvailable()).isFalse(); assertThat(mPreferenceController.isAvailable()).isFalse();
} }
@Test
public void testNeverUseFakeData() {
assertThat(BatteryAppListPreferenceController.USE_FAKE_DATA).isFalse();
}
} }

View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2018 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.fuelgauge.batterysaver;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.arch.lifecycle.LifecycleOwner;
import android.content.Context;
import android.os.PowerManager;
import android.support.v7.preference.PreferenceScreen;
import android.view.View;
import android.widget.Button;
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.TwoStateButtonPreference;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowPowerManager;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
shadows = com.android.settings.testutils.shadow.ShadowPowerManager.class)
public class BatterySaverButtonPreferenceControllerTest {
private BatterySaverButtonPreferenceController mController;
private Context mContext;
private Lifecycle mLifecycle;
private LifecycleOwner mLifecycleOwner;
private Button mButtonOn;
private Button mButtonOff;
private ShadowPowerManager mShadowPowerManager;
@Mock
private TwoStateButtonPreference mPreference;
@Mock
private PreferenceScreen mPreferenceScreen;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mLifecycleOwner = () -> mLifecycle;
mLifecycle = new Lifecycle(mLifecycleOwner);
mContext = spy(RuntimeEnvironment.application);
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mShadowPowerManager = Shadows.shadowOf(powerManager);
doReturn(mPreference).when(mPreferenceScreen).findPreference(anyString());
mButtonOn = new Button(mContext);
mButtonOn.setId(R.id.state_on_button);
doReturn(mButtonOn).when(mPreference).getStateOnButton();
mButtonOff = new Button(mContext);
mButtonOff.setId(R.id.state_off_button);
doReturn(mButtonOff).when(mPreference).getStateOffButton();
mController = new BatterySaverButtonPreferenceController(mContext, mLifecycle);
mController.displayPreference(mPreferenceScreen);
}
@Test
public void testUpdateState_lowPowerOn_displayButtonOff() {
mShadowPowerManager.setIsPowerSaveMode(true);
mController.updateState(mPreference);
assertThat(mButtonOn.getVisibility()).isEqualTo(View.GONE);
assertThat(mButtonOff.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void testUpdateState_lowPowerOff_displayButtonOn() {
mShadowPowerManager.setIsPowerSaveMode(false);
mController.updateState(mPreference);
assertThat(mButtonOn.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mButtonOff.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void testOnClick_clickButtonOn_setPowerSaveMode() {
mController.onClick(mButtonOn);
assertThat(mShadowPowerManager.isPowerSaveMode()).isTrue();
}
@Test
public void testOnClick_clickButtonOff_clearPowerSaveMode() {
mController.onClick(mButtonOff);
assertThat(mShadowPowerManager.isPowerSaveMode()).isFalse();
}
}

View File

@@ -137,7 +137,6 @@ public class BaseSearchIndexProviderTest {
final List<String> nonIndexableKeys = provider final List<String> nonIndexableKeys = provider
.getNonIndexableKeys(RuntimeEnvironment.application); .getNonIndexableKeys(RuntimeEnvironment.application);
assertThat(nonIndexableKeys).containsAllOf("status_header", "limit_summary", assertThat(nonIndexableKeys).contains("status_header");
"restrict_background");
} }
} }

View File

@@ -18,6 +18,7 @@ package com.android.settings.search.actionbar;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.os.Bundle; import android.os.Bundle;
@@ -27,6 +28,7 @@ import android.view.MenuItem;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.ObservableFragment;
import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment; import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment;
import org.junit.Before; import org.junit.Before;
@@ -42,26 +44,47 @@ public class SearchMenuControllerTest {
@Mock @Mock
private Menu mMenu; private Menu mMenu;
private TestFragment mHost; private TestPreferenceFragment mPreferenceHost;
private ObservableFragment mHost;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mHost = new TestFragment(); mHost = new ObservableFragment();
mPreferenceHost = new TestPreferenceFragment();
when(mMenu.add(Menu.NONE, Menu.NONE, 0 /* order */, R.string.search_menu))
.thenReturn(mock(MenuItem.class));
} }
@Test @Test
public void init_shouldAddMenu() { public void init_prefFragment_shouldAddMenu() {
when(mMenu.add(Menu.NONE, Menu.NONE, 0 /* order */, R.string.search_menu)) SearchMenuController.init(mPreferenceHost);
.thenReturn(mock(MenuItem.class)); mPreferenceHost.getLifecycle().onCreateOptionsMenu(mMenu, null /* inflater */);
verify(mMenu).add(Menu.NONE, Menu.NONE, 0 /* order */, R.string.search_menu);
}
@Test
public void init_observableFragment_shouldAddMenu() {
SearchMenuController.init(mHost); SearchMenuController.init(mHost);
mHost.getLifecycle().onCreateOptionsMenu(mMenu, null /* inflater */); mHost.getLifecycle().onCreateOptionsMenu(mMenu, null /* inflater */);
verify(mMenu).add(Menu.NONE, Menu.NONE, 0 /* order */, R.string.search_menu); verify(mMenu).add(Menu.NONE, Menu.NONE, 0 /* order */, R.string.search_menu);
} }
public static class TestFragment extends ObservablePreferenceFragment { @Test
public void init_doNotNeedSearchIcon_shouldNotAddMenu() {
final Bundle args = new Bundle();
args.putBoolean(SearchMenuController.NEED_SEARCH_ICON_IN_ACTION_BAR, false);
mHost.setArguments(args);
SearchMenuController.init(mHost);
mHost.getLifecycle().onCreateOptionsMenu(mMenu, null /* inflater */);
verifyZeroInteractions(mMenu);
}
public static class TestPreferenceFragment extends ObservablePreferenceFragment {
@Override @Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {

View File

@@ -31,6 +31,7 @@ import android.net.Uri;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
import com.android.settings.testutils.DatabaseTestUtils; import com.android.settings.testutils.DatabaseTestUtils;
import com.android.settings.testutils.FakeToggleController;
import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.After; import org.junit.After;

View File

@@ -31,6 +31,7 @@ import com.android.settings.search.FakeIndexProvider;
import com.android.settings.search.SearchFeatureProvider; import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.search.SearchFeatureProviderImpl; import com.android.settings.search.SearchFeatureProviderImpl;
import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.FakeToggleController;
import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.After; import org.junit.After;

View File

@@ -29,6 +29,7 @@ import android.net.Uri;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
import com.android.settings.testutils.FakeToggleController;
import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before; import org.junit.Before;

View File

@@ -0,0 +1,201 @@
/*
* Copyright (C) 2018 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.slices;
import static com.android.settings.TestConfig.SDK_VERSION;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.Mockito.spy;
import android.content.Context;
import android.content.res.XmlResourceParser;
import android.provider.SearchIndexableResource;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Xml;
import com.android.settings.TestConfig;
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.core.codeinspection.ClassScanner;
import com.android.settings.core.codeinspection.CodeInspector;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.DatabaseIndexingUtils;
import com.android.settings.search.Indexable;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.search.SearchFeatureProviderImpl;
import com.android.settings.search.XmlParserUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.xmlpull.v1.XmlPullParser;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = SDK_VERSION)
public class SliceControllerInXmlTest {
private static final List<Class> mSliceControllerClasses = new ArrayList<>(Arrays.asList(
TogglePreferenceController.class
));
private final List<String> mXmlDeclaredControllers = new ArrayList<>();
private final List<String> mGrandfatheredClasses = new ArrayList<>();
private final String ERROR_MISSING_CONTROLLER =
"The following controllers were expected to be declared by "
+ "'settings:controller=Controller_Class_Name' in their corresponding Xml. "
+ "If it should not appear in XML, add the controller's classname to "
+ "grandfather_slice_controller_not_in_xml. Controllers:\n";
private Context mContext;
SearchFeatureProvider mSearchProvider;
private FakeFeatureFactory mFakeFeatureFactory;
@Before
public void setUp() {
mContext = spy(RuntimeEnvironment.application);
mSearchProvider = new SearchFeatureProviderImpl();
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mFakeFeatureFactory.searchFeatureProvider = mSearchProvider;
CodeInspector.initializeGrandfatherList(mGrandfatheredClasses,
"grandfather_slice_controller_not_in_xml");
initDeclaredControllers();
}
private void initDeclaredControllers() {
final List<Integer> xmlResources = getIndexableXml();
XmlResourceParser parser;
for (int xmlResId : xmlResources) {
try {
parser = mContext.getResources().getXml(xmlResId);
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& type != XmlPullParser.START_TAG) {
// Parse next until start tag is found
}
final int outerDepth = parser.getDepth();
final AttributeSet attrs = Xml.asAttributeSet(parser);
String controllerClassName;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
controllerClassName = XmlParserUtils.getController(mContext, attrs);
if (!TextUtils.isEmpty(controllerClassName)) {
mXmlDeclaredControllers.add(controllerClassName);
}
}
} catch (Exception e) {
// Assume an issue with robolectric resources
}
}
}
@Test
public void testAllControllersDeclaredInXml() throws Exception {
final List<Class<?>> classes = new ClassScanner().getClassesForPackage(
mContext.getPackageName());
final List<String> missingControllersInXml = new ArrayList<>();
for (Class<?> clazz : classes) {
if (!isInlineSliceClass(clazz)) {
// Only care about inline-slice controller classes.
continue;
}
if (!mXmlDeclaredControllers.contains(clazz.getName())) {
// Class clazz should have been declared in XML (unless whitelisted).
missingControllersInXml.add(clazz.getName());
}
}
// Removed whitelisted classes
missingControllersInXml.removeAll(mGrandfatheredClasses);
final String missingControllerError = buildErrorMessage(ERROR_MISSING_CONTROLLER,
missingControllersInXml);
assertWithMessage(missingControllerError).that(missingControllersInXml).isEmpty();
}
private boolean isInlineSliceClass(Class clazz) {
while (clazz != null) {
clazz = clazz.getSuperclass();
if (mSliceControllerClasses.contains(clazz)) {
return true;
}
}
return false;
}
private String buildErrorMessage(String errorSummary, List<String> errorClasses) {
final StringBuilder error = new StringBuilder(errorSummary);
for (String c : errorClasses) {
error.append(c).append("\n");
}
return error.toString();
}
private List<Integer> getIndexableXml() {
final List<Integer> xmlResSet = new ArrayList<>();
final Collection<Class> indexableClasses = FeatureFactory.getFactory(
mContext).getSearchFeatureProvider().getSearchIndexableResources()
.getProviderValues();
for (Class clazz : indexableClasses) {
Indexable.SearchIndexProvider provider = DatabaseIndexingUtils.getSearchIndexProvider(
clazz);
if (provider == null) {
continue;
}
List<SearchIndexableResource> resources = provider.getXmlResourcesToIndex(mContext,
true);
if (resources == null) {
continue;
}
for (SearchIndexableResource resource : resources) {
// Add '0's anyway. It won't break the test.
xmlResSet.add(resource.xmlResId);
}
}
return xmlResSet;
}
}

View File

@@ -68,7 +68,7 @@ public class SettingsSuggestionsTest {
@Test @Test
public void wifiCallingSuggestion_isValid() { public void wifiCallingSuggestion_isValid() {
assertSuggestionEquals("com.android.settings.wifi.WifiCallingSuggestionActivity", assertSuggestionEquals("com.android.settings.wifi.calling.WifiCallingSuggestionActivity",
CATEGORY_FIRST_IMPRESSION, CATEGORY_FIRST_IMPRESSION,
R.string.wifi_calling_suggestion_title, R.string.wifi_calling_suggestion_summary); R.string.wifi_calling_suggestion_title, R.string.wifi_calling_suggestion_summary);
} }

View File

@@ -15,7 +15,7 @@
* *
*/ */
package com.android.settings.slices; package com.android.settings.testutils;
import android.content.Context; import android.content.Context;
import android.provider.Settings; import android.provider.Settings;

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2018 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.testutils.shadow;
import android.os.PowerManager;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@Implements(PowerManager.class)
public class ShadowPowerManager extends org.robolectric.shadows.ShadowPowerManager {
@Implementation
public boolean setPowerSaveMode(boolean mode) {
setIsPowerSaveMode(mode);
return true;
}
}

View File

@@ -105,6 +105,24 @@ public class MasterCheckBoxPreferenceTest {
assertThat(checkBox.isEnabled()).isTrue(); assertThat(checkBox.isEnabled()).isTrue();
} }
@Test
public void onBindViewHolder_shouldSetCheckboxEnabledState() {
final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
LayoutInflater.from(mContext).inflate(
R.layout.preference_widget_master_checkbox, null));
final CheckBox checkBox = (CheckBox) holder.findViewById(R.id.checkboxWidget);
mPreference.setCheckBoxEnabled(false);
mPreference.onBindViewHolder(holder);
assertThat(mPreference.isEnabled()).isTrue();
assertThat(checkBox.isEnabled()).isFalse();
mPreference.setCheckBoxEnabled(true);
assertThat(mPreference.isEnabled()).isTrue();
assertThat(checkBox.isEnabled()).isTrue();
}
@Test @Test
public void clickWidgetView_shouldToggleCheckBox() { public void clickWidgetView_shouldToggleCheckBox() {
final LayoutInflater inflater = LayoutInflater.from(mContext); final LayoutInflater inflater = LayoutInflater.from(mContext);

View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2018 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.widget;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import android.content.Context;
import android.support.v7.preference.PreferenceScreen;
import android.view.View;
import android.widget.Button;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class TwoStateButtonPreferenceControllerTest {
private static final String KEY = "pref_key";
@Mock
private PreferenceScreen mPreferenceScreen;
@Mock
private TwoStateButtonPreference mPreference;
private TwoStateButtonPreferenceController mController;
private Context mContext;
private Button mButtonOn;
private Button mButtonOff;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
doReturn(mPreference).when(mPreferenceScreen).findPreference(anyString());
mButtonOn = new Button(mContext);
doReturn(mButtonOn).when(mPreference).getStateOnButton();
mButtonOff = new Button(mContext);
doReturn(mButtonOff).when(mPreference).getStateOffButton();
mController = new TestButtonsPreferenceController(mContext, KEY);
mController.displayPreference(mPreferenceScreen);
}
@Test
public void testSetButtonVisibility_stateOn_onlyShowButtonOn() {
mController.setButtonVisibility(true /* stateOn */);
assertThat(mButtonOn.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mButtonOff.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void testSetButtonVisibility_stateOff_onlyShowButtonOff() {
mController.setButtonVisibility(false /* stateOn */);
assertThat(mButtonOn.getVisibility()).isEqualTo(View.GONE);
assertThat(mButtonOff.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void testSetButtonEnabled_enabled_buttonEnabled() {
mController.setButtonEnabled(true /* enabled */);
assertThat(mButtonOn.isEnabled()).isTrue();
assertThat(mButtonOff.isEnabled()).isTrue();
}
@Test
public void testSetButtonEnabled_disabled_buttonDisabled() {
mController.setButtonEnabled(false /* enabled */);
assertThat(mButtonOn.isEnabled()).isFalse();
assertThat(mButtonOff.isEnabled()).isFalse();
}
/**
* Controller to test methods in {@link TwoStateButtonPreferenceController}
*/
public static class TestButtonsPreferenceController extends
TwoStateButtonPreferenceController {
TestButtonsPreferenceController(Context context, String key) {
super(context, key);
}
@Override
public void onButtonClicked(boolean stateOn) {
//do nothing
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
}
}

View File

@@ -53,6 +53,15 @@
<meta-data android:name="com.android.settings.summary" android:resource="@string/manufacturer_settings_summary" /> <meta-data android:name="com.android.settings.summary" android:resource="@string/manufacturer_settings_summary" />
<meta-data android:name="com.android.settings.icon" android:resource="@drawable/ic_settings_applications" /> <meta-data android:name="com.android.settings.icon" android:resource="@drawable/ic_settings_applications" />
</activity> </activity>
<service android:name="com.android.settings.accounts.TestAuthService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>
</application> </application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"

View File

@@ -28,4 +28,7 @@
<string name="manufacturer_hello" translatable="false">Hello Manufacturer!</string> <string name="manufacturer_hello" translatable="false">Hello Manufacturer!</string>
<string name="manufacturer_settings_title" translatable="false">Manufacturer</string> <string name="manufacturer_settings_title" translatable="false">Manufacturer</string>
<string name="manufacturer_settings_summary" translatable="false">Manufacturer hook that can be used to start activity of choice</string> <string name="manufacturer_settings_summary" translatable="false">Manufacturer hook that can be used to start activity of choice</string>
<string name="account_auth_label" translatable="false">Settings Test Account</string>
<string name="account_type" translatable="false">com.settingstest.account-prefs</string>
<string name="account_pref_title" translatable="false">Test preference for external account</string>
</resources> </resources>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 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.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<SwitchPreference
android:key="account_test_switch"
android:title="@string/account_pref_title" />
</PreferenceScreen>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 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.
-->
<account-authenticator
xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/account_auth_label"
android:icon="@drawable/ic_settings_applications"
android:accountType="@string/account_type"
android:accountPreferences="@xml/account_preferences" />

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2018 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.accounts;
import static com.google.common.truth.Truth.assertThat;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.content.Intent;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.UiScrollable;
import android.support.test.uiautomator.UiObjectNotFoundException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class AccountsSettingsTest {
private static final String ACCOUNTS = "Accounts";
private static final String ACCOUNT_TYPE = "com.settingstest.account-prefs";
private static final String PREF_TITLE = "Test preference for external account";
private UiDevice mDevice;
private Context mContext;
private String mTargetPackage;
@Before
public void setUp() {
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mContext = InstrumentationRegistry.getTargetContext();
mTargetPackage = mContext.getPackageName();
}
@Test
public void testExternalAccountInfoExists() throws UiObjectNotFoundException {
// add a test account
final String testAccountName = "Test Account";
final Account account = new Account(testAccountName, ACCOUNT_TYPE);
final AccountManager accountManager = AccountManager.get(mContext);
final boolean accountAdded =
accountManager.addAccountExplicitly(account, null /* password */, null /* userdata */);
assertThat(accountAdded).isTrue();
// launch Accounts Settings and select the test account
launchAccountsSettings();
mDevice.findObject(new UiSelector().text(testAccountName)).click();
final UiObject testPreference = mDevice.findObject(new UiSelector().text(PREF_TITLE));
// remove test account
accountManager.removeAccountExplicitly(account);
assertThat(testPreference.exists()).isTrue();
}
private void launchAccountsSettings() throws UiObjectNotFoundException {
// launch settings
Intent settingsIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER)
.setPackage(mTargetPackage)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(settingsIntent);
// selects Accounts
final UiScrollable settings = new UiScrollable(
new UiSelector().packageName(mTargetPackage).scrollable(true));
final String titleAccounts = ACCOUNTS;
settings.scrollTextIntoView(titleAccounts);
mDevice.findObject(new UiSelector().text(titleAccounts)).click();
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2018 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.accounts;
import android.accounts.AbstractAccountAuthenticator;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.accounts.NetworkErrorException;
import android.content.Context;
import android.os.Bundle;
public class Authenticator extends AbstractAccountAuthenticator {
public Authenticator(Context context) {
super(context);
}
@Override
public Bundle editProperties(AccountAuthenticatorResponse r, String s) {
return null;
}
@Override
public Bundle addAccount(AccountAuthenticatorResponse r, String s, String s2, String[] strings,
Bundle bundle) throws NetworkErrorException {
final Bundle result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, "Test Account");
result.putString(AccountManager.KEY_ACCOUNT_TYPE, s);
return result;
}
@Override
public Bundle confirmCredentials(AccountAuthenticatorResponse r, Account account, Bundle bundle)
throws NetworkErrorException {
return null;
}
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse r, Account account, String s,
Bundle bundle) throws NetworkErrorException {
return null;
}
@Override
public String getAuthTokenLabel(String s) {
return s;
}
@Override
public Bundle updateCredentials(AccountAuthenticatorResponse r, Account account, String s,
Bundle bundle) throws NetworkErrorException {
return null;
}
@Override
public Bundle hasFeatures(AccountAuthenticatorResponse r, Account account, String[] strings)
throws NetworkErrorException {
return null;
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2018 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.accounts;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class TestAuthService extends Service {
private Authenticator mAuthenticator;
@Override
public void onCreate() {
mAuthenticator = new Authenticator(this);
}
@Override
public IBinder onBind(Intent intent) {
return mAuthenticator.getIBinder();
}
}

View File

@@ -15,34 +15,47 @@
*/ */
package com.android.settings.users; package com.android.settings.users;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest; import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiSelector; import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.UiScrollable; import android.support.test.uiautomator.UiScrollable;
import android.test.InstrumentationTestCase; import android.support.test.uiautomator.UiObjectNotFoundException;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest @SmallTest
public class UserSettingsTest extends InstrumentationTestCase { public class UserSettingsTest {
private static final String USER_AND_ACCOUNTS = "Users & accounts"; private static final String SYSTEM = "System";
private static final String USERS = "Users"; private static final String ADVANCED = "Advanced";
private static final String USERS = "Multiple users";
private static final String EMERGNENCY_INFO = "Emergency information"; private static final String EMERGNENCY_INFO = "Emergency information";
private static final String ADD_USERS_WHEN_LOCKED = "Add users"; private static final String ADD_USERS_WHEN_LOCKED = "Add users";
private static final String SWITCH_USER_BUTTON = "com.android.systemui:id/multi_user_switch";
private static final String SETTINGS_BUTTON = "com.android.systemui:id/settings_button";
private static final String PRIMARY_USER = "Owner";
private static final String GUEST_USER = "Guest";
private static final String ADD_GUEST = "Add guest";
private static final String CONTINUE = "Yes, continue";
private UiDevice mDevice; private UiDevice mDevice;
private Context mContext; private Context mContext;
private String mTargetPackage; private String mTargetPackage;
@Override @Before
protected void setUp() throws Exception { public void setUp() {
super.setUp(); mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mDevice = UiDevice.getInstance(getInstrumentation()); mContext = InstrumentationRegistry.getTargetContext();
mContext = getInstrumentation().getTargetContext();
mTargetPackage = mContext.getPackageName(); mTargetPackage = mContext.getPackageName();
} }
@@ -51,7 +64,8 @@ public class UserSettingsTest extends InstrumentationTestCase {
launchUserSettings(); launchUserSettings();
UiObject emergencyInfoPreference = UiObject emergencyInfoPreference =
mDevice.findObject(new UiSelector().text(EMERGNENCY_INFO)); mDevice.findObject(new UiSelector().text(EMERGNENCY_INFO));
assertFalse(emergencyInfoPreference.exists());
assertThat(emergencyInfoPreference.exists()).isFalse();
} }
@Test @Test
@@ -59,7 +73,32 @@ public class UserSettingsTest extends InstrumentationTestCase {
launchUserSettings(); launchUserSettings();
UiObject addUsersPreference = UiObject addUsersPreference =
mDevice.findObject(new UiSelector().text(ADD_USERS_WHEN_LOCKED)); mDevice.findObject(new UiSelector().text(ADD_USERS_WHEN_LOCKED));
assertFalse(addUsersPreference.exists()); assertThat(addUsersPreference.exists()).isFalse();
}
@Test
public void testUsersExistsOnSecondaryUser() throws Exception {
// switch to guest user
switchToOrCreateGuest();
// launch settings (launch from intent doesn't work, hence launch from quick settings)
mDevice.openQuickSettings();
mDevice.findObject(new UiSelector().resourceId(SETTINGS_BUTTON)).click();
// launch system settings and expand whole screen
final UiScrollable settings = new UiScrollable(
new UiSelector().packageName(mTargetPackage).scrollable(true));
final String titleSystem = SYSTEM;
settings.scrollTextIntoView(titleSystem);
mDevice.findObject(new UiSelector().text(titleSystem)).click();
mDevice.findObject(new UiSelector().text(ADVANCED)).click();
final boolean hasUsersSettings = mDevice.findObject(new UiSelector().text(USERS)).exists();
// switch back to primary user
mDevice.openQuickSettings();
mDevice.findObject(new UiSelector().resourceId(SWITCH_USER_BUTTON)).click();
mDevice.findObject(new UiSelector().text(PRIMARY_USER)).click();
assertThat(hasUsersSettings).isTrue();
} }
private void launchSettings() { private void launchSettings() {
@@ -67,17 +106,34 @@ public class UserSettingsTest extends InstrumentationTestCase {
.addCategory(Intent.CATEGORY_LAUNCHER) .addCategory(Intent.CATEGORY_LAUNCHER)
.setPackage(mTargetPackage) .setPackage(mTargetPackage)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getInstrumentation().getContext().startActivity(settingsIntent); mContext.startActivity(settingsIntent);
} }
private void launchUserSettings() throws Exception { private void launchUserSettings() throws Exception {
launchSettings(); launchSettings();
final UiScrollable settings = new UiScrollable( final UiScrollable settings = new UiScrollable(
new UiSelector().packageName(mTargetPackage).scrollable(true)); new UiSelector().packageName(mTargetPackage).scrollable(true));
final String titleUsersAndAccounts = USER_AND_ACCOUNTS; final String titleSystem = SYSTEM;
settings.scrollTextIntoView(titleUsersAndAccounts); settings.scrollTextIntoView(titleSystem);
mDevice.findObject(new UiSelector().text(titleUsersAndAccounts)).click(); mDevice.findObject(new UiSelector().text(titleSystem)).click();
mDevice.findObject(new UiSelector().text(ADVANCED)).click();
mDevice.findObject(new UiSelector().text(USERS)).click(); mDevice.findObject(new UiSelector().text(USERS)).click();
} }
private void switchToOrCreateGuest() throws UiObjectNotFoundException {
mDevice.openQuickSettings();
mDevice.findObject(new UiSelector().resourceId(SWITCH_USER_BUTTON)).click();
// if no existing guest user, select "Add guest", otherwise select "Guest"
final UiObject addGuest = mDevice.findObject(new UiSelector().text(ADD_GUEST));
if (addGuest.exists()) {
addGuest.click();
mDevice.waitForIdle();
mDevice.pressBack();
} else {
mDevice.findObject(new UiSelector().text(GUEST_USER)).click();
mDevice.waitForIdle();
mDevice.findObject(new UiSelector().text(CONTINUE)).click();
mDevice.waitForIdle();
}
}
} }