Snap for 4598635 from 08addde8b5 to pi-release
Change-Id: I0dd217b846bf0a4ebb0b3e345fbec2f2be8ecc4a
This commit is contained in:
File diff suppressed because it is too large
Load Diff
112
res/layout/data_usage_summary_preference.xml
Normal file
112
res/layout/data_usage_summary_preference.xml
Normal 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>
|
||||
|
||||
@@ -25,23 +25,21 @@
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<Button
|
||||
android:id="@+id/battery_saver_on_button"
|
||||
android:id="@+id/state_on_button"
|
||||
style="@style/ActionPrimaryButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/battery_saver_button_turn_on"
|
||||
android:paddingEnd="8dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/battery_saver_off_button"
|
||||
android:id="@+id/state_off_button"
|
||||
style="@style/ActionSecondaryButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/battery_saver_button_turn_off"
|
||||
android:paddingEnd="8dp" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -162,4 +162,12 @@
|
||||
<attr name="showPercentString" format="boolean" />
|
||||
<attr name="thickness" format="dimension" />
|
||||
</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>
|
||||
|
||||
@@ -5844,6 +5844,8 @@
|
||||
<string name="data_usage_enable_3g">2G-3G data</string>
|
||||
<!-- Toggle switch title for enabling 4G data network connection. [CHAR LIMIT=32] -->
|
||||
<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] -->
|
||||
<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_private_dns" 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] -->
|
||||
<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>
|
||||
</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] -->
|
||||
<string name="data_saver_title">Data saver</string>
|
||||
|
||||
|
||||
@@ -36,4 +36,8 @@
|
||||
<item name="android:widgetLayout">@layout/preference_widget_sync_toggle</item>
|
||||
</style>
|
||||
|
||||
<style name="TwoStateButtonPreference" parent="Preference.SettingsBase">
|
||||
<item name="android:layout">@layout/two_state_button</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -176,6 +176,7 @@
|
||||
<item name="preferenceFragmentStyle">@style/SettingsPreferenceFragmentStyle</item>
|
||||
<item name="apnPreferenceStyle">@style/ApnPreference</item>
|
||||
<item name="seekBarPreferenceStyle">@style/SettingsSeekBarPreference</item>
|
||||
<item name="twoStateButtonPreferenceStyle">@style/TwoStateButtonPreference</item>
|
||||
</style>
|
||||
|
||||
<style name="PreferenceTheme.SetupWizard" parent="PreferenceTheme">
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:title="@string/battery_saver"
|
||||
android:key="battery_saver">
|
||||
|
||||
@@ -23,16 +24,20 @@
|
||||
<SwitchPreference
|
||||
android:key="auto_battery_saver"
|
||||
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
|
||||
android:key="battery_saver_seek_bar"
|
||||
android:title="@string/battery_saver_seekbar_title"
|
||||
android:max="75"
|
||||
android:min="5"/>
|
||||
<com.android.settings.applications.LayoutPreference
|
||||
|
||||
<com.android.settings.widget.TwoStateButtonPreference
|
||||
android:key="battery_saver_button_container"
|
||||
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
|
||||
android:key="battery_saver_footer">
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
android:title="@string/bluetooth_settings_title"
|
||||
android:icon="@drawable/ic_settings_bluetooth"
|
||||
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
|
||||
android:key="toggle_nfc"
|
||||
@@ -54,6 +54,7 @@
|
||||
android:title="@string/bluetooth_on_while_driving_pref"
|
||||
android:icon="@drawable/ic_settings_bluetooth"
|
||||
android:summary="@string/bluetooth_on_while_driving_summary"
|
||||
settings:controller="com.android.settings.connecteddevice.BluetoothOnWhileDrivingPreferenceController"
|
||||
android:order="-2"/>
|
||||
|
||||
<Preference
|
||||
|
||||
@@ -20,24 +20,8 @@
|
||||
android:key="data_usage_screen"
|
||||
android:title="@string/data_usage_summary_title">
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="data_usage_category"
|
||||
android:title="@string/usage">
|
||||
|
||||
<com.android.settings.SummaryPreference
|
||||
<com.android.settings.datausage.DataUsageSummaryPreference
|
||||
android:key="status_header"
|
||||
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>
|
||||
|
||||
@@ -43,8 +43,9 @@
|
||||
<com.android.settingslib.RestrictedSwitchPreference
|
||||
android:key="auto_brightness"
|
||||
android:title="@string/auto_brightness_title"
|
||||
settings:keywords="@string/keywords_display_auto_brightness"
|
||||
android:summary="@string/auto_brightness_summary"
|
||||
settings:keywords="@string/keywords_display_auto_brightness"
|
||||
settings:controller="com.android.settings.display.AutoBrightnessPreferenceController"
|
||||
settings:useAdminDisabledSummary="true"
|
||||
settings:userRestriction="no_config_brightness" />
|
||||
|
||||
|
||||
@@ -79,7 +79,8 @@
|
||||
<SwitchPreference
|
||||
android:key="visiblepattern_profile"
|
||||
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
|
||||
android:key="fingerprint_settings_profile"
|
||||
@@ -103,7 +104,8 @@
|
||||
<SwitchPreference
|
||||
android:key="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>
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
<PreferenceScreen
|
||||
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:title="@string/lockscreen_settings_title">
|
||||
|
||||
@@ -36,7 +37,8 @@
|
||||
<SwitchPreference
|
||||
android:key="security_setting_lockdown_enabled"
|
||||
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
|
||||
android:key="security_setting_lock_screen_notif_work_header"
|
||||
|
||||
@@ -808,7 +808,6 @@ public class SettingsActivity extends SettingsDrawerActivity
|
||||
|| somethingChanged;
|
||||
|
||||
final boolean showDev = DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(this)
|
||||
&& !um.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES)
|
||||
&& !Utils.isMonkeyRunning();
|
||||
|
||||
somethingChanged = setTileEnabled(new ComponentName(packageName,
|
||||
|
||||
@@ -42,6 +42,24 @@ public class LayoutPreference extends Preference {
|
||||
|
||||
public LayoutPreference(Context context, AttributeSet 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);
|
||||
mAllowDividerAbove = TypedArrayUtils.getBoolean(a, R.styleable.Preference_allowDividerAbove,
|
||||
R.styleable.Preference_allowDividerAbove, false);
|
||||
@@ -50,7 +68,7 @@ public class LayoutPreference extends Preference {
|
||||
a.recycle();
|
||||
|
||||
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,
|
||||
0);
|
||||
if (layoutResource == 0) {
|
||||
@@ -64,15 +82,6 @@ public class LayoutPreference extends Preference {
|
||||
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) {
|
||||
setLayoutResource(R.layout.layout_preference_frame);
|
||||
final ViewGroup allDetails = view.findViewById(R.id.all_details);
|
||||
@@ -106,4 +115,4 @@ public class LayoutPreference extends Preference {
|
||||
return mRootView.findViewById(id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,8 @@ import java.util.List;
|
||||
* 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 each type when plugging into Slices.
|
||||
*
|
||||
* TODO (b/73074893) Add Lifecycle Setting method.
|
||||
*/
|
||||
public abstract class BasePreferenceController extends AbstractPreferenceController {
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ import com.android.settings.Settings;
|
||||
import com.android.settings.TestingSettings;
|
||||
import com.android.settings.TetherSettings;
|
||||
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.AccessibilitySettingsForSetupWizard;
|
||||
import com.android.settings.accessibility.CaptionPropertiesFragment;
|
||||
|
||||
@@ -55,7 +55,7 @@ public class DashboardSummary extends InstrumentedFragment
|
||||
FocusListener, SuggestionControllerMixin.SuggestionControllerHost {
|
||||
public static final boolean DEBUG = 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 EXTRA_SCROLL_POSITION = "scroll_position";
|
||||
|
||||
@@ -37,7 +37,7 @@ import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.password.ScreenLockSuggestionActivity;
|
||||
import com.android.settings.support.NewDeviceIntroSuggestionActivity;
|
||||
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.drawer.Tile;
|
||||
import com.android.settingslib.suggestions.SuggestionControllerMixin;
|
||||
|
||||
@@ -18,7 +18,6 @@ import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.NetworkPolicyManager;
|
||||
import android.net.NetworkTemplate;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserManager;
|
||||
@@ -28,6 +27,7 @@ import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.SubscriptionPlan;
|
||||
import android.text.BidiFormatter;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
@@ -40,7 +40,6 @@ import android.view.MenuItem;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SummaryPreference;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.dashboard.SummaryLoader;
|
||||
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";
|
||||
|
||||
private static final String KEY_STATUS_HEADER = "status_header";
|
||||
private static final String KEY_LIMIT_SUMMARY = "limit_summary";
|
||||
|
||||
// Mobile data keys
|
||||
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_DATA_USAGE = "wifi_data_usage";
|
||||
|
||||
private DataUsageController mDataUsageController;
|
||||
private DataUsageInfoController mDataInfoController;
|
||||
private SummaryPreference mSummaryPreference;
|
||||
private Preference mLimitPreference;
|
||||
private DataUsageSummaryPreference mSummaryPreference;
|
||||
private DataUsageSummaryPreferenceController mSummaryController;
|
||||
private NetworkTemplate mDefaultTemplate;
|
||||
private int mDataUsageTemplate;
|
||||
private NetworkPolicyEditor mPolicyEditor;
|
||||
|
||||
@Override
|
||||
public int getHelpResource() {
|
||||
@@ -95,25 +89,20 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
|
||||
super.onCreate(icicle);
|
||||
|
||||
final Context context = getContext();
|
||||
NetworkPolicyManager policyManager = NetworkPolicyManager.from(context);
|
||||
mPolicyEditor = new NetworkPolicyEditor(policyManager);
|
||||
|
||||
boolean hasMobileData = DataUsageUtils.hasMobileData(context);
|
||||
mDataUsageController = new DataUsageController(context);
|
||||
mDataInfoController = new DataUsageInfoController();
|
||||
|
||||
int defaultSubId = DataUsageUtils.getDefaultSubscriptionId(context);
|
||||
if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
|
||||
hasMobileData = false;
|
||||
}
|
||||
mDefaultTemplate = DataUsageUtils.getDefaultTemplate(context, defaultSubId);
|
||||
mSummaryPreference = (SummaryPreference) findPreference(KEY_STATUS_HEADER);
|
||||
mSummaryPreference = (DataUsageSummaryPreference) findPreference(KEY_STATUS_HEADER);
|
||||
|
||||
if (!hasMobileData || !isAdmin()) {
|
||||
removePreference(KEY_RESTRICT_BACKGROUND);
|
||||
}
|
||||
if (hasMobileData) {
|
||||
mLimitPreference = findPreference(KEY_LIMIT_SUMMARY);
|
||||
List<SubscriptionInfo> subscriptions =
|
||||
services.mSubscriptionManager.getActiveSubscriptionInfoList();
|
||||
if (subscriptions == null || subscriptions.size() == 0) {
|
||||
@@ -127,10 +116,6 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
|
||||
addMobileSection(subInfo.getSubscriptionId());
|
||||
}
|
||||
}
|
||||
mSummaryPreference.setSelectable(true);
|
||||
} else {
|
||||
removePreference(KEY_LIMIT_SUMMARY);
|
||||
mSummaryPreference.setSelectable(false);
|
||||
}
|
||||
boolean hasWifiRadio = DataUsageUtils.hasWifiRadio(context);
|
||||
if (hasWifiRadio) {
|
||||
@@ -139,10 +124,6 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
|
||||
if (hasEthernet(context)) {
|
||||
addEthernetSection();
|
||||
}
|
||||
mDataUsageTemplate = hasMobileData ? R.string.cell_data_template
|
||||
: hasWifiRadio ? R.string.wifi_data_template
|
||||
: R.string.ethernet_data_template;
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@@ -189,7 +170,11 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
|
||||
|
||||
@Override
|
||||
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) {
|
||||
@@ -269,36 +254,6 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
|
||||
}
|
||||
|
||||
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();
|
||||
for (int i = 1; i < screen.getPreferenceCount(); i++) {
|
||||
((TemplatePreferenceCategory) screen.getPreference(i)).pushTemplates(services);
|
||||
@@ -323,6 +278,7 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
|
||||
@Override
|
||||
public void updateDataUsage() {
|
||||
updateState();
|
||||
mSummaryController.updateState(mSummaryPreference);
|
||||
}
|
||||
|
||||
private static class SummaryProvider
|
||||
@@ -341,17 +297,39 @@ public class DataUsageSummary extends DataUsageBaseFragment implements Indexable
|
||||
@Override
|
||||
public void setListening(boolean 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,
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import static com.android.settings.bluetooth.Utils.getLocalBtManager;
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserManager;
|
||||
@@ -126,6 +127,16 @@ public class MyDeviceInfoFragment extends DashboardFragment {
|
||||
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() {
|
||||
// TODO: Migrate into its own controller.
|
||||
final LayoutPreference headerPreference =
|
||||
|
||||
@@ -62,7 +62,8 @@ import java.util.List;
|
||||
*/
|
||||
public class BatteryAppListPreferenceController extends AbstractPreferenceController
|
||||
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 MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
|
||||
private static final int STATS_TYPE = BatteryStats.STATS_SINCE_CHARGED;
|
||||
|
||||
@@ -27,7 +27,7 @@ import com.android.settings.Utils;
|
||||
|
||||
/**
|
||||
* 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%)
|
||||
* 2. Battery status(e.g. plugged->unplugged)
|
||||
@@ -35,7 +35,14 @@ import com.android.settings.Utils;
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ public class BatterySaverReceiver extends BroadcastReceiver {
|
||||
mBatterySaverListener = lsn;
|
||||
}
|
||||
|
||||
interface BatterySaverListener {
|
||||
public interface BatterySaverListener {
|
||||
void onPowerSaveModeChanged();
|
||||
void onBatteryChanged(boolean pluggedIn);
|
||||
}
|
||||
|
||||
@@ -16,12 +16,21 @@
|
||||
|
||||
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.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.preference.ListPreference;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.Preference.OnPreferenceClickListener;
|
||||
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.settings.R;
|
||||
import com.android.settings.SettingsPreferenceFragment;
|
||||
import com.android.settings.widget.RadioButtonPreference;
|
||||
|
||||
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;
|
||||
|
||||
@@ -68,29 +89,51 @@ public class InactiveApps extends SettingsPreferenceFragment implements OnPrefer
|
||||
List<ResolveInfo> apps = pm.queryIntentActivities(launcherIntent, 0);
|
||||
for (ResolveInfo app : apps) {
|
||||
String packageName = app.activityInfo.applicationInfo.packageName;
|
||||
Preference p = new Preference(getPrefContext());
|
||||
ListPreference p = new ListPreference(getPrefContext());
|
||||
p.setTitle(app.loadLabel(pm));
|
||||
p.setIcon(app.loadIcon(pm));
|
||||
p.setKey(packageName);
|
||||
p.setEntries(SETTABLE_BUCKETS_NAMES);
|
||||
p.setEntryValues(SETTABLE_BUCKETS_VALUES);
|
||||
updateSummary(p);
|
||||
p.setOnPreferenceClickListener(this);
|
||||
p.setOnPreferenceChangeListener(this);
|
||||
|
||||
screen.addPreference(p);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSummary(Preference p) {
|
||||
boolean inactive = mUsageStats.isAppInactive(p.getKey());
|
||||
p.setSummary(inactive
|
||||
? R.string.inactive_app_inactive_summary
|
||||
: R.string.inactive_app_active_summary);
|
||||
static String bucketToName(int bucket) {
|
||||
switch (bucket) {
|
||||
case STANDBY_BUCKET_EXEMPTED: return "EXEMPTED";
|
||||
case STANDBY_BUCKET_ACTIVE: return "ACTIVE";
|
||||
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
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
String packageName = preference.getKey();
|
||||
mUsageStats.setAppInactive(packageName, !mUsageStats.isAppInactive(packageName));
|
||||
updateSummary(preference);
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
mUsageStats.setAppStandbyBucket(preference.getKey(), Integer.parseInt((String) newValue));
|
||||
updateSummary((ListPreference) preference);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -78,6 +78,7 @@ public class BatterySaverSettings extends DashboardFragment {
|
||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
controllers.add(new AutoBatterySaverPreferenceController(context));
|
||||
controllers.add(new AutoBatterySeekBarPreferenceController(context, lifecycle));
|
||||
controllers.add(new BatterySaverButtonPreferenceController(context, lifecycle));
|
||||
return controllers;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.android.settings.R;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.search.SearchFeatureProvider;
|
||||
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.events.OnCreateOptionsMenu;
|
||||
|
||||
@@ -41,6 +42,10 @@ public class SearchMenuController implements LifecycleObserver, OnCreateOptionsM
|
||||
host.getLifecycle().addObserver(new SearchMenuController(host));
|
||||
}
|
||||
|
||||
public static void init(@NonNull ObservableFragment host) {
|
||||
host.getLifecycle().addObserver(new SearchMenuController(host));
|
||||
}
|
||||
|
||||
private SearchMenuController(@NonNull Fragment host) {
|
||||
mHost = host;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,11 @@ public class VisiblePatternProfilePreferenceController extends TogglePreferenceC
|
||||
|
||||
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) {
|
||||
super(context, KEY_VISIBLE_PATTERN_PROFILE);
|
||||
mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.view.MenuInflater;
|
||||
|
||||
import com.android.settingslib.HelpUtils;
|
||||
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.events.OnCreateOptionsMenu;
|
||||
|
||||
@@ -41,6 +42,10 @@ public class HelpMenuController implements LifecycleObserver, OnCreateOptionsMen
|
||||
host.getLifecycle().addObserver(new HelpMenuController(host));
|
||||
}
|
||||
|
||||
public static void init(@NonNull ObservableFragment host) {
|
||||
host.getLifecycle().addObserver(new HelpMenuController(host));
|
||||
}
|
||||
|
||||
private HelpMenuController(@NonNull Fragment host) {
|
||||
mHost = host;
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ public class MasterCheckBoxPreference extends TwoTargetPreference {
|
||||
if (mCheckBox != null) {
|
||||
mCheckBox.setContentDescription(getTitle());
|
||||
mCheckBox.setChecked(mChecked);
|
||||
mCheckBox.setEnabled(mEnableCheckBox);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -14,11 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings;
|
||||
package com.android.settings.wifi.calling;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.v13.app.FragmentPagerAdapter;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
@@ -28,9 +27,13 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.ims.ImsConfig;
|
||||
import com.android.ims.ImsManager;
|
||||
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.SlidingTabLayout;
|
||||
|
||||
@@ -40,7 +43,7 @@ import java.util.List;
|
||||
* "Wi-Fi Calling settings" screen. This is the container fragment which holds
|
||||
* {@link WifiCallingSettingsForSub} fragments.
|
||||
*/
|
||||
public class WifiCallingSettings extends SettingsPreferenceFragment {
|
||||
public class WifiCallingSettings extends InstrumentedFragment implements HelpResourceProvider {
|
||||
private static final String TAG = "WifiCallingSettings";
|
||||
private List<SubscriptionInfo> mSil;
|
||||
|
||||
@@ -71,6 +74,10 @@ public class WifiCallingSettings extends SettingsPreferenceFragment {
|
||||
@Override
|
||||
public void onCreate(Bundle 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
|
||||
// changes.
|
||||
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 RtlCompatibleViewPager mViewPager;
|
||||
|
||||
@@ -105,6 +117,7 @@ public class WifiCallingSettings extends SettingsPreferenceFragment {
|
||||
public Fragment getItem(int position) {
|
||||
Log.d(TAG, "Adapter getItem " + position);
|
||||
final Bundle args = new Bundle();
|
||||
args.putBoolean(SearchMenuController.NEED_SEARCH_ICON_IN_ACTION_BAR, false);
|
||||
args.putInt(WifiCallingSettingsForSub.FRAGMENT_BUNDLE_SUBID,
|
||||
mSil.get(position).getSubscriptionId());
|
||||
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() {
|
||||
mSil = SubscriptionManager.from(getActivity()).getActiveSubscriptionInfoList();
|
||||
|
||||
@@ -159,7 +152,7 @@ public class WifiCallingSettings extends SettingsPreferenceFragment {
|
||||
if (mSil == null) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < mSil.size();) {
|
||||
for (int i = 0; i < mSil.size(); ) {
|
||||
ImsManager imsManager = ImsManager.getInstance(getActivity(),
|
||||
mSil.get(i).getSimSlotIndex());
|
||||
if (!imsManager.isWfcEnabledByPlatform()) {
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings;
|
||||
package com.android.settings.wifi.calling;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
@@ -45,6 +45,10 @@ import com.android.ims.ImsConfig;
|
||||
import com.android.ims.ImsManager;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -54,7 +58,7 @@ import com.android.settings.widget.SwitchBar;
|
||||
public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
|
||||
implements SwitchBar.OnSwitchChangeListener,
|
||||
Preference.OnPreferenceChangeListener {
|
||||
private static final String TAG = "WifiCallingSettingsForSub";
|
||||
private static final String TAG = "WifiCallingForSub";
|
||||
|
||||
//String keys for preference lookup
|
||||
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 =
|
||||
new OnPreferenceClickListener() {
|
||||
/*
|
||||
@@ -226,8 +224,7 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
|
||||
|
||||
// SubId should always be specified when creating this fragment. Either through
|
||||
// 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);
|
||||
} else if (savedInstanceState != null) {
|
||||
mSubId = savedInstanceState.getInt(
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.wifi;
|
||||
package com.android.settings.wifi.calling;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
@@ -60,8 +60,7 @@ com.android.settings.applications.appinfo.PictureInPictureSettings
|
||||
com.android.settings.applications.appinfo.PictureInPictureDetails
|
||||
com.android.settings.ApnSettings
|
||||
com.android.settings.PrivacySettings
|
||||
com.android.settings.WifiCallingSettings
|
||||
com.android.settings.WifiCallingSettingsForSub
|
||||
com.android.settings.wifi.calling.WifiCallingSettingsForSub
|
||||
com.android.settings.password.SetupChooseLockGeneric$SetupChooseLockGenericFragment
|
||||
com.android.settings.SetupRedactionInterstitial$SetupRedactionInterstitialFragment
|
||||
com.android.settings.security.trustagent.TrustAgentSettings
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
com.android.settings.testutils.FakeToggleController
|
||||
@@ -37,7 +37,9 @@ import com.android.settings.TestConfig;
|
||||
import com.android.settings.applications.ProcStatsData;
|
||||
import com.android.settings.applications.ProcessStatsDetail;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.shadow.ShadowUserManager;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -48,7 +50,9 @@ import org.robolectric.annotation.Config;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
@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 {
|
||||
|
||||
@Mock
|
||||
@@ -67,6 +71,7 @@ public class AppMemoryPreferenceControllerTest {
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
ShadowUserManager.getShadow().setIsAdminUser(true);
|
||||
mController =
|
||||
spy(new AppMemoryPreferenceController(mContext, mFragment, null /* lifecycle */));
|
||||
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
|
||||
@@ -75,6 +80,11 @@ public class AppMemoryPreferenceControllerTest {
|
||||
when(mFragment.getActivity()).thenReturn(mActivity);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowUserManager.getShadow().reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_developmentSettingsEnabled_shouldReturnAvailable() {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
|
||||
@@ -80,7 +80,7 @@ public class BluetoothDetailsHeaderControllerTest extends BluetoothDetailsContro
|
||||
*/
|
||||
@Test
|
||||
public void testContextMock() {
|
||||
assertThat(mContext.getString(R.string.bluetooth_connected)).isEqualTo("Connected");
|
||||
assertThat(mContext.getString(R.string.bluetooth_connected)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.android.settings.development;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
@@ -33,6 +32,7 @@ import com.android.settings.R;
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
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.ToggleSwitch;
|
||||
import com.android.settingslib.development.AbstractEnableAdbPreferenceController;
|
||||
@@ -52,7 +52,9 @@ import org.robolectric.util.ReflectionHelpers;
|
||||
import java.util.List;
|
||||
|
||||
@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 {
|
||||
|
||||
private SwitchBar mSwitchBar;
|
||||
@@ -68,11 +70,13 @@ public class DevelopmentSettingsDashboardFragmentTest {
|
||||
mSwitch = mSwitchBar.getSwitch();
|
||||
mDashboard = spy(new DevelopmentSettingsDashboardFragment());
|
||||
ReflectionHelpers.setField(mDashboard, "mSwitchBar", mSwitchBar);
|
||||
ShadowUserManager.getShadow().setIsAdminUser(true);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowEnableDevelopmentSettingWarningDialog.reset();
|
||||
ShadowUserManager.getShadow().reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -101,7 +105,7 @@ public class DevelopmentSettingsDashboardFragmentTest {
|
||||
SettingsShadowResources.class,
|
||||
SettingsShadowResources.SettingsShadowTheme.class
|
||||
})
|
||||
public void searchIndex_pageDisabled_shouldAddAllKeysToNonIndexable() {
|
||||
public void searchIndex_pageDisabledBySetting_shouldAddAllKeysToNonIndexable() {
|
||||
final Context appContext = RuntimeEnvironment.application;
|
||||
DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(appContext, false);
|
||||
|
||||
@@ -109,7 +113,24 @@ public class DevelopmentSettingsDashboardFragmentTest {
|
||||
DevelopmentSettingsDashboardFragment.SEARCH_INDEX_DATA_PROVIDER
|
||||
.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
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.content.Context;
|
||||
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.shadow.ShadowUserManager;
|
||||
import com.android.settings.testutils.shadow.ShadowUtils;
|
||||
import com.android.settings.widget.SwitchBar;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
@@ -47,7 +48,8 @@ import java.util.ArrayList;
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
|
||||
shadows = {
|
||||
ShadowUtils.class
|
||||
ShadowUtils.class,
|
||||
ShadowUserManager.class
|
||||
})
|
||||
public class DevelopmentSwitchBarControllerTest {
|
||||
|
||||
@@ -63,6 +65,7 @@ public class DevelopmentSwitchBarControllerTest {
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
ShadowUserManager.getShadow().setIsAdminUser(true);
|
||||
mLifecycleOwner = () -> mLifecycle;
|
||||
mLifecycle = new Lifecycle(mLifecycleOwner);
|
||||
mSwitchBar = new SwitchBar(mContext);
|
||||
@@ -72,6 +75,7 @@ public class DevelopmentSwitchBarControllerTest {
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowUtils.reset();
|
||||
ShadowUserManager.getShadow().reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -43,6 +43,7 @@ import com.android.settings.search.DatabaseIndexingManager;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
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.development.DevelopmentSettingsEnabler;
|
||||
|
||||
@@ -60,7 +61,8 @@ import org.robolectric.util.ReflectionHelpers;
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
|
||||
shadows = {
|
||||
ShadowUtils.class
|
||||
ShadowUtils.class,
|
||||
ShadowUserManager.class,
|
||||
})
|
||||
public class BuildNumberPreferenceControllerTest {
|
||||
|
||||
@@ -84,6 +86,7 @@ public class BuildNumberPreferenceControllerTest {
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
ShadowUserManager.getShadow().setIsAdminUser(true);
|
||||
mFactory = FakeFeatureFactory.setupForTest();
|
||||
mLifecycleOwner = () -> mLifecycle;
|
||||
mLifecycle = new Lifecycle(mLifecycleOwner);
|
||||
@@ -98,6 +101,7 @@ public class BuildNumberPreferenceControllerTest {
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowUtils.reset();
|
||||
ShadowUserManager.getShadow().reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -21,15 +21,18 @@ import static com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment;
|
||||
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.ShadowConnectivityManager;
|
||||
import com.android.settings.testutils.shadow.ShadowUserManager;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -48,6 +52,11 @@ import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
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)
|
||||
@Config(
|
||||
@@ -97,4 +106,23 @@ public class MyDeviceInfoFragmentTest {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,4 +220,9 @@ public class BatteryAppListPreferenceControllerTest {
|
||||
|
||||
assertThat(mPreferenceController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNeverUseFakeData() {
|
||||
assertThat(BatteryAppListPreferenceController.USE_FAKE_DATA).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -137,7 +137,6 @@ public class BaseSearchIndexProviderTest {
|
||||
final List<String> nonIndexableKeys = provider
|
||||
.getNonIndexableKeys(RuntimeEnvironment.application);
|
||||
|
||||
assertThat(nonIndexableKeys).containsAllOf("status_header", "limit_summary",
|
||||
"restrict_background");
|
||||
assertThat(nonIndexableKeys).contains("status_header");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.settings.search.actionbar;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.os.Bundle;
|
||||
@@ -27,6 +28,7 @@ import android.view.MenuItem;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settingslib.core.lifecycle.ObservableFragment;
|
||||
import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -42,26 +44,47 @@ public class SearchMenuControllerTest {
|
||||
|
||||
@Mock
|
||||
private Menu mMenu;
|
||||
private TestFragment mHost;
|
||||
private TestPreferenceFragment mPreferenceHost;
|
||||
private ObservableFragment mHost;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
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
|
||||
public void init_shouldAddMenu() {
|
||||
when(mMenu.add(Menu.NONE, Menu.NONE, 0 /* order */, R.string.search_menu))
|
||||
.thenReturn(mock(MenuItem.class));
|
||||
public void init_prefFragment_shouldAddMenu() {
|
||||
SearchMenuController.init(mPreferenceHost);
|
||||
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);
|
||||
mHost.getLifecycle().onCreateOptionsMenu(mMenu, null /* inflater */);
|
||||
|
||||
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
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.net.Uri;
|
||||
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.testutils.DatabaseTestUtils;
|
||||
import com.android.settings.testutils.FakeToggleController;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.After;
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.android.settings.search.FakeIndexProvider;
|
||||
import com.android.settings.search.SearchFeatureProvider;
|
||||
import com.android.settings.search.SearchFeatureProviderImpl;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.FakeToggleController;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.After;
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.net.Uri;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.TestConfig;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.testutils.FakeToggleController;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ public class SettingsSuggestionsTest {
|
||||
|
||||
@Test
|
||||
public void wifiCallingSuggestion_isValid() {
|
||||
assertSuggestionEquals("com.android.settings.wifi.WifiCallingSuggestionActivity",
|
||||
assertSuggestionEquals("com.android.settings.wifi.calling.WifiCallingSuggestionActivity",
|
||||
CATEGORY_FIRST_IMPRESSION,
|
||||
R.string.wifi_calling_suggestion_title, R.string.wifi_calling_suggestion_summary);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package com.android.settings.slices;
|
||||
package com.android.settings.testutils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -105,6 +105,24 @@ public class MasterCheckBoxPreferenceTest {
|
||||
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
|
||||
public void clickWidgetView_shouldToggleCheckBox() {
|
||||
final LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.icon" android:resource="@drawable/ic_settings_applications" />
|
||||
</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>
|
||||
|
||||
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
@@ -28,4 +28,7 @@
|
||||
<string name="manufacturer_hello" translatable="false">Hello 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="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>
|
||||
|
||||
23
tests/unit/res/xml/account_preferences.xml
Normal file
23
tests/unit/res/xml/account_preferences.xml
Normal 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>
|
||||
|
||||
22
tests/unit/res/xml/authenticator.xml
Normal file
22
tests/unit/res/xml/authenticator.xml
Normal 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" />
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,34 +15,47 @@
|
||||
*/
|
||||
package com.android.settings.users;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
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.test.InstrumentationTestCase;
|
||||
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 UserSettingsTest extends InstrumentationTestCase {
|
||||
public class UserSettingsTest {
|
||||
|
||||
private static final String USER_AND_ACCOUNTS = "Users & accounts";
|
||||
private static final String USERS = "Users";
|
||||
private static final String SYSTEM = "System";
|
||||
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 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 Context mContext;
|
||||
private String mTargetPackage;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mDevice = UiDevice.getInstance(getInstrumentation());
|
||||
mContext = getInstrumentation().getTargetContext();
|
||||
@Before
|
||||
public void setUp() {
|
||||
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mTargetPackage = mContext.getPackageName();
|
||||
}
|
||||
|
||||
@@ -51,7 +64,8 @@ public class UserSettingsTest extends InstrumentationTestCase {
|
||||
launchUserSettings();
|
||||
UiObject emergencyInfoPreference =
|
||||
mDevice.findObject(new UiSelector().text(EMERGNENCY_INFO));
|
||||
assertFalse(emergencyInfoPreference.exists());
|
||||
|
||||
assertThat(emergencyInfoPreference.exists()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -59,7 +73,32 @@ public class UserSettingsTest extends InstrumentationTestCase {
|
||||
launchUserSettings();
|
||||
UiObject addUsersPreference =
|
||||
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() {
|
||||
@@ -67,17 +106,34 @@ public class UserSettingsTest extends InstrumentationTestCase {
|
||||
.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
.setPackage(mTargetPackage)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
getInstrumentation().getContext().startActivity(settingsIntent);
|
||||
mContext.startActivity(settingsIntent);
|
||||
}
|
||||
|
||||
private void launchUserSettings() throws Exception {
|
||||
launchSettings();
|
||||
final UiScrollable settings = new UiScrollable(
|
||||
new UiSelector().packageName(mTargetPackage).scrollable(true));
|
||||
final String titleUsersAndAccounts = USER_AND_ACCOUNTS;
|
||||
settings.scrollTextIntoView(titleUsersAndAccounts);
|
||||
mDevice.findObject(new UiSelector().text(titleUsersAndAccounts)).click();
|
||||
final String titleSystem = SYSTEM;
|
||||
settings.scrollTextIntoView(titleSystem);
|
||||
mDevice.findObject(new UiSelector().text(titleSystem)).click();
|
||||
mDevice.findObject(new UiSelector().text(ADVANCED)).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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user