Merge "Extract magnification capabilities from MagnificationSettingsFragment into a new class."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c77680d..c946122 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2742,6 +2742,19 @@
</activity>
<activity
+ android:name="Settings$PremiumSmsAccessActivity"
+ android:label="@string/premium_sms_access"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.settings.PREMIUM_SMS_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="package" />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.applications.specialaccess.premiumsms.PremiumSmsAccess" />
+ </activity>
+
+ <activity
android:name="Settings$SoundSettingsActivity"
android:label="@string/sound_settings"
android:icon="@drawable/ic_homepage_sound"
diff --git a/res/layout/settings_homepage_container.xml b/res/layout/settings_homepage_container.xml
index f210c54..fe119c6 100644
--- a/res/layout/settings_homepage_container.xml
+++ b/res/layout/settings_homepage_container.xml
@@ -57,6 +57,41 @@
android:layout_height="wrap_content"
android:touchscreenBlocksFocus="false"
android:keyboardNavigationCluster="false">
- <include layout="@layout/search_bar"/>
+ <LinearLayout
+ android:id="@+id/app_bar_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed">
+
+ <LinearLayout
+ android:id="@+id/contextual_suggestion_content"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/suggestion_height"
+ android:paddingHorizontal="@dimen/suggestion_padding_horizontal"
+ android:paddingBottom="@dimen/suggestion_padding_bottom"
+ android:orientation="vertical"
+ android:gravity="bottom"
+ android:visibility="gone">
+
+ <TextView
+ android:id="@+id/suggestion_title"
+ android:text="@string/settings_label"
+ style="@style/ContextualSuggestionText"/>
+
+ <Button
+ android:id="@+id/suggestion_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/suggestion_button_margin_top"
+ android:paddingHorizontal="@dimen/suggestion_button_padding_horizontal"
+ android:visibility="gone"
+ style="@style/ActionPrimaryButton"/>
+
+ </LinearLayout>
+
+ <include layout="@layout/search_bar"/>
+
+ </LinearLayout>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/res/values-th/arrays.xml b/res/values-th/arrays.xml
index d9ebe44..3b533bb 100644
--- a/res/values-th/arrays.xml
+++ b/res/values-th/arrays.xml
@@ -233,8 +233,8 @@
<item msgid="50701215019227883">"สั่น"</item>
<item msgid="2690144000353492014">"อ่านรายชื่อติดต่อ"</item>
<item msgid="3858029424955955625">"แก้ไขรายชื่อติดต่อ"</item>
- <item msgid="3439658954936709507">"อ่านประวัติการโทร"</item>
- <item msgid="1908944516631132130">"แก้ไขประวัติการโทร"</item>
+ <item msgid="3439658954936709507">"อ่านบันทึกการโทร"</item>
+ <item msgid="1908944516631132130">"แก้ไขบันทึกการโทร"</item>
<item msgid="9066115715905100138">"อ่านปฏิทิน"</item>
<item msgid="1664720478157892566">"แก้ไขปฏิทิน"</item>
<item msgid="5478277451617814822">"ค้นหา WiFi"</item>
@@ -300,8 +300,8 @@
<item msgid="4104617224667554750">"สั่น"</item>
<item msgid="1623646715189708947">"อ่านรายชื่อติดต่อ"</item>
<item msgid="5060760609109972207">"แก้ไขรายชื่อติดต่อ"</item>
- <item msgid="7451260062940797278">"อ่านประวัติการโทร"</item>
- <item msgid="2348589304974534308">"แก้ไขประวัติการโทร"</item>
+ <item msgid="7451260062940797278">"อ่านบันทึกการโทร"</item>
+ <item msgid="2348589304974534308">"แก้ไขบันทึกการโทร"</item>
<item msgid="4089146706115315300">"อ่านปฏิทิน"</item>
<item msgid="1305780729690198918">"แก้ไขปฏิทิน"</item>
<item msgid="3461096740171440592">"ตำแหน่ง"</item>
@@ -495,7 +495,7 @@
</string-array>
<string-array name="wifi_metered_entries">
<item msgid="3237321077949659241">"ตรวจหาโดยอัตโนมัติ"</item>
- <item msgid="3779092145391320375">"ถือว่ามีการวัดปริมาณอินเทอร์เน็ต"</item>
+ <item msgid="3779092145391320375">"ถือว่ามีการจำกัดปริมาณอินเทอร์เน็ต"</item>
<item msgid="2047166446768045816">"ถือว่าไม่มีการวัดปริมาณอินเทอร์เน็ต"</item>
</string-array>
<string-array name="wifi_privacy_entries">
diff --git a/res/values-uz/arrays.xml b/res/values-uz/arrays.xml
index d2f82b7..9d885b2 100644
--- a/res/values-uz/arrays.xml
+++ b/res/values-uz/arrays.xml
@@ -499,8 +499,8 @@
<item msgid="2047166446768045816">"Bu – bepul tarmoq"</item>
</string-array>
<string-array name="wifi_privacy_entries">
- <item msgid="3485945604919292489">"Ixtiyoriy MAC manzil (standart)"</item>
- <item msgid="741680937828608749">"Ixtiyoriy MAC manzil"</item>
+ <item msgid="3485945604919292489">"Tasodifiy MAC manzil (standart)"</item>
+ <item msgid="741680937828608749">"Qurilmaning MAC manzili"</item>
</string-array>
<string-array name="wifi_hidden_entries">
<item msgid="342232116597649254">"Yo‘q"</item>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index f8df920..bf757d1 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -223,6 +223,10 @@
<!-- Security types for wireless tether -->
<string-array name="wifi_tether_security">
<!-- Do not translate. -->
+ <item>@string/wifi_security_sae</item>
+ <!-- Do not translate. -->
+ <item>@string/wifi_security_psk_sae</item>
+ <!-- Do not translate. -->
<item>@string/wifi_security_wpa2</item>
<!-- Do not translate. -->
<item>@string/wifi_security_none</item>
@@ -231,6 +235,10 @@
<!-- Values for security type for wireless tether -->
<string-array name="wifi_tether_security_values" translatable="false">
<!-- Do not translate. -->
+ <item>3</item>
+ <!-- Do not translate. -->
+ <item>2</item>
+ <!-- Do not translate. -->
<item>1</item>
<!-- Do not translate. -->
<item>0</item>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 7809f05..bc01d59 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -123,13 +123,20 @@
<dimen name="switchbar_subsettings_margin_start">72dp</dimen>
<dimen name="switchbar_subsettings_margin_end">16dp</dimen>
+ <!-- Search bar and avatar -->
<dimen name="search_bar_margin">24dp</dimen>
<dimen name="search_bar_height">48dp</dimen>
- <dimen name="search_bar_text_size">16dp</dimen>
+ <dimen name="search_bar_text_size">16sp</dimen>
<dimen name="search_bar_card_elevation">2dp</dimen>
<dimen name="search_bar_content_inset">64dp</dimen>
<dimen name="avatar_length">@dimen/search_bar_height</dimen>
+ <!-- Contextual suggestions -->
+ <dimen name="suggestion_height">224dp</dimen>
+ <dimen name="suggestion_padding_horizontal">24dp</dimen>
+ <dimen name="suggestion_padding_bottom">8dp</dimen>
+ <dimen name="suggestion_button_margin_top">16dp</dimen>
+ <dimen name="suggestion_button_padding_horizontal">24dp</dimen>
<!-- Dimensions for Wifi Assistant Card -->
<dimen name="wifi_assistant_padding_top_bottom">16dp</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index fd4d268..ce6b095 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -782,6 +782,14 @@
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
</style>
+ <style name="ContextualSuggestionText" parent="@android:style/TextAppearance.DeviceDefault">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:textSize">32sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+ </style>
+
<style name="RequestManageCredentialsButtonPanel">
<item name="android:paddingStart">12dp</item>
<item name="android:paddingEnd">12dp</item>
diff --git a/res/values/themes_suw.xml b/res/values/themes_suw.xml
index 98ab28d..959ffb3 100644
--- a/res/values/themes_suw.xml
+++ b/res/values/themes_suw.xml
@@ -197,8 +197,8 @@
<item name="android:textAllCaps">false</item>
<item name="android:windowSoftInputMode">adjustResize</item>
- <!-- copied from Theme.DeviceDefault.Light.Dialog.Alert -->
- <item name="colorAccent">@*android:color/accent_device_default_light</item>
+ <!-- copied from Theme.DeviceDefault.Dialog.Alert -->
+ <item name="colorAccent">@*android:color/accent_device_default_dark</item>
<item name="dialogCornerRadius">@*android:dimen/config_dialogCornerRadius</item>
</style>
diff --git a/res/xml/display_settings_v2.xml b/res/xml/display_settings_v2.xml
new file mode 100644
index 0000000..5e20db5
--- /dev/null
+++ b/res/xml/display_settings_v2.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="display_settings_screen"
+ android:title="@string/display_settings"
+ settings:keywords="@string/keywords_display"
+ settings:initialExpandedChildrenCount="5">
+
+ <com.android.settingslib.RestrictedPreference
+ android:key="brightness"
+ android:title="@string/brightness"
+ settings:keywords="@string/keywords_display_brightness_level"
+ settings:useAdminDisabledSummary="true"
+ settings:userRestriction="no_config_brightness">
+ <intent android:action="com.android.intent.action.SHOW_BRIGHTNESS_DIALOG" />
+ </com.android.settingslib.RestrictedPreference>
+
+ <com.android.settings.display.darkmode.DarkModePreference
+ android:key="dark_ui_mode"
+ android:title="@string/dark_ui_mode"
+ android:fragment="com.android.settings.display.darkmode.DarkModeSettingsFragment"
+ android:widgetLayout="@null"
+ settings:widgetLayout="@null"
+ settings:controller="com.android.settings.display.DarkUIPreferenceController"
+ settings:keywords="@string/keywords_dark_ui_mode"/>
+
+ <com.android.settings.display.NightDisplayPreference
+ android:key="night_display"
+ android:title="@string/night_display_title"
+ android:fragment="com.android.settings.display.NightDisplaySettings"
+ android:widgetLayout="@null"
+ settings:widgetLayout="@null"/>
+
+ <Preference
+ android:key="auto_brightness_entry"
+ android:title="@string/auto_brightness_title"
+ android:summary="@string/summary_placeholder"
+ android:fragment="com.android.settings.display.AutoBrightnessSettings"
+ settings:controller="com.android.settings.display.AutoBrightnessPreferenceController"/>
+
+ <!-- Cross-listed item, if you change this, also change it in power_usage_summary.xml -->
+ <com.android.settingslib.RestrictedPreference
+ android:key="screen_timeout"
+ android:title="@string/screen_timeout"
+ android:summary="@string/summary_placeholder"
+ android:fragment="com.android.settings.display.ScreenTimeoutSettings"
+ settings:controller="com.android.settings.display.ScreenTimeoutPreferenceController" />
+
+ <SwitchPreference
+ android:key="auto_rotate"
+ android:title="@string/accelerometer_title"
+ settings:keywords="@string/keywords_auto_rotate"
+ settings:controller="com.android.settings.display.AutoRotatePreferenceController" />
+
+ <Preference
+ android:key="color_mode"
+ android:title="@string/color_mode_title"
+ android:fragment="com.android.settings.display.ColorModePreferenceFragment"
+ settings:controller="com.android.settings.display.ColorModePreferenceController"
+ settings:keywords="@string/keywords_color_mode" />
+
+ <SwitchPreference
+ android:key="display_white_balance"
+ android:title="@string/display_white_balance_title"
+ android:summary="@string/display_white_balance_summary"
+ settings:controller="com.android.settings.display.DisplayWhiteBalancePreferenceController" />
+
+ <SwitchPreference
+ android:key="peak_refresh_rate"
+ android:title="@string/peak_refresh_rate_title"
+ android:summary="@string/peak_refresh_rate_summary"
+ settings:controller="com.android.settings.display.PeakRefreshRatePreferenceController" />
+
+ <Preference
+ android:key="font_size"
+ android:title="@string/title_font_size"
+ android:fragment="com.android.settings.display.ToggleFontSizePreferenceFragment"
+ settings:controller="com.android.settings.display.FontSizePreferenceController"
+ settings:keywords="@string/keywords_font_size" />
+
+ <com.android.settings.display.ScreenZoomPreference
+ android:key="display_settings_screen_zoom"
+ android:title="@string/screen_zoom_title"
+ android:fragment="com.android.settings.display.ScreenZoomSettings"/>
+
+ <SwitchPreference
+ android:key="show_operator_name"
+ android:title="@string/show_operator_name_title"
+ android:summary="@string/show_operator_name_summary" />
+
+ <Preference
+ android:key="screensaver"
+ android:title="@string/screensaver_settings_title"
+ android:fragment="com.android.settings.dream.DreamSettings" />
+
+ <Preference
+ android:key="lockscreen_from_display_settings"
+ android:title="@string/lockscreen_settings_title"
+ android:fragment="com.android.settings.security.LockscreenDashboardFragment"
+ settings:keywords="@string/keywords_ambient_display_screen"
+ settings:controller="com.android.settings.security.screenlock.LockScreenPreferenceController" />
+
+ <SwitchPreference
+ android:key="camera_gesture"
+ android:title="@string/camera_gesture_title"
+ android:summary="@string/camera_gesture_desc" />
+
+ <SwitchPreference
+ android:key="lift_to_wake"
+ android:title="@string/lift_to_wake_title" />
+
+ <SwitchPreference
+ android:key="tap_to_wake"
+ android:title="@string/tap_to_wake"
+ android:summary="@string/tap_to_wake_summary" />
+
+ <ListPreference
+ android:key="theme"
+ android:title="@string/device_theme"
+ android:summary="@string/summary_placeholder" />
+
+ <Preference
+ android:key="vr_display_pref"
+ android:title="@string/display_vr_pref_title"
+ android:fragment="com.android.settings.display.VrDisplayPreferencePicker" />
+
+</PreferenceScreen>
diff --git a/res/xml/top_level_settings_grouped.xml b/res/xml/top_level_settings_grouped.xml
index cdfab91..baee7b3 100644
--- a/res/xml/top_level_settings_grouped.xml
+++ b/res/xml/top_level_settings_grouped.xml
@@ -20,43 +20,38 @@
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="top_level_settings_grouped">
- <PreferenceCategory
- android:key="connectivity"
- android:order="-130"
- settings:allowDividerAbove="false">
- <Preference
- android:fragment="com.android.settings.network.NetworkDashboardFragment"
- android:icon="@drawable/ic_homepage_network"
- android:key="top_level_network"
- android:order="-130"
- android:title="@string/network_dashboard_title"
- settings:controller="com.android.settings.network.TopLevelNetworkEntryPreferenceController"/>
+ <Preference
+ android:fragment="com.android.settings.network.NetworkDashboardFragment"
+ android:icon="@drawable/ic_homepage_network"
+ android:key="top_level_network"
+ android:order="-140"
+ android:title="@string/network_dashboard_title"
+ settings:controller="com.android.settings.network.TopLevelNetworkEntryPreferenceController"/>
- <Preference
- android:fragment="com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment"
- android:icon="@drawable/ic_homepage_connected_device"
- android:key="top_level_connected_devices"
- android:order="-120"
- android:title="@string/connected_devices_dashboard_title"
- settings:controller="com.android.settings.connecteddevice.TopLevelConnectedDevicesPreferenceController"/>
- </PreferenceCategory>
+ <Preference
+ android:fragment="com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment"
+ android:icon="@drawable/ic_homepage_connected_device"
+ android:key="top_level_connected_devices"
+ android:order="-130"
+ android:title="@string/connected_devices_dashboard_title"
+ settings:controller="com.android.settings.connecteddevice.TopLevelConnectedDevicesPreferenceController"/>
<PreferenceCategory
android:key="apps"
- android:order="-110"
+ android:order="-120"
settings:allowDividerAbove="false">
<Preference
android:fragment="com.android.settings.applications.AppAndNotificationDashboardFragment"
android:icon="@drawable/ic_homepage_apps"
android:key="top_level_apps_and_notifs"
- android:order="-110"
+ android:order="-120"
android:title="@string/apps_dashboard_title"/>
<Preference
android:fragment="com.android.settings.notification.ConfigureNotificationSettings"
android:icon="@drawable/ic_homepage_notification"
android:key="top_level_notification"
- android:order="-100"
+ android:order="-110"
android:title="@string/configure_notification_settings"/>
@@ -64,13 +59,13 @@
<PreferenceCategory
android:key="phone_essential"
- android:order="-90"
+ android:order="-100"
settings:allowDividerAbove="false">
<Preference
android:fragment="com.android.settings.fuelgauge.PowerUsageSummary"
android:icon="@drawable/ic_homepage_battery"
android:key="top_level_battery"
- android:order="-90"
+ android:order="-100"
android:title="@string/power_usage_summary_title"
settings:controller="com.android.settings.fuelgauge.TopLevelBatteryPreferenceController"/>
@@ -78,7 +73,7 @@
android:fragment="com.android.settings.deviceinfo.StorageSettings"
android:icon="@drawable/ic_homepage_storage"
android:key="top_level_storage"
- android:order="-80"
+ android:order="-90"
android:title="@string/storage_settings"
settings:controller="com.android.settings.deviceinfo.TopLevelStoragePreferenceController"/>
@@ -86,17 +81,24 @@
android:fragment="com.android.settings.notification.SoundSettings"
android:icon="@drawable/ic_homepage_sound"
android:key="top_level_sound"
- android:order="-70"
+ android:order="-80"
android:title="@string/sound_settings"/>
<Preference
android:fragment="com.android.settings.DisplaySettings"
android:icon="@drawable/ic_homepage_display"
android:key="top_level_display"
- android:order="-60"
+ android:order="-70"
android:title="@string/display_settings"
settings:controller="com.android.settings.display.TopLevelDisplayPreferenceController"/>
+ <com.android.settingslib.RestrictedTopLevelPreference
+ android:icon="@drawable/ic_homepage_display"
+ android:key="top_level_wallpaper"
+ android:order="-60"
+ android:title="@string/wallpaper_settings_title"
+ settings:controller="com.android.settings.display.TopLevelWallpaperPreferenceController"/>
+
<Preference
android:fragment="com.android.settings.accessibility.AccessibilitySettings"
android:icon="@drawable/ic_homepage_accessibility"
diff --git a/src/com/android/settings/AllInOneTetherSettings.java b/src/com/android/settings/AllInOneTetherSettings.java
index 82e3206..5442ed7 100644
--- a/src/com/android/settings/AllInOneTetherSettings.java
+++ b/src/com/android/settings/AllInOneTetherSettings.java
@@ -355,7 +355,7 @@
@Override
public void onTetherConfigUpdated(AbstractPreferenceController controller) {
final SoftApConfiguration config = buildNewConfig();
- mPasswordPreferenceController.updateVisibility(config.getSecurityType());
+ mPasswordPreferenceController.setSecurityType(config.getSecurityType());
mWifiManager.setSoftApConfiguration(config);
if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) {
diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java
index cbfbe7a..3292ede 100644
--- a/src/com/android/settings/DisplaySettings.java
+++ b/src/com/android/settings/DisplaySettings.java
@@ -19,7 +19,10 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
+import android.provider.SearchIndexableResource;
+import android.util.FeatureFlagUtils;
+import com.android.settings.core.FeatureFlags;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.display.BrightnessLevelPreferenceController;
import com.android.settings.display.CameraGesturePreferenceController;
@@ -37,6 +40,7 @@
import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
@@ -55,6 +59,9 @@
@Override
protected int getPreferenceScreenResId() {
+ if (FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.SILKY_HOME)) {
+ return R.xml.display_settings_v2;
+ }
return R.xml.display_settings;
}
@@ -90,7 +97,16 @@
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
- new BaseSearchIndexProvider(R.xml.display_settings) {
+ new BaseSearchIndexProvider() {
+
+ @Override
+ public List<SearchIndexableResource> getXmlResourcesToIndex(
+ Context context, boolean enabled) {
+ final SearchIndexableResource sir = new SearchIndexableResource(context);
+ sir.xmlResId = FeatureFlagUtils.isEnabled(context, FeatureFlags.SILKY_HOME)
+ ? R.xml.display_settings_v2 : R.xml.display_settings;
+ return Arrays.asList(sir);
+ }
@Override
public List<AbstractPreferenceController> createPreferenceControllers(
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index b226133..8389d84 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -144,6 +144,7 @@
public static class NotificationAccessSettingsActivity extends SettingsActivity { /* empty */ }
public static class NotificationAccessDetailsActivity extends SettingsActivity { /* empty */ }
public static class VrListenersSettingsActivity extends SettingsActivity { /* empty */ }
+ public static class PremiumSmsAccessActivity extends SettingsActivity { /* empty */ }
public static class PictureInPictureSettingsActivity extends SettingsActivity { /* empty */ }
public static class AppPictureInPictureSettingsActivity extends SettingsActivity { /* empty */ }
public static class ZenAccessSettingsActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/accessibility/ToggleAutoclickPreferenceController.java b/src/com/android/settings/accessibility/ToggleAutoclickPreferenceController.java
index b9af7ce..78f31df 100644
--- a/src/com/android/settings/accessibility/ToggleAutoclickPreferenceController.java
+++ b/src/com/android/settings/accessibility/ToggleAutoclickPreferenceController.java
@@ -25,6 +25,7 @@
import android.provider.Settings;
import android.util.ArrayMap;
+import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.LifecycleObserver;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
@@ -44,16 +45,23 @@
public class ToggleAutoclickPreferenceController extends BasePreferenceController implements
LifecycleObserver, RadioButtonPreference.OnClickListener, PreferenceControllerMixin {
- private static final String CONTROL_AUTOCLICK_DELAY_SECURE =
+ @VisibleForTesting
+ static final String CONTROL_AUTOCLICK_DELAY_SECURE =
Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY;
- private static final String KEY_AUTOCLICK_CUSTOM_SEEKBAR = "autoclick_custom_seekbar";
+
+ @VisibleForTesting
+ static final String KEY_AUTOCLICK_CUSTOM_SEEKBAR = "autoclick_custom_seekbar";
static final String KEY_DELAY_MODE = "delay_mode";
- private static final int AUTOCLICK_OFF_MODE = 0;
- private static final int AUTOCLICK_CUSTOM_MODE = 2000;
+ @VisibleForTesting
+ static final int AUTOCLICK_OFF_MODE = 0;
+
+ @VisibleForTesting
+ static final int AUTOCLICK_CUSTOM_MODE = 2000;
// Pair the preference key and autoclick mode value.
- private final Map<String, Integer> mAccessibilityAutoclickKeyToValueMap = new ArrayMap<>();
+ @VisibleForTesting
+ Map<String, Integer> mAccessibilityAutoclickKeyToValueMap = new ArrayMap<>();
private SharedPreferences mSharedPreferences;
private final ContentResolver mContentResolver;
@@ -70,13 +78,7 @@
private int mCurrentUiAutoClickMode;
public ToggleAutoclickPreferenceController(Context context, String preferenceKey) {
- super(context, preferenceKey);
-
- mSharedPreferences = context.getSharedPreferences(context.getPackageName(), MODE_PRIVATE);
- mContentResolver = context.getContentResolver();
- mResources = context.getResources();
-
- setAutoclickModeToKeyMap();
+ this(context, /* lifecycle= */ null, preferenceKey);
}
public ToggleAutoclickPreferenceController(Context context, Lifecycle lifecycle,
diff --git a/src/com/android/settings/accessibility/VideoPlayer.java b/src/com/android/settings/accessibility/VideoPlayer.java
index 8f94b76..d4aa6a6 100644
--- a/src/com/android/settings/accessibility/VideoPlayer.java
+++ b/src/com/android/settings/accessibility/VideoPlayer.java
@@ -25,6 +25,7 @@
import androidx.annotation.GuardedBy;
import androidx.annotation.RawRes;
+import androidx.annotation.VisibleForTesting;
/**
* Plays the video by {@link MediaPlayer} on {@link TextureView}, calls {@link #create(Context, int,
@@ -32,19 +33,25 @@
* is no longer used, call {@link #release()} so that MediaPlayer object can be released.
*/
public class VideoPlayer implements SurfaceTextureListener {
- private final Context context;
- private final Object mediaPlayerLock = new Object();
+ private final Context mContext;
+ private final Object mMediaPlayerLock = new Object();
// Media player object can't be used after it has been released, so it will be set to null. But
// VideoPlayer is asynchronized, media player object might be paused or resumed again before
// released media player is set to null. Therefore, lock mediaPlayer and mediaPlayerState by
// mediaPlayerLock keep their states consistent.
+ @VisibleForTesting
@GuardedBy("mediaPlayerLock")
- private MediaPlayer mediaPlayer;
+ MediaPlayer mMediaPlayer;
+
+ @VisibleForTesting
@GuardedBy("mediaPlayerLock")
- private State mediaPlayerState = State.NONE;
+ State mMediaPlayerState = State.NONE;
+
@RawRes
- private final int videoRes;
- private Surface animationSurface;
+ private final int mVideoRes;
+
+ @VisibleForTesting
+ Surface mAnimationSurface;
/**
@@ -58,54 +65,54 @@
}
private VideoPlayer(Context context, @RawRes int videoRes, TextureView textureView) {
- this.context = context;
- this.videoRes = videoRes;
+ this.mContext = context;
+ this.mVideoRes = videoRes;
textureView.setSurfaceTextureListener(this);
}
public void pause() {
- synchronized (mediaPlayerLock) {
- if (mediaPlayerState == State.STARTED) {
- mediaPlayerState = State.PAUSED;
- mediaPlayer.pause();
+ synchronized (mMediaPlayerLock) {
+ if (mMediaPlayerState == State.STARTED) {
+ mMediaPlayerState = State.PAUSED;
+ mMediaPlayer.pause();
}
}
}
public void resume() {
- synchronized (mediaPlayerLock) {
- if (mediaPlayerState == State.PAUSED) {
- mediaPlayer.start();
- mediaPlayerState = State.STARTED;
+ synchronized (mMediaPlayerLock) {
+ if (mMediaPlayerState == State.PAUSED) {
+ mMediaPlayer.start();
+ mMediaPlayerState = State.STARTED;
}
}
}
/** Release media player when it's no longer needed. */
public void release() {
- synchronized (mediaPlayerLock) {
- if (mediaPlayerState != State.NONE && mediaPlayerState != State.END) {
- mediaPlayerState = State.END;
- mediaPlayer.release();
- mediaPlayer = null;
+ synchronized (mMediaPlayerLock) {
+ if (mMediaPlayerState != State.NONE && mMediaPlayerState != State.END) {
+ mMediaPlayerState = State.END;
+ mMediaPlayer.release();
+ mMediaPlayer = null;
}
}
- if (animationSurface != null) {
- animationSurface.release();
- animationSurface = null;
+ if (mAnimationSurface != null) {
+ mAnimationSurface.release();
+ mAnimationSurface = null;
}
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
- animationSurface = new Surface(surface);
- synchronized (mediaPlayerLock) {
- mediaPlayer = MediaPlayer.create(context, videoRes);
- mediaPlayerState = State.PREPARED;
- mediaPlayer.setSurface(animationSurface);
- mediaPlayer.setLooping(true);
- mediaPlayer.start();
- mediaPlayerState = State.STARTED;
+ mAnimationSurface = new Surface(surface);
+ synchronized (mMediaPlayerLock) {
+ mMediaPlayer = MediaPlayer.create(mContext, mVideoRes);
+ mMediaPlayerState = State.PREPARED;
+ mMediaPlayer.setSurface(mAnimationSurface);
+ mMediaPlayer.setLooping(true);
+ mMediaPlayer.start();
+ mMediaPlayerState = State.STARTED;
}
}
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 25be4fa..2c21771 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -53,6 +53,7 @@
import com.android.settings.applications.specialaccess.notificationaccess.NotificationAccessDetails;
import com.android.settings.applications.specialaccess.pictureinpicture.PictureInPictureDetails;
import com.android.settings.applications.specialaccess.pictureinpicture.PictureInPictureSettings;
+import com.android.settings.applications.specialaccess.premiumsms.PremiumSmsAccess;
import com.android.settings.applications.specialaccess.vrlistener.VrListenerSettings;
import com.android.settings.applications.specialaccess.zenaccess.ZenAccessDetails;
import com.android.settings.backup.PrivacySettings;
@@ -270,6 +271,7 @@
VrListenerSettings.class.getName(),
PictureInPictureSettings.class.getName(),
PictureInPictureDetails.class.getName(),
+ PremiumSmsAccess.class.getName(),
ManagedProfileSettings.class.getName(),
ChooseAccountFragment.class.getName(),
IccLockSettings.class.getName(),
diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProvider.java b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProvider.java
index b755ba7..fe97759 100644
--- a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProvider.java
+++ b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProvider.java
@@ -21,6 +21,7 @@
import android.content.SharedPreferences;
import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
/** Interface should be implemented if you have added new suggestions */
public interface SuggestionFeatureProvider {
@@ -42,4 +43,9 @@
* Returns the {@link SharedPreferences} that holds metadata for suggestions.
*/
SharedPreferences getSharedPrefs(Context context);
+
+ /**
+ * Returns the class of {@link Fragment} that supports contextual suggestion.
+ */
+ Class<? extends Fragment> getContextualSuggestionFragment();
}
diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java
index 60a8c54..deb1c7e 100644
--- a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java
+++ b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java
@@ -22,6 +22,7 @@
import android.content.SharedPreferences;
import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
import com.android.settings.Settings.NightDisplaySuggestionActivity;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollSuggestionActivity;
@@ -86,6 +87,11 @@
return context.getSharedPreferences(SHARED_PREF_FILENAME, Context.MODE_PRIVATE);
}
+ @Override
+ public Class<? extends Fragment> getContextualSuggestionFragment() {
+ return null;
+ }
+
public SuggestionFeatureProviderImpl(Context context) {
final Context appContext = context.getApplicationContext();
mMetricsFeatureProvider = FeatureFactory.getFactory(appContext)
diff --git a/src/com/android/settings/deviceinfo/hardwareinfo/HardwareRevisionPreferenceController.java b/src/com/android/settings/deviceinfo/hardwareinfo/HardwareRevisionPreferenceController.java
index 955c60c..e5fd3da 100644
--- a/src/com/android/settings/deviceinfo/hardwareinfo/HardwareRevisionPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/hardwareinfo/HardwareRevisionPreferenceController.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.os.SystemProperties;
+import android.text.TextUtils;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
@@ -31,8 +32,8 @@
@Override
public int getAvailabilityStatus() {
- return mContext.getResources().getBoolean(R.bool.config_show_device_model)
- ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ return mContext.getResources().getBoolean(R.bool.config_show_device_model) &&
+ !TextUtils.isEmpty(getSummary()) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
@Override
diff --git a/src/com/android/settings/display/TopLevelWallpaperPreferenceController.java b/src/com/android/settings/display/TopLevelWallpaperPreferenceController.java
new file mode 100644
index 0000000..beef4f3
--- /dev/null
+++ b/src/com/android/settings/display/TopLevelWallpaperPreferenceController.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2020 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.display;
+
+import static android.os.UserManager.DISALLOW_SET_WALLPAPER;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.RestrictedLockUtilsInternal;
+import com.android.settingslib.RestrictedTopLevelPreference;
+
+import java.util.List;
+
+/** This controller manages the wallpaper preference of the top level page. */
+public class TopLevelWallpaperPreferenceController extends BasePreferenceController {
+ private static final String TAG = "TopLevelWallpaperPreferenceController";
+ private static final String LAUNCHED_SETTINGS = "app_launched_settings";
+
+ private final String mWallpaperPackage;
+ private final String mWallpaperClass;
+ private final String mStylesAndWallpaperClass;
+ private final String mWallpaperLaunchExtra;
+
+ public TopLevelWallpaperPreferenceController(Context context, String key) {
+ super(context, key);
+ mWallpaperPackage = mContext.getString(R.string.config_wallpaper_picker_package);
+ mWallpaperClass = mContext.getString(R.string.config_wallpaper_picker_class);
+ mStylesAndWallpaperClass =
+ mContext.getString(R.string.config_styles_and_wallpaper_picker_class);
+ mWallpaperLaunchExtra = mContext.getString(R.string.config_wallpaper_picker_launch_extra);
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ Preference preference = screen.findPreference(getPreferenceKey());
+ preference.setTitle(getTitle());
+ }
+
+ public String getTitle() {
+ return mContext.getString(areStylesAvailable()
+ ? R.string.style_and_wallpaper_settings_title : R.string.wallpaper_settings_title);
+ }
+
+ public ComponentName getComponentName() {
+ return new ComponentName(mWallpaperPackage, getComponentClassString());
+ }
+
+ public String getComponentClassString() {
+ return areStylesAvailable() ? mStylesAndWallpaperClass : mWallpaperClass;
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ if ((TextUtils.isEmpty(mWallpaperClass) && TextUtils.isEmpty(mStylesAndWallpaperClass))
+ || TextUtils.isEmpty(mWallpaperPackage)) {
+ Log.e(TAG, "No Wallpaper picker specified!");
+ return UNSUPPORTED_ON_DEVICE;
+ }
+ return canResolveWallpaperComponent(getComponentClassString())
+ ? AVAILABLE_UNSEARCHABLE : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ disablePreferenceIfManaged((RestrictedTopLevelPreference) preference);
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (getPreferenceKey().equals(preference.getKey())) {
+ final Intent intent = new Intent().setComponent(
+ getComponentName()).putExtra(mWallpaperLaunchExtra, LAUNCHED_SETTINGS);
+ if (areStylesAvailable()) {
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
+ preference.getContext().startActivity(intent);
+ return true;
+ }
+ return super.handlePreferenceTreeClick(preference);
+ }
+
+ /** Returns whether Styles & Wallpaper is enabled and available. */
+ public boolean areStylesAvailable() {
+ return !TextUtils.isEmpty(mStylesAndWallpaperClass)
+ && canResolveWallpaperComponent(mStylesAndWallpaperClass);
+ }
+
+ private boolean canResolveWallpaperComponent(String className) {
+ final ComponentName componentName = new ComponentName(mWallpaperPackage, className);
+ final PackageManager pm = mContext.getPackageManager();
+ final Intent intent = new Intent().setComponent(componentName);
+ final List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0 /* flags */);
+ return resolveInfos != null && !resolveInfos.isEmpty();
+ }
+
+ private void disablePreferenceIfManaged(RestrictedTopLevelPreference pref) {
+ final String restriction = DISALLOW_SET_WALLPAPER;
+ if (pref != null) {
+ pref.setDisabledByAdmin(null);
+ if (RestrictedLockUtilsInternal.hasBaseUserRestriction(mContext,
+ restriction, UserHandle.myUserId())) {
+ // Do not show the admin dialog for system restriction.
+ pref.setEnabled(false);
+ } else {
+ pref.checkRestrictionAndSetDisabled(restriction);
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index 237318f..5eb9d94 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -21,6 +21,7 @@
import android.app.settings.SettingsEnums;
import android.os.Bundle;
import android.util.FeatureFlagUtils;
+import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -41,6 +42,9 @@
public class SettingsHomepageActivity extends FragmentActivity {
+ private static final String TAG = "SettingsHomepageActivity";
+ private int mSearchBoxHeight;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -50,7 +54,9 @@
root.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
- setHomepageContainerPaddingTop();
+ final View appBar = findViewById(R.id.app_bar_container);
+ appBar.setMinimumHeight(getSearchBoxHeight());
+ setDefaultHomepageContainerPaddingTop();
final Toolbar toolbar = findViewById(R.id.search_action_bar);
FeatureFactory.getFactory(this).getSearchFeatureProvider()
@@ -60,16 +66,36 @@
getLifecycle().addObserver(new AvatarViewMixin(this, avatarView));
getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
- if (FeatureFlagUtils.isEnabled(this, FeatureFlags.CONTEXTUAL_HOME)
- && !getSystemService(ActivityManager.class).isLowRamDevice()) {
- // Only allow contextual feature on high ram devices.
- showFragment(new ContextualCardsFragment(), R.id.contextual_cards_content);
+ if (!getSystemService(ActivityManager.class).isLowRamDevice()) {
+ // Only allow contextual features on high ram devices.
+ if (FeatureFlagUtils.isEnabled(this, FeatureFlags.SILKY_HOME)) {
+ showSuggestionFragment();
+ }
+ if (FeatureFlagUtils.isEnabled(this, FeatureFlags.CONTEXTUAL_HOME)) {
+ showFragment(new ContextualCardsFragment(), R.id.contextual_cards_content);
+ }
}
showFragment(new TopLevelSettings(), R.id.main_content);
((FrameLayout) findViewById(R.id.main_content))
.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
}
+ private void showSuggestionFragment() {
+ final Class<? extends Fragment> fragment = FeatureFactory.getFactory(this)
+ .getSuggestionFeatureProvider(this).getContextualSuggestionFragment();
+ if (fragment == null) {
+ return;
+ }
+
+ try {
+ showFragment(fragment.newInstance(), R.id.contextual_suggestion_content);
+ setHomepageContainerTopOffset(getResources()
+ .getDimensionPixelSize(R.dimen.suggestion_height));
+ } catch (IllegalAccessException | InstantiationException e) {
+ Log.w(TAG, "Cannot show fragment", e);
+ }
+ }
+
private void showFragment(Fragment fragment, int id) {
final FragmentManager fragmentManager = getSupportFragmentManager();
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
@@ -84,18 +110,32 @@
}
@VisibleForTesting
- void setHomepageContainerPaddingTop() {
- final View view = this.findViewById(R.id.homepage_container);
-
- final int searchBarHeight = getResources().getDimensionPixelSize(R.dimen.search_bar_height);
- final int searchBarMargin = getResources().getDimensionPixelSize(R.dimen.search_bar_margin);
-
- // The top padding is the height of action bar(48dp) + top/bottom margins(16dp)
- final int paddingTop = searchBarHeight + searchBarMargin * 2;
+ void setHomepageContainerTopOffset(int offset) {
+ final View view = findViewById(R.id.homepage_container);
+ final int paddingTop = getSearchBoxHeight() + offset;
view.setPadding(0 /* left */, paddingTop, 0 /* right */, 0 /* bottom */);
// Prevent inner RecyclerView gets focus and invokes scrolling.
view.setFocusableInTouchMode(true);
view.requestFocus();
}
+
+ @VisibleForTesting
+ void setDefaultHomepageContainerPaddingTop() {
+ setHomepageContainerTopOffset(0);
+ }
+
+ @VisibleForTesting
+ int getSearchBoxHeight() {
+ if (mSearchBoxHeight != 0) {
+ return mSearchBoxHeight;
+ }
+
+ final int searchBarHeight = getResources().getDimensionPixelSize(R.dimen.search_bar_height);
+ final int searchBarMargin = getResources().getDimensionPixelSize(R.dimen.search_bar_margin);
+
+ // The height of search box is the height of search bar(48dp) + top/bottom margins(24dp)
+ mSearchBoxHeight = searchBarHeight + searchBarMargin * 2;
+ return mSearchBoxHeight;
+ }
}
diff --git a/src/com/android/settings/network/MobilePlanPreferenceController.java b/src/com/android/settings/network/MobilePlanPreferenceController.java
index 255dfcd..b4135b8 100644
--- a/src/com/android/settings/network/MobilePlanPreferenceController.java
+++ b/src/com/android/settings/network/MobilePlanPreferenceController.java
@@ -145,7 +145,7 @@
}
// Get provisioning URL
- String url = mCm.getMobileProvisioningUrl();
+ String url = mTm.getMobileProvisioningUrl();
if (!TextUtils.isEmpty(url)) {
Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN,
Intent.CATEGORY_APP_BROWSER);
diff --git a/src/com/android/settings/network/ProviderModelSlice.java b/src/com/android/settings/network/ProviderModelSlice.java
index f6908c9..5314d7f 100644
--- a/src/com/android/settings/network/ProviderModelSlice.java
+++ b/src/com/android/settings/network/ProviderModelSlice.java
@@ -165,16 +165,28 @@
if (subscriptionManager == null) {
return;
}
- final boolean newState = intent.getBooleanExtra(EXTRA_TOGGLE_STATE,
- mHelper.isMobileDataEnabled());
final int defaultSubId = subscriptionManager.getDefaultDataSubscriptionId();
log("defaultSubId:" + defaultSubId);
if (!SubscriptionManager.isUsableSubscriptionId(defaultSubId)) {
return; // No subscription - do nothing.
}
+ boolean requestConnectCarrier = !intent.hasExtra(EXTRA_TOGGLE_STATE);
+ // Enable the mobile data always if the user requests to connect to the carrier network.
+ boolean newState = requestConnectCarrier ? true
+ : intent.getBooleanExtra(EXTRA_TOGGLE_STATE, mHelper.isMobileDataEnabled());
MobileNetworkUtils.setMobileDataEnabled(mContext, defaultSubId, newState,
false /* disableOtherSubscriptions */);
+
+ final NetworkProviderWorker worker = getWorker();
+ if (worker == null) {
+ return;
+ }
+ if (requestConnectCarrier) {
+ worker.connectCarrierNetwork();
+ } else {
+ worker.setCarrierNetworkEnabled(newState);
+ }
}
@Override
diff --git a/src/com/android/settings/network/ProviderModelSliceHelper.java b/src/com/android/settings/network/ProviderModelSliceHelper.java
index 482695a..de43737 100644
--- a/src/com/android/settings/network/ProviderModelSliceHelper.java
+++ b/src/com/android/settings/network/ProviderModelSliceHelper.java
@@ -131,14 +131,16 @@
e.printStackTrace();
}
final IconCompat levelIcon = Utils.createIconWithDrawable(drawable);
- final PendingIntent toggleAction = mSliceable.getBroadcastIntent(mContext);
- final SliceAction toggleSliceAction = SliceAction.createToggle(toggleAction,
+ final PendingIntent rowIntent = mSliceable.getBroadcastIntent(mContext);
+ final SliceAction primaryAction = SliceAction.create(rowIntent,
+ levelIcon, ListBuilder.ICON_IMAGE, title);
+ final SliceAction toggleAction = SliceAction.createToggle(rowIntent,
"mobile_toggle" /* actionTitle */, isMobileDataEnabled());
final ListBuilder.RowBuilder rowBuilder = new ListBuilder.RowBuilder()
.setTitle(title)
.setTitleItem(levelIcon, ListBuilder.ICON_IMAGE)
- .addEndItem(toggleSliceAction)
- .setPrimaryAction(toggleSliceAction)
+ .addEndItem(toggleAction)
+ .setPrimaryAction(primaryAction)
.setSubtitle(summary);
return rowBuilder;
}
diff --git a/src/com/android/settings/network/SubscriptionsPreferenceController.java b/src/com/android/settings/network/SubscriptionsPreferenceController.java
index f4ffd09..a17fc60 100644
--- a/src/com/android/settings/network/SubscriptionsPreferenceController.java
+++ b/src/com/android/settings/network/SubscriptionsPreferenceController.java
@@ -21,10 +21,13 @@
import static com.android.settings.network.telephony.MobileNetworkUtils.NO_CELL_DATA_TYPE_ICON;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.graphics.drawable.Drawable;
import android.provider.Settings;
+import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -46,6 +49,7 @@
import com.android.settings.network.telephony.MobileNetworkActivity;
import com.android.settings.network.telephony.MobileNetworkUtils;
import com.android.settings.network.telephony.SignalStrengthListener;
+import com.android.settings.widget.GearPreference;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.net.SignalStrengthUtil;
@@ -55,9 +59,15 @@
import java.util.Set;
/**
- * This manages a set of Preferences it places into a PreferenceGroup owned by some parent
+ * If the provider model is not enabled, this controller manages a set of Preferences it places into
+ * a PreferenceGroup owned by some parent
* controller class - one for each available subscription. This controller is only considered
* available if there are 2 or more subscriptions.
+ *
+ * If the provider model is enabled, this controller manages preference with data subscription
+ * information and make its state display on preference.
+ * TODO this class will clean up the multiple subscriptions functionality after the provider
+ * model is released.
*/
public class SubscriptionsPreferenceController extends AbstractPreferenceController implements
LifecycleObserver, SubscriptionsChangeListener.SubscriptionsChangeListenerClient,
@@ -68,16 +78,30 @@
private UpdateListener mUpdateListener;
private String mPreferenceGroupKey;
private PreferenceGroup mPreferenceGroup;
- private SubscriptionManager mManager;
+ private TelephonyManager mTelephonyManager;
+ private SubscriptionManager mSubscriptionManager;
private SubscriptionsChangeListener mSubscriptionsListener;
private MobileDataEnabledListener mDataEnabledListener;
private DataConnectivityListener mConnectivityListener;
private SignalStrengthListener mSignalStrengthListener;
+ @VisibleForTesting
+ final BroadcastReceiver mDataSubscriptionChangedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (action.equals(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
+ update();
+ }
+ }
+ };
// Map of subscription id to Preference
private Map<Integer, Preference> mSubscriptionPreferences;
private int mStartOrder;
+ private GearPreference mSubsGearPref;
+
+ private SubsPrefCtrlInjector mSubsPrefCtrlInjector;
/**
* This interface lets a parent of this class know that some change happened - this could
* either be because overall availability changed, or because we've added/removed/updated some
@@ -107,21 +131,37 @@
mUpdateListener = updateListener;
mPreferenceGroupKey = preferenceGroupKey;
mStartOrder = startOrder;
- mManager = context.getSystemService(SubscriptionManager.class);
+ mTelephonyManager = context.getSystemService(TelephonyManager.class);
+ mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
mSubscriptionPreferences = new ArrayMap<>();
mSubscriptionsListener = new SubscriptionsChangeListener(context, this);
mDataEnabledListener = new MobileDataEnabledListener(context, this);
mConnectivityListener = new DataConnectivityListener(context, this);
mSignalStrengthListener = new SignalStrengthListener(context, this);
lifecycle.addObserver(this);
+ mSubsPrefCtrlInjector = createSubsPrefCtrlInjector();
+ }
+
+ private void registerDataSubscriptionChangedReceiver() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
+ mContext.registerReceiver(mDataSubscriptionChangedReceiver, filter);
+ }
+
+ private void unRegisterDataSubscriptionChangedReceiver() {
+ if (mDataSubscriptionChangedReceiver != null) {
+ mContext.unregisterReceiver(mDataSubscriptionChangedReceiver);
+ }
+
}
@OnLifecycleEvent(ON_RESUME)
public void onResume() {
mSubscriptionsListener.start();
- mDataEnabledListener.start(SubscriptionManager.getDefaultDataSubscriptionId());
+ mDataEnabledListener.start(mSubsPrefCtrlInjector.getDefaultDataSubscriptionId());
mConnectivityListener.start();
mSignalStrengthListener.resume();
+ registerDataSubscriptionChangedReceiver();
update();
}
@@ -131,6 +171,7 @@
mDataEnabledListener.stop();
mConnectivityListener.stop();
mSignalStrengthListener.pause();
+ unRegisterDataSubscriptionChangedReceiver();
}
@Override
@@ -143,29 +184,116 @@
if (mPreferenceGroup == null) {
return;
}
-
if (!isAvailable()) {
+ if (mSubsGearPref != null) {
+ mPreferenceGroup.removePreference(mSubsGearPref);
+ }
for (Preference pref : mSubscriptionPreferences.values()) {
mPreferenceGroup.removePreference(pref);
}
+
mSubscriptionPreferences.clear();
mSignalStrengthListener.updateSubscriptionIds(Collections.emptySet());
mUpdateListener.onChildrenUpdated();
return;
}
+ if (mSubsPrefCtrlInjector.isProviderModelEnabled(mContext)) {
+ updateForProvider();
+ } else {
+ updateForBase();
+ }
+ }
+
+ private void updateForProvider() {
+ SubscriptionInfo subInfo = mSubscriptionManager.getDefaultDataSubscriptionInfo();
+ if (subInfo == null) {
+ mPreferenceGroup.removeAll();
+ return;
+ }
+ if (mSubsGearPref == null) {
+ mPreferenceGroup.removeAll();
+ mSubsGearPref = new GearPreference(mContext, null);
+ mSubsGearPref.setOnPreferenceClickListener(preference -> {
+ //TODO(b/176141379) Wait for wifiManager#selectCarrier(int subscriptionId)
+ return true;
+ });
+ mSubsGearPref.setOnGearClickListener(p ->
+ startMobileNetworkActivity(mContext, subInfo.getSubscriptionId()));
+ }
+
+ mSubsGearPref.setTitle(subInfo.getDisplayName());
+ mSubsGearPref.setOrder(mStartOrder);
+ //TODO(b/176141828) Wait for api provided by system ui.
+ mSubsGearPref.setSummary(getMobilePreferenceSummary());
+ mSubsGearPref.setIcon(getIcon(subInfo.getSubscriptionId()));
+ mPreferenceGroup.addPreference(mSubsGearPref);
+
+ final Set<Integer> activeDataSubIds = new ArraySet<>();
+ activeDataSubIds.add(subInfo.getSubscriptionId());
+ mSignalStrengthListener.updateSubscriptionIds(activeDataSubIds);
+ mUpdateListener.onChildrenUpdated();
+ }
+
+ private String getMobilePreferenceSummary() {
+ //TODO(b/176141828) Waiting for the api provided by system UI.
+ String result = "5G";
+ if (MobileNetworkUtils.activeNetworkIsCellular(mContext)) {
+ result = "Active, " + result;
+ }
+ return result;
+ }
+
+ private Drawable getIcon(int subId) {
+ final TelephonyManager tmForSubId = mTelephonyManager.createForSubscriptionId(subId);
+ final SignalStrength strength = tmForSubId.getSignalStrength();
+ int level = (strength == null) ? 0 : strength.getLevel();
+
+ int numLevels = SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
+ if (shouldInflateSignalStrength(subId)) {
+ level += 1;
+ numLevels += 1;
+ }
+
+ final boolean isMobileDataOn = tmForSubId.isDataEnabled();
+ final boolean isActiveCellularNetwork =
+ mSubsPrefCtrlInjector.isActiveCellularNetwork(mContext);
+ final boolean isMobileDataAccessible = tmForSubId.getDataState()
+ == TelephonyManager.DATA_CONNECTED;
+ final ServiceState serviceState = tmForSubId.getServiceState();
+ final boolean isVoiceOutOfService = (serviceState == null)
+ ? true
+ : (serviceState.getState() == ServiceState.STATE_OUT_OF_SERVICE);
+
+ Drawable icon = mSubsPrefCtrlInjector.getIcon(mContext, level, numLevels, false);
+
+ if (isActiveCellularNetwork) {
+ icon.setTint(Utils.getColorAccentDefaultColor(mContext));
+ return icon;
+ }
+ if ((isMobileDataOn && isMobileDataAccessible)
+ || (!isMobileDataOn && !isVoiceOutOfService)) {
+ return icon;
+ }
+
+ icon = mContext.getDrawable(R.drawable.ic_signal_strength_zero_bar_no_internet);
+ return icon;
+ }
+
+ private void updateForBase() {
final Map<Integer, Preference> existingPrefs = mSubscriptionPreferences;
mSubscriptionPreferences = new ArrayMap<>();
int order = mStartOrder;
final Set<Integer> activeSubIds = new ArraySet<>();
- final int dataDefaultSubId = SubscriptionManager.getDefaultDataSubscriptionId();
- for (SubscriptionInfo info : SubscriptionUtil.getActiveSubscriptions(mManager)) {
+ final int dataDefaultSubId = mSubsPrefCtrlInjector.getDefaultDataSubscriptionId();
+ for (SubscriptionInfo info :
+ SubscriptionUtil.getActiveSubscriptions(mSubscriptionManager)) {
final int subId = info.getSubscriptionId();
// Avoid from showing subscription(SIM)s which has been marked as hidden
// For example, only one subscription will be shown when there're multiple
// subscriptions with same group UUID.
- if (!canSubscriptionBeDisplayed(mContext, subId)) {
+ if (!mSubsPrefCtrlInjector.canSubscriptionBeDisplayed(mContext, subId)) {
continue;
}
activeSubIds.add(subId);
@@ -181,9 +309,7 @@
pref.setOrder(order++);
pref.setOnPreferenceClickListener(clickedPref -> {
- final Intent intent = new Intent(mContext, MobileNetworkActivity.class);
- intent.putExtra(Settings.EXTRA_SUB_ID, subId);
- mContext.startActivity(intent);
+ startMobileNetworkActivity(mContext, subId);
return true;
});
@@ -198,6 +324,12 @@
mUpdateListener.onChildrenUpdated();
}
+ private static void startMobileNetworkActivity(Context context, int subId) {
+ final Intent intent = new Intent(context, MobileNetworkActivity.class);
+ intent.putExtra(Settings.EXTRA_SUB_ID, subId);
+ context.startActivity(intent);
+ }
+
@VisibleForTesting
boolean shouldInflateSignalStrength(int subId) {
return SignalStrengthUtil.shouldInflateSignalStrength(mContext, subId);
@@ -214,14 +346,9 @@
level += 1;
numLevels += 1;
}
- final boolean showCutOut = !isDefaultForData || !mgr.isDataEnabled();
- pref.setIcon(getIcon(level, numLevels, showCutOut));
- }
- @VisibleForTesting
- Drawable getIcon(int level, int numLevels, boolean cutOut) {
- return MobileNetworkUtils.getSignalStrengthIcon(mContext, level, numLevels,
- NO_CELL_DATA_TYPE_ICON, cutOut);
+ final boolean showCutOut = !isDefaultForData || !mgr.isDataEnabled();
+ pref.setIcon(mSubsPrefCtrlInjector.getIcon(mContext, level, numLevels, showCutOut));
}
/**
@@ -236,8 +363,8 @@
* If a subscription isn't the default for anything, we just say it is available.
*/
protected String getSummary(int subId, boolean isDefaultForData) {
- final int callsDefaultSubId = SubscriptionManager.getDefaultVoiceSubscriptionId();
- final int smsDefaultSubId = SubscriptionManager.getDefaultSmsSubscriptionId();
+ final int callsDefaultSubId = mSubsPrefCtrlInjector.getDefaultVoiceSubscriptionId();
+ final int smsDefaultSubId = mSubsPrefCtrlInjector.getDefaultSmsSubscriptionId();
String line1 = null;
if (subId == callsDefaultSubId && subId == smsDefaultSubId) {
@@ -253,7 +380,7 @@
final TelephonyManager telMgrForSub = mContext.getSystemService(
TelephonyManager.class).createForSubscriptionId(subId);
final boolean dataEnabled = telMgrForSub.isDataEnabled();
- if (dataEnabled && MobileNetworkUtils.activeNetworkIsCellular(mContext)) {
+ if (dataEnabled && mSubsPrefCtrlInjector.isActiveCellularNetwork(mContext)) {
line2 = mContext.getString(R.string.mobile_data_active);
} else if (!dataEnabled) {
line2 = mContext.getString(R.string.mobile_data_off);
@@ -274,14 +401,16 @@
}
/**
- * @return true if there are at least 2 available subscriptions.
+ * @return true if there are at least 2 available subscriptions,
+ * or if there is at least 1 available subscription for provider model.
*/
@Override
public boolean isAvailable() {
if (mSubscriptionsListener.isAirplaneModeOn()) {
return false;
}
- List<SubscriptionInfo> subInfoList = SubscriptionUtil.getActiveSubscriptions(mManager);
+ List<SubscriptionInfo> subInfoList =
+ SubscriptionUtil.getActiveSubscriptions(mSubscriptionManager);
if (subInfoList == null) {
return false;
}
@@ -290,8 +419,9 @@
// For example, only one subscription will be shown when there're multiple
// subscriptions with same group UUID.
.filter(subInfo ->
- canSubscriptionBeDisplayed(mContext, subInfo.getSubscriptionId()))
- .count() >= (Utils.isProviderModelEnabled(mContext) ? 1 : 2);
+ mSubsPrefCtrlInjector.canSubscriptionBeDisplayed(mContext,
+ subInfo.getSubscriptionId()))
+ .count() >= (mSubsPrefCtrlInjector.isProviderModelEnabled(mContext) ? 1 : 2);
}
@Override
@@ -307,7 +437,7 @@
@Override
public void onSubscriptionsChanged() {
// See if we need to change which sub id we're using to listen for enabled/disabled changes.
- int defaultDataSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+ int defaultDataSubId = mSubsPrefCtrlInjector.getDefaultDataSubscriptionId();
if (defaultDataSubId != mDataEnabledListener.getSubId()) {
mDataEnabledListener.stop();
mDataEnabledListener.start(defaultDataSubId);
@@ -335,4 +465,65 @@
return (SubscriptionUtil.getAvailableSubscription(context,
ProxySubscriptionManager.getInstance(context), subId) != null);
}
-}
+
+ SubsPrefCtrlInjector createSubsPrefCtrlInjector() {
+ return new SubsPrefCtrlInjector();
+ }
+
+ /**
+ * To inject necessary data from each static api.
+ */
+ @VisibleForTesting
+ public static class SubsPrefCtrlInjector {
+ /**
+ * Use to inject function and value for class and test class.
+ */
+ public boolean canSubscriptionBeDisplayed(Context context, int subId) {
+ return (SubscriptionUtil.getAvailableSubscription(context,
+ ProxySubscriptionManager.getInstance(context), subId) != null);
+ }
+
+ /**
+ * Check SIM be able to display on UI.
+ */
+ public int getDefaultSmsSubscriptionId() {
+ return SubscriptionManager.getDefaultSmsSubscriptionId();
+ }
+
+ /**
+ * Get default voice subscription ID.
+ */
+ public int getDefaultVoiceSubscriptionId() {
+ return SubscriptionManager.getDefaultVoiceSubscriptionId();
+ }
+
+ /**
+ * Get default data subscription ID.
+ */
+ public int getDefaultDataSubscriptionId() {
+ return SubscriptionManager.getDefaultDataSubscriptionId();
+ }
+
+ /**
+ * Confirm the current network is cellular and active.
+ */
+ public boolean isActiveCellularNetwork(Context context) {
+ return MobileNetworkUtils.activeNetworkIsCellular(context);
+ }
+
+ /**
+ * Confirm the flag of Provider Model switch is turned on or not.
+ */
+ public boolean isProviderModelEnabled(Context context) {
+ return Utils.isProviderModelEnabled(context);
+ }
+
+ /**
+ * Get signal icon with different signal level.
+ */
+ public Drawable getIcon(Context context, int level, int numLevels, boolean cutOut) {
+ return MobileNetworkUtils.getSignalStrengthIcon(context, level, numLevels,
+ NO_CELL_DATA_TYPE_ICON, cutOut);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/notification/zen/AbstractZenModePreferenceController.java b/src/com/android/settings/notification/zen/AbstractZenModePreferenceController.java
index 6fa446b..02e4015 100644
--- a/src/com/android/settings/notification/zen/AbstractZenModePreferenceController.java
+++ b/src/com/android/settings/notification/zen/AbstractZenModePreferenceController.java
@@ -84,7 +84,10 @@
mScreen = screen;
Preference pref = screen.findPreference(KEY);
if (pref != null) {
- mSettingObserver = new SettingObserver(pref);
+ if (mSettingObserver == null) {
+ mSettingObserver = new SettingObserver();
+ }
+ mSettingObserver.setPreference(pref);
}
}
@@ -128,10 +131,13 @@
private final Uri ZEN_MODE_DURATION_URI = Settings.Secure.getUriFor(
Settings.Secure.ZEN_DURATION);
- private final Preference mPreference;
+ private Preference mPreference;
- public SettingObserver(Preference preference) {
+ public SettingObserver() {
super(new Handler());
+ }
+
+ public void setPreference(Preference preference) {
mPreference = preference;
}
diff --git a/src/com/android/settings/wifi/ConfigureWifiSettings.java b/src/com/android/settings/wifi/ConfigureWifiSettings.java
index 81ca183..ff313c7 100644
--- a/src/com/android/settings/wifi/ConfigureWifiSettings.java
+++ b/src/com/android/settings/wifi/ConfigureWifiSettings.java
@@ -63,18 +63,6 @@
}
@Override
- public int getInitialExpandedChildCount() {
- int tileLimit = 1;
- if (mWifiWakeupPreferenceController.isAvailable()) {
- tileLimit++;
- }
- if (mUseOpenWifiPreferenceController.isAvailable()) {
- tileLimit++;
- }
- return tileLimit;
- }
-
- @Override
protected int getPreferenceScreenResId() {
return R.xml.wifi_configure_settings;
}
diff --git a/src/com/android/settings/wifi/WifiUtils.java b/src/com/android/settings/wifi/WifiUtils.java
index 06f74d5..d05260a 100644
--- a/src/com/android/settings/wifi/WifiUtils.java
+++ b/src/com/android/settings/wifi/WifiUtils.java
@@ -56,12 +56,12 @@
}
/**
- * Check if the WPA2-PSK hotspot password is valid.
+ * Check if the hotspot password is valid.
*/
- public static boolean isHotspotWpa2PasswordValid(String password) {
+ public static boolean isHotspotPasswordValid(String password, int securityType) {
final SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
try {
- configBuilder.setPassphrase(password, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+ configBuilder.setPassphrase(password, securityType);
} catch (IllegalArgumentException e) {
return false;
}
diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
index 2957e1f..abf5bec 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppUtils.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
@@ -301,7 +301,11 @@
final String ssid = removeFirstAndLastDoubleQuotes(softApConfiguration.getSsid());
String security;
- if (softApConfiguration.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) {
+ final int securityType = softApConfiguration.getSecurityType();
+ if (securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE) {
+ security = WifiQrCode.SECURITY_SAE;
+ } else if (securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK
+ || securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION) {
security = WifiQrCode.SECURITY_WPA_PSK;
} else {
security = WifiQrCode.SECURITY_NO_PASSWORD;
@@ -431,11 +435,11 @@
private static boolean isSupportHotspotConfiguratorQrCodeGenerator(
SoftApConfiguration softApConfiguration) {
- // QR code generator produces QR code with ZXing's Wi-Fi network config format,
- // it supports PSK and WEP and non security
- // KeyMgmt.NONE is for WEP or non security
- return softApConfiguration.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK
- || softApConfiguration.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_OPEN;
+ final int securityType = softApConfiguration.getSecurityType();
+ return securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE
+ || securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION
+ || securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK
+ || securityType == SoftApConfiguration.SECURITY_TYPE_OPEN;
}
private static boolean isSupportWifiDpp(Context context, int wifiEntrySecurity) {
diff --git a/src/com/android/settings/wifi/slice/WifiScanWorker.java b/src/com/android/settings/wifi/slice/WifiScanWorker.java
index 6c0f4aa..a87b36a 100644
--- a/src/com/android/settings/wifi/slice/WifiScanWorker.java
+++ b/src/com/android/settings/wifi/slice/WifiScanWorker.java
@@ -36,6 +36,7 @@
import com.android.settings.slices.SliceBackgroundWorker;
import com.android.settingslib.utils.ThreadUtils;
+import com.android.wifitrackerlib.MergedCarrierEntry;
import com.android.wifitrackerlib.WifiEntry;
import com.android.wifitrackerlib.WifiEntry.WifiEntryCallback;
import com.android.wifitrackerlib.WifiPickerTracker;
@@ -199,4 +200,18 @@
}
super.updateResults(resultList);
}
+
+ public void setCarrierNetworkEnabled(boolean enable) {
+ final MergedCarrierEntry mergedCarrierEntry = mWifiPickerTracker.getMergedCarrierEntry();
+ if (mergedCarrierEntry != null) {
+ mergedCarrierEntry.setEnabled(enable);
+ }
+ }
+
+ public void connectCarrierNetwork() {
+ final MergedCarrierEntry mergedCarrierEntry = mWifiPickerTracker.getMergedCarrierEntry();
+ if (mergedCarrierEntry != null && mergedCarrierEntry.canConnect()) {
+ mergedCarrierEntry.connect(null /* ConnectCallback */);
+ }
+ }
}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
index be67d22..287e971 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
@@ -43,6 +43,7 @@
private static final String PREF_KEY = "wifi_tether_network_password";
private String mPassword;
+ private int mSecurityType;
private final MetricsFeatureProvider mMetricsFeatureProvider;
@@ -68,13 +69,13 @@
@Override
public void updateDisplay() {
final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
- if (config == null
- || (config.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK
- && TextUtils.isEmpty(config.getPassphrase()))) {
+ if (config.getSecurityType() != SoftApConfiguration.SECURITY_TYPE_OPEN
+ && TextUtils.isEmpty(config.getPassphrase())) {
mPassword = generateRandomPassword();
} else {
mPassword = config.getPassphrase();
}
+ mSecurityType = config.getSecurityType();
((ValidatedEditTextPreference) mPreference).setValidator(this);
((ValidatedEditTextPreference) mPreference).setIsPassword(true);
((ValidatedEditTextPreference) mPreference).setIsSummaryPassword(true);
@@ -105,20 +106,21 @@
// don't actually overwrite unless we get a new config in case it was accidentally toggled.
if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN) {
return "";
- } else if (!isTextValid(mPassword)) {
+ } else if (!WifiUtils.isHotspotPasswordValid(mPassword, securityType)) {
mPassword = generateRandomPassword();
updatePasswordDisplay((EditTextPreference) mPreference);
}
return mPassword;
}
- public void updateVisibility(int securityType) {
+ public void setSecurityType(int securityType) {
+ mSecurityType = securityType;
mPreference.setVisible(securityType != SoftApConfiguration.SECURITY_TYPE_OPEN);
}
@Override
public boolean isTextValid(String value) {
- return WifiUtils.isHotspotWpa2PasswordValid(value);
+ return WifiUtils.isHotspotPasswordValid(value, mSecurityType);
}
private static String generateRandomPassword() {
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceController.java
index 56b5031..ec5e6e0 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceController.java
@@ -1,28 +1,62 @@
+/*
+ * Copyright (C) 2020 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.wifi.tether;
import static com.android.settings.AllInOneTetherSettings.DEDUP_POSTFIX;
+import android.annotation.NonNull;
import android.content.Context;
+import android.net.wifi.SoftApCapability;
import android.net.wifi.SoftApConfiguration;
+import android.net.wifi.WifiManager;
import android.util.FeatureFlagUtils;
+import android.util.Log;
+import androidx.annotation.VisibleForTesting;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.core.FeatureFlags;
-public class WifiTetherSecurityPreferenceController extends WifiTetherBasePreferenceController {
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class WifiTetherSecurityPreferenceController extends WifiTetherBasePreferenceController
+ implements WifiManager.SoftApCallback {
private static final String PREF_KEY = "wifi_tether_security";
- private final String[] mSecurityEntries;
+ private Map<Integer, String> mSecurityMap = new LinkedHashMap<Integer, String>();
private int mSecurityValue;
+ @VisibleForTesting
+ boolean mIsWpa3Supported = true;
public WifiTetherSecurityPreferenceController(Context context,
OnTetherConfigUpdateListener listener) {
super(context, listener);
- mSecurityEntries = mContext.getResources().getStringArray(R.array.wifi_tether_security);
+ final String[] securityNames = mContext.getResources().getStringArray(
+ R.array.wifi_tether_security);
+ final String[] securityValues = mContext.getResources().getStringArray(
+ R.array.wifi_tether_security_values);
+ for (int i = 0; i < securityNames.length; i++) {
+ mSecurityMap.put(Integer.parseInt(securityValues[i]), securityNames[i]);
+ }
+ mWifiManager.registerSoftApCallback(context.getMainExecutor(), this);
}
@Override
@@ -33,35 +67,48 @@
@Override
public void updateDisplay() {
- final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
- if (config != null && config.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_OPEN) {
- mSecurityValue = SoftApConfiguration.SECURITY_TYPE_OPEN;
- } else {
- mSecurityValue = SoftApConfiguration.SECURITY_TYPE_WPA2_PSK;
+ final ListPreference preference = (ListPreference) mPreference;
+ // If the device is not support WPA3 then remove the WPA3 options.
+ if (!mIsWpa3Supported && mSecurityMap.keySet()
+ .removeIf(key -> key > SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)) {
+ preference.setEntries(mSecurityMap.values().stream().toArray(CharSequence[]::new));
+ preference.setEntryValues(mSecurityMap.keySet().stream().map(Integer::toBinaryString)
+ .toArray(CharSequence[]::new));
}
- final ListPreference preference = (ListPreference) mPreference;
- preference.setSummary(getSummaryForSecurityType(mSecurityValue));
+ final int securityType = mWifiManager.getSoftApConfiguration().getSecurityType();
+ mSecurityValue = mSecurityMap.get(securityType) != null
+ ? securityType : SoftApConfiguration.SECURITY_TYPE_WPA2_PSK;
+
+ preference.setSummary(mSecurityMap.get(mSecurityValue));
preference.setValue(String.valueOf(mSecurityValue));
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
mSecurityValue = Integer.parseInt((String) newValue);
- preference.setSummary(getSummaryForSecurityType(mSecurityValue));
- mListener.onTetherConfigUpdated(this);
+ preference.setSummary(mSecurityMap.get(mSecurityValue));
+ if (mListener != null) {
+ mListener.onTetherConfigUpdated(this);
+ }
return true;
}
+ @Override
+ public void onCapabilityChanged(@NonNull SoftApCapability softApCapability) {
+ final boolean isWpa3Supported =
+ softApCapability.areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_WPA3_SAE);
+ if (!isWpa3Supported) {
+ Log.i(PREF_KEY, "WPA3 SAE is not supported on this device");
+ }
+ if (mIsWpa3Supported != isWpa3Supported) {
+ mIsWpa3Supported = isWpa3Supported;
+ updateDisplay();
+ }
+ mWifiManager.unregisterSoftApCallback(this);
+ }
+
public int getSecurityType() {
return mSecurityValue;
}
-
- private String getSummaryForSecurityType(int securityType) {
- if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN) {
- return mSecurityEntries[1];
- }
- // WPA2 PSK
- return mSecurityEntries[0];
- }
}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
index d6c49bc..f260298 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
@@ -192,7 +192,7 @@
@Override
public void onTetherConfigUpdated(AbstractPreferenceController context) {
final SoftApConfiguration config = buildNewConfig();
- mPasswordPreferenceController.updateVisibility(config.getSecurityType());
+ mPasswordPreferenceController.setSecurityType(config.getSecurityType());
/**
* if soft AP is stopped, bring up
@@ -216,10 +216,10 @@
final SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
final int securityType = mSecurityPreferenceController.getSecurityType();
configBuilder.setSsid(mSSIDPreferenceController.getSSID());
- if (securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK) {
+ if (securityType != SoftApConfiguration.SECURITY_TYPE_OPEN) {
configBuilder.setPassphrase(
mPasswordPreferenceController.getPasswordValidated(securityType),
- SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+ securityType);
}
configBuilder.setBand(mApBandPreferenceController.getBandIndex());
return configBuilder.build();
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleAutoclickPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleAutoclickPreferenceControllerTest.java
new file mode 100644
index 0000000..edc2992
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleAutoclickPreferenceControllerTest.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2020 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.accessibility;
+
+import static android.content.Context.MODE_PRIVATE;
+
+import static com.android.settings.accessibility.ToggleAutoclickPreferenceController.AUTOCLICK_CUSTOM_MODE;
+import static com.android.settings.accessibility.ToggleAutoclickPreferenceController.AUTOCLICK_OFF_MODE;
+import static com.android.settings.accessibility.ToggleAutoclickPreferenceController.KEY_AUTOCLICK_CUSTOM_SEEKBAR;
+import static com.android.settings.accessibility.ToggleAutoclickPreferenceController.KEY_DELAY_MODE;
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.provider.Settings.Secure;
+
+import androidx.lifecycle.LifecycleObserver;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.accessibility.ToggleAutoclickPreferenceController.OnChangeListener;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.widget.LayoutPreference;
+import com.android.settingslib.widget.RadioButtonPreference;
+import com.android.settingslib.widget.RadioButtonPreference.OnClickListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+import java.util.Map;
+
+/** Tests for {@link ToggleAutoclickPreferenceController}. */
+@RunWith(RobolectricTestRunner.class)
+public class ToggleAutoclickPreferenceControllerTest {
+
+ @Mock
+ private PreferenceScreen mScreen;
+
+ @Mock
+ private RadioButtonPreference mDelayModePref;
+
+ @Mock
+ private OnChangeListener mOnChangeListener;
+
+ @Mock
+ private LayoutPreference mSeekBarPref;
+
+ @Mock
+ private Map<String, Integer> mAccessibilityAutoclickKeyToValueMap;
+
+ private ToggleAutoclickPreferenceController mController;
+ private SharedPreferences mSharedPreferences;
+ private final String mPrefKey = "prefKey";
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mController = new ToggleAutoclickPreferenceController(mContext, mPrefKey);
+ mController.mAccessibilityAutoclickKeyToValueMap = mAccessibilityAutoclickKeyToValueMap;
+ mSharedPreferences =
+ mContext.getSharedPreferences(mContext.getPackageName(), MODE_PRIVATE);
+
+ when(mScreen.findPreference(mPrefKey)).thenReturn(mDelayModePref);
+ when(mScreen.findPreference(KEY_AUTOCLICK_CUSTOM_SEEKBAR)).thenReturn(mSeekBarPref);
+ when(mAccessibilityAutoclickKeyToValueMap.get(mDelayModePref.getKey())).thenReturn(
+ AUTOCLICK_OFF_MODE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_available() {
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ }
+
+ @Test
+ public void setClickListenerOnDelayModePref_whenDisplay_success() {
+ mController.displayPreference(mScreen);
+
+ verify(mDelayModePref).setOnClickListener(any(OnClickListener.class));
+ }
+
+ @Test
+ public void constructor_hasLifecycle_addObserver() {
+ final Lifecycle lifecycle = mock(Lifecycle.class);
+ mController = new ToggleAutoclickPreferenceController(mContext, lifecycle, mPrefKey);
+
+ verify(lifecycle).addObserver(any(LifecycleObserver.class));
+ }
+
+ @Test
+ public void onRadioButtonClicked_offMode_disableAutoClick() {
+ when(mAccessibilityAutoclickKeyToValueMap.get(mPrefKey)).thenReturn(AUTOCLICK_OFF_MODE);
+
+ mController.displayPreference(mScreen);
+ mController.onRadioButtonClicked(any(RadioButtonPreference.class));
+ final boolean isEnabled = Secure.getInt(mContext.getContentResolver(),
+ Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, /* def= */ 0) == 1;
+ final int delayMs = Secure.getInt(mContext.getContentResolver(),
+ Secure.ACCESSIBILITY_AUTOCLICK_DELAY, /* def= */ 0);
+ final int keyDelayMode = mSharedPreferences.getInt(KEY_DELAY_MODE, AUTOCLICK_CUSTOM_MODE);
+
+ assertThat(keyDelayMode).isEqualTo(AUTOCLICK_OFF_MODE);
+ assertThat(delayMs).isEqualTo(/* expected= */ 0);
+ assertThat(isEnabled).isFalse();
+ }
+
+ @Test
+ public void onRadioButtonClicked_customMode_enableAutoClick() {
+ when(mAccessibilityAutoclickKeyToValueMap.get(mDelayModePref.getKey())).thenReturn(
+ AUTOCLICK_CUSTOM_MODE);
+ when(mAccessibilityAutoclickKeyToValueMap.get(mPrefKey)).thenReturn(AUTOCLICK_CUSTOM_MODE);
+
+ mController.displayPreference(mScreen);
+ mController.onRadioButtonClicked(any(RadioButtonPreference.class));
+ final boolean isEnabled = Secure.getInt(mContext.getContentResolver(),
+ Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, /* def= */ 0) == 1;
+ final int keyDelayMode = mSharedPreferences.getInt(KEY_DELAY_MODE, AUTOCLICK_CUSTOM_MODE);
+
+ assertThat(keyDelayMode).isEqualTo(AUTOCLICK_CUSTOM_MODE);
+ assertThat(isEnabled).isTrue();
+ }
+
+ @Test
+ public void onRadioButtonClicked_hasListener_runOnCheckedChanged() {
+ when(mAccessibilityAutoclickKeyToValueMap.get(mDelayModePref.getKey())).thenReturn(
+ AUTOCLICK_CUSTOM_MODE);
+ when(mAccessibilityAutoclickKeyToValueMap.get(mPrefKey)).thenReturn(AUTOCLICK_CUSTOM_MODE);
+
+ mController.setOnChangeListener(mOnChangeListener);
+ mController.displayPreference(mScreen);
+ mController.onRadioButtonClicked(any(RadioButtonPreference.class));
+
+ verify(mOnChangeListener).onCheckedChanged(mDelayModePref);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/VideoPlayerTest.java b/tests/robotests/src/com/android/settings/accessibility/VideoPlayerTest.java
new file mode 100644
index 0000000..57df456
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/VideoPlayerTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2020 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.accessibility;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.media.MediaPlayer;
+import android.view.Surface;
+import android.view.TextureView;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.accessibility.VideoPlayer.State;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+/** Tests for {@link VideoPlayer}. */
+@RunWith(RobolectricTestRunner.class)
+public class VideoPlayerTest {
+
+ @Mock
+ private MediaPlayer mMediaPlayer;
+
+ @Mock
+ private TextureView mTextureView;
+
+ @Mock
+ private Surface mSurface;
+
+ private VideoPlayer mVideoPlayer;
+
+ @Before
+ public void initVideoPlayer() {
+ MockitoAnnotations.initMocks(this);
+
+ final int videoRes = 0;
+ final Context context = ApplicationProvider.getApplicationContext();
+
+ mVideoPlayer = spy(VideoPlayer.create(context, videoRes, mTextureView));
+ mVideoPlayer.mMediaPlayer = mMediaPlayer;
+ mVideoPlayer.mAnimationSurface = mSurface;
+ }
+
+ @Test
+ public void setSurfaceTextureListener_success() {
+ verify(mTextureView).setSurfaceTextureListener(any());
+ }
+
+ @Test
+ public void onPlayerPaused_startedState_pause() {
+ mVideoPlayer.mMediaPlayerState = State.STARTED;
+
+ mVideoPlayer.pause();
+
+ assertThat(mVideoPlayer.mMediaPlayerState).isEqualTo(State.PAUSED);
+ verify(mMediaPlayer).pause();
+ }
+
+ @Test
+ public void onPlayerResumed_pausedState_start() {
+ mVideoPlayer.mMediaPlayerState = State.PAUSED;
+
+ mVideoPlayer.resume();
+
+ assertThat(mVideoPlayer.mMediaPlayerState).isEqualTo(State.STARTED);
+ verify(mMediaPlayer).start();
+ }
+
+ @Test
+ public void onPlayerReleased_stoppedState_release() {
+ mVideoPlayer.mMediaPlayerState = State.STOPPED;
+
+ mVideoPlayer.release();
+
+ assertThat(mVideoPlayer.mMediaPlayerState).isEqualTo(State.END);
+ verify(mMediaPlayer).release();
+ verify(mSurface).release();
+ }
+
+ @Test
+ public void onSurfaceTextureDestroyed_preparedState_release() {
+ mVideoPlayer.mMediaPlayerState = State.PREPARED;
+
+ mVideoPlayer.onSurfaceTextureDestroyed(any());
+
+ assertThat(mVideoPlayer.mMediaPlayerState).isEqualTo(State.END);
+ verify(mMediaPlayer).release();
+ verify(mSurface).release();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/display/TopLevelWallpaperPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/TopLevelWallpaperPreferenceControllerTest.java
new file mode 100644
index 0000000..7b3ae65
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/display/TopLevelWallpaperPreferenceControllerTest.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2020 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.display;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+
+import androidx.fragment.app.FragmentActivity;
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.testutils.shadow.SettingsShadowResources;
+
+import com.google.common.collect.Lists;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowPackageManager;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {SettingsShadowResources.class})
+public class TopLevelWallpaperPreferenceControllerTest {
+ private static final String TEST_KEY = "test_key";
+
+ private Intent mWallpaperIntent;
+ private Intent mStylesAndWallpaperIntent;
+ private FragmentActivity mContext;
+ private ShadowPackageManager mShadowPackageManager;
+
+ private TopLevelWallpaperPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = Robolectric.buildActivity(FragmentActivity.class).get();
+ SettingsShadowResources.overrideResource(
+ R.string.config_wallpaper_picker_package, "bogus.package.for.testing");
+ SettingsShadowResources.overrideResource(
+ R.string.config_styles_and_wallpaper_picker_class, "bogus.package.class");
+ mWallpaperIntent = new Intent().setComponent(new ComponentName(
+ mContext.getString(R.string.config_wallpaper_picker_package),
+ mContext.getString(R.string.config_wallpaper_picker_class)));
+ mStylesAndWallpaperIntent = new Intent().setComponent(new ComponentName(
+ mContext.getString(R.string.config_wallpaper_picker_package),
+ mContext.getString(R.string.config_styles_and_wallpaper_picker_class)));
+ mShadowPackageManager = Shadows.shadowOf(mContext.getPackageManager());
+ mController = new TopLevelWallpaperPreferenceController(mContext, TEST_KEY);
+ }
+
+ @Test
+ public void isAvailable_wallpaperPickerEnabledAndStylePickerEnabled_returnsTrue() {
+ mShadowPackageManager.setResolveInfosForIntent(
+ mWallpaperIntent, Lists.newArrayList(mock(ResolveInfo.class)));
+ mShadowPackageManager.setResolveInfosForIntent(
+ mStylesAndWallpaperIntent, Lists.newArrayList(mock(ResolveInfo.class)));
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void isAvailable_wallpaperPickerEnabledAndStylePickerDisabled_returnsTrue() {
+ mShadowPackageManager.setResolveInfosForIntent(
+ mWallpaperIntent, Lists.newArrayList(mock(ResolveInfo.class)));
+ mShadowPackageManager.setResolveInfosForIntent(
+ mStylesAndWallpaperIntent, Lists.newArrayList());
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void isAvailable_wallpaperPickerDisabledAndStylePickerEnabled_returnsTrue() {
+ mShadowPackageManager.setResolveInfosForIntent(
+ mWallpaperIntent, Lists.newArrayList());
+ mShadowPackageManager.setResolveInfosForIntent(
+ mStylesAndWallpaperIntent, Lists.newArrayList(mock(ResolveInfo.class)));
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void isAvailable_wallpaperPickerDisabledAndStylePickerDisabled_returnsFalse() {
+ mShadowPackageManager.setResolveInfosForIntent(
+ mWallpaperIntent, Lists.newArrayList());
+ mShadowPackageManager.setResolveInfosForIntent(
+ mStylesAndWallpaperIntent, Lists.newArrayList());
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void getComponentClassString_stylesAvailable_returnsStylePickerClassString() {
+ mShadowPackageManager.setResolveInfosForIntent(
+ mStylesAndWallpaperIntent,
+ Lists.newArrayList(mock(ResolveInfo.class)));
+ assertThat(mController.getComponentClassString())
+ .isEqualTo(mContext.getString(R.string.config_styles_and_wallpaper_picker_class));
+ }
+
+ @Test
+ public void getComponentClassString_stylesUnavailable_returnsWallpaperPickerClassString() {
+ mShadowPackageManager.setResolveInfosForIntent(
+ mStylesAndWallpaperIntent, Lists.newArrayList());
+ assertThat(mController.getComponentClassString())
+ .isEqualTo(mContext.getString(R.string.config_wallpaper_picker_class));
+ }
+
+ @Test
+ public void areStylesAvailable_noComponentSpecified() {
+ SettingsShadowResources.overrideResource(
+ R.string.config_styles_and_wallpaper_picker_class, "");
+ mShadowPackageManager.setResolveInfosForIntent(
+ mStylesAndWallpaperIntent, Lists.newArrayList());
+
+ assertThat(mController.areStylesAvailable()).isFalse();
+ }
+
+ @Test
+ public void areStylesAvailable_componentUnresolveable() {
+ mShadowPackageManager.setResolveInfosForIntent(
+ mStylesAndWallpaperIntent, Lists.newArrayList());
+
+ assertThat(mController.areStylesAvailable()).isFalse();
+ }
+
+ @Test
+ public void areStylesAvailable_componentResolved() {
+ mShadowPackageManager.setResolveInfosForIntent(
+ mStylesAndWallpaperIntent,
+ Lists.newArrayList(mock(ResolveInfo.class)));
+
+ assertThat(mController.areStylesAvailable()).isTrue();
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_wallpaperOnly() {
+ mShadowPackageManager.setResolveInfosForIntent(
+ mWallpaperIntent, Lists.newArrayList(mock(ResolveInfo.class)));
+ mShadowPackageManager.setResolveInfosForIntent(
+ mStylesAndWallpaperIntent, Lists.newArrayList());
+ Preference preference = new Preference(mContext);
+ preference.setKey(TEST_KEY);
+
+ mController.handlePreferenceTreeClick(preference);
+
+ assertThat(Shadows.shadowOf(mContext)
+ .getNextStartedActivityForResult().intent.getComponent().getClassName())
+ .isEqualTo(mContext.getString(R.string.config_wallpaper_picker_class));
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_stylesAndWallpaper() {
+ mShadowPackageManager.setResolveInfosForIntent(
+ mWallpaperIntent, Lists.newArrayList());
+ mShadowPackageManager.setResolveInfosForIntent(
+ mStylesAndWallpaperIntent, Lists.newArrayList(mock(ResolveInfo.class)));
+ Preference preference = new Preference(mContext);
+ preference.setKey(TEST_KEY);
+
+ mController.handlePreferenceTreeClick(preference);
+
+ assertThat(Shadows.shadowOf(mContext)
+ .getNextStartedActivityForResult().intent.getComponent().getClassName())
+ .isEqualTo(mContext.getString(R.string.config_styles_and_wallpaper_picker_class));
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_launchSourceExtra() {
+ mShadowPackageManager.setResolveInfosForIntent(
+ mWallpaperIntent, Lists.newArrayList());
+ mShadowPackageManager.setResolveInfosForIntent(
+ mStylesAndWallpaperIntent, Lists.newArrayList());
+ Preference preference = new Preference(mContext);
+ preference.setKey(TEST_KEY);
+
+ mController.handlePreferenceTreeClick(preference);
+
+ assertThat(Shadows.shadowOf(mContext).getNextStartedActivityForResult()
+ .intent.hasExtra("com.android.wallpaper.LAUNCH_SOURCE")).isTrue();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
index db12580..4c7b4b5 100644
--- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
@@ -48,25 +48,36 @@
@RunWith(RobolectricTestRunner.class)
public class SettingsHomepageActivityTest {
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
- public void setHomepageContainerPaddingTop_shouldBeSetPaddingTop() {
+ public void setDefaultHomepageContainerPaddingTop_shouldSetSearchBoxHeight() {
final SettingsHomepageActivity activity = Robolectric.buildActivity(
SettingsHomepageActivity.class).create().get();
- final int searchBarHeight = activity.getResources().getDimensionPixelSize(
- R.dimen.search_bar_height);
- final int searchBarMargin = activity.getResources().getDimensionPixelSize(
- R.dimen.search_bar_margin);
final View view = activity.findViewById(R.id.homepage_container);
- activity.setHomepageContainerPaddingTop();
+ activity.setDefaultHomepageContainerPaddingTop();
final int actualPaddingTop = view.getPaddingTop();
- assertThat(actualPaddingTop).isEqualTo(searchBarHeight + searchBarMargin * 2);
+ assertThat(actualPaddingTop).isEqualTo(activity.getSearchBoxHeight());
+ }
+
+ @Test
+ public void setHomepageContainerTopOffset_shouldBeSetPaddingTop() {
+ final SettingsHomepageActivity activity = Robolectric.buildActivity(
+ SettingsHomepageActivity.class).create().get();
+ final View view = activity.findViewById(R.id.homepage_container);
+ final int offset = activity.getResources().getDimensionPixelSize(
+ R.dimen.suggestion_height);
+
+ activity.setHomepageContainerTopOffset(offset);
+
+ final int actualPaddingTop = view.getPaddingTop();
+ assertThat(actualPaddingTop).isEqualTo(activity.getSearchBoxHeight() + offset);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java
deleted file mode 100644
index 57b2e2f..0000000
--- a/tests/robotests/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * 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.network;
-
-import static android.telephony.SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
-import static android.telephony.SignalStrength.SIGNAL_STRENGTH_GOOD;
-import static android.telephony.SignalStrength.SIGNAL_STRENGTH_GREAT;
-import static android.telephony.SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-import static android.telephony.SignalStrength.SIGNAL_STRENGTH_POOR;
-import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-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.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.provider.Settings;
-import android.telephony.SignalStrength;
-import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-
-import androidx.lifecycle.LifecycleOwner;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowSubscriptionManager;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowSubscriptionManager.class)
-public class SubscriptionsPreferenceControllerTest {
- private static final String KEY = "preference_group";
-
- @Mock
- private PreferenceScreen mScreen;
- @Mock
- private PreferenceCategory mPreferenceCategory;
- @Mock
- private SubscriptionManager mSubscriptionManager;
- @Mock
- private ConnectivityManager mConnectivityManager;
- @Mock
- private TelephonyManager mTelephonyManager;
- @Mock
- private Network mActiveNetwork;
- @Mock
- private NetworkCapabilities mCapabilities;
- @Mock
- private Drawable mSignalStrengthIcon;
-
- private Context mContext;
- private LifecycleOwner mLifecycleOwner;
- private Lifecycle mLifecycle;
- private SubscriptionsPreferenceController mController;
- private int mOnChildUpdatedCount;
- private SubscriptionsPreferenceController.UpdateListener mUpdateListener;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = spy(RuntimeEnvironment.application);
- mLifecycleOwner = () -> mLifecycle;
- mLifecycle = new Lifecycle(mLifecycleOwner);
- when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
- when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(mConnectivityManager);
- when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
- when(mConnectivityManager.getActiveNetwork()).thenReturn(mActiveNetwork);
- when(mConnectivityManager.getNetworkCapabilities(mActiveNetwork)).thenReturn(mCapabilities);
- when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
- when(mScreen.findPreference(eq(KEY))).thenReturn(mPreferenceCategory);
- when(mPreferenceCategory.getContext()).thenReturn(mContext);
- mOnChildUpdatedCount = 0;
- mUpdateListener = () -> mOnChildUpdatedCount++;
-
- mController = spy(
- new SubscriptionsPreferenceController(mContext, mLifecycle, mUpdateListener,
- KEY, 5));
- doReturn(true).when(mController).canSubscriptionBeDisplayed(any(), anyInt());
- doReturn(mSignalStrengthIcon).when(mController).getIcon(anyInt(), anyInt(), anyBoolean());
- }
-
- @After
- public void tearDown() {
- SubscriptionUtil.setActiveSubscriptionsForTesting(null);
- }
-
- @Test
- public void isAvailable_oneSubscription_availableFalse() {
- setupMockSubscriptions(1);
- assertThat(mController.isAvailable()).isFalse();
- }
-
- @Test
- public void isAvailable_twoSubscriptions_availableTrue() {
- setupMockSubscriptions(2);
- assertThat(mController.isAvailable()).isTrue();
- }
-
- @Test
- public void isAvailable_fiveSubscriptions_availableTrue() {
- setupMockSubscriptions(5);
- assertThat(mController.isAvailable()).isTrue();
- }
-
- @Test
- public void isAvailable_airplaneModeOn_availableFalse() {
- setupMockSubscriptions(2);
- assertThat(mController.isAvailable()).isTrue();
- Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
- assertThat(mController.isAvailable()).isFalse();
- }
-
- @Test
- public void onAirplaneModeChanged_airplaneModeTurnedOn_eventFired() {
- setupMockSubscriptions(2);
- mController.onResume();
- mController.displayPreference(mScreen);
- assertThat(mController.isAvailable()).isTrue();
-
- final int updateCountBeforeModeChange = mOnChildUpdatedCount;
- Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
- mController.onAirplaneModeChanged(true);
- assertThat(mController.isAvailable()).isFalse();
- assertThat(mOnChildUpdatedCount).isEqualTo(updateCountBeforeModeChange + 1);
- }
-
- @Test
- public void onAirplaneModeChanged_airplaneModeTurnedOff_eventFired() {
- Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
- setupMockSubscriptions(2);
- mController.onResume();
- mController.displayPreference(mScreen);
- assertThat(mController.isAvailable()).isFalse();
-
- final int updateCountBeforeModeChange = mOnChildUpdatedCount;
- Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
- mController.onAirplaneModeChanged(false);
- assertThat(mController.isAvailable()).isTrue();
- assertThat(mOnChildUpdatedCount).isEqualTo(updateCountBeforeModeChange + 1);
- }
-
- @Test
- public void onSubscriptionsChanged_countBecameTwo_eventFired() {
- final List<SubscriptionInfo> subs = setupMockSubscriptions(2);
- SubscriptionUtil.setActiveSubscriptionsForTesting(subs.subList(0, 1));
- mController.onResume();
- mController.displayPreference(mScreen);
- assertThat(mController.isAvailable()).isFalse();
-
- final int updateCountBeforeSubscriptionChange = mOnChildUpdatedCount;
- SubscriptionUtil.setActiveSubscriptionsForTesting(subs);
- mController.onSubscriptionsChanged();
- assertThat(mController.isAvailable()).isTrue();
- assertThat(mOnChildUpdatedCount).isEqualTo(updateCountBeforeSubscriptionChange + 1);
- }
-
- @Test
- public void onSubscriptionsChanged_countBecameOne_eventFiredAndPrefsRemoved() {
- final List<SubscriptionInfo> subs = setupMockSubscriptions(2);
- mController.onResume();
- mController.displayPreference(mScreen);
- assertThat(mController.isAvailable()).isTrue();
- verify(mPreferenceCategory, times(2)).addPreference(any(Preference.class));
-
- final int updateCountBeforeSubscriptionChange = mOnChildUpdatedCount;
- SubscriptionUtil.setActiveSubscriptionsForTesting(subs.subList(0, 1));
- mController.onSubscriptionsChanged();
- assertThat(mController.isAvailable()).isFalse();
- assertThat(mOnChildUpdatedCount).isEqualTo(updateCountBeforeSubscriptionChange + 1);
-
- verify(mPreferenceCategory, times(2)).removePreference(any(Preference.class));
- }
-
- @Test
- public void onSubscriptionsChanged_subscriptionReplaced_preferencesChanged() {
- final List<SubscriptionInfo> subs = setupMockSubscriptions(3);
-
- // Start out with only sub1 and sub2.
- SubscriptionUtil.setActiveSubscriptionsForTesting(subs.subList(0, 2));
- mController.onResume();
- mController.displayPreference(mScreen);
- final ArgumentCaptor<Preference> captor = ArgumentCaptor.forClass(Preference.class);
- verify(mPreferenceCategory, times(2)).addPreference(captor.capture());
- assertThat(captor.getAllValues().size()).isEqualTo(2);
- assertThat(captor.getAllValues().get(0).getTitle()).isEqualTo("sub1");
- assertThat(captor.getAllValues().get(1).getTitle()).isEqualTo("sub2");
-
- // Now replace sub2 with sub3, and make sure the old preference was removed and the new
- // preference was added.
- final int updateCountBeforeSubscriptionChange = mOnChildUpdatedCount;
- SubscriptionUtil.setActiveSubscriptionsForTesting(Arrays.asList(subs.get(0), subs.get(2)));
- mController.onSubscriptionsChanged();
- assertThat(mController.isAvailable()).isTrue();
- assertThat(mOnChildUpdatedCount).isEqualTo(updateCountBeforeSubscriptionChange + 1);
-
- verify(mPreferenceCategory).removePreference(captor.capture());
- assertThat(captor.getValue().getTitle()).isEqualTo("sub2");
- verify(mPreferenceCategory, times(3)).addPreference(captor.capture());
- assertThat(captor.getValue().getTitle()).isEqualTo("sub3");
- }
-
-
- /**
- * Helper to create a specified number of subscriptions, display them, and then click on one and
- * verify that the intent fires and has the right subscription id extra.
- *
- * @param subscriptionCount the number of subscriptions
- * @param selectedPrefIndex index of the subscription to click on
- */
- private void runPreferenceClickTest(final int subscriptionCount, final int selectedPrefIndex) {
- final List<SubscriptionInfo> subs = setupMockSubscriptions(subscriptionCount);
- final ArgumentCaptor<Preference> prefCaptor = ArgumentCaptor.forClass(Preference.class);
- mController.displayPreference(mScreen);
- verify(mPreferenceCategory, times(subscriptionCount)).addPreference(prefCaptor.capture());
- final List<Preference> prefs = prefCaptor.getAllValues();
- final Preference pref = prefs.get(selectedPrefIndex);
- final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- doNothing().when(mContext).startActivity(intentCaptor.capture());
- pref.getOnPreferenceClickListener().onPreferenceClick(pref);
- final Intent intent = intentCaptor.getValue();
- assertThat(intent).isNotNull();
- assertThat(intent.hasExtra(Settings.EXTRA_SUB_ID)).isTrue();
- final int subIdFromIntent = intent.getIntExtra(Settings.EXTRA_SUB_ID,
- INVALID_SUBSCRIPTION_ID);
- assertThat(subIdFromIntent).isEqualTo(
- subs.get(selectedPrefIndex).getSubscriptionId());
- }
-
- @Test
- public void twoPreferences_firstPreferenceClicked_correctIntentFires() {
- runPreferenceClickTest(2, 0);
- }
-
- @Test
- public void twoPreferences_secondPreferenceClicked_correctIntentFires() {
- runPreferenceClickTest(2, 1);
- }
-
- @Test
- public void threePreferences_secondPreferenceClicked_correctIntentFires() {
- runPreferenceClickTest(3, 1);
- }
-
- @Test
- public void threePreferences_thirdPreferenceClicked_correctIntentFires() {
- runPreferenceClickTest(3, 2);
- }
-
- @Test
- public void getSummary_twoSubsOneDefaultForEverythingDataActive() {
- setupMockSubscriptions(2);
-
- ShadowSubscriptionManager.setDefaultSmsSubscriptionId(11);
- ShadowSubscriptionManager.setDefaultVoiceSubscriptionId(11);
- when(mTelephonyManager.isDataEnabled()).thenReturn(true);
- when(mCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).thenReturn(true);
-
- assertThat(mController.getSummary(11, true)).isEqualTo(
- mContext.getString(R.string.default_for_calls_and_sms) + System.lineSeparator()
- + mContext.getString(R.string.mobile_data_active));
-
- assertThat(mController.getSummary(22, false)).isEqualTo(
- mContext.getString(R.string.subscription_available));
- }
-
- @Test
- public void getSummary_twoSubsOneDefaultForEverythingDataNotActive() {
- setupMockSubscriptions(2, 1, true);
-
- ShadowSubscriptionManager.setDefaultSmsSubscriptionId(1);
- ShadowSubscriptionManager.setDefaultVoiceSubscriptionId(1);
-
- assertThat(mController.getSummary(1, true)).isEqualTo(
- mContext.getString(R.string.default_for_calls_and_sms) + System.lineSeparator()
- + mContext.getString(R.string.default_for_mobile_data));
-
- assertThat(mController.getSummary(2, false)).isEqualTo(
- mContext.getString(R.string.subscription_available));
- }
-
- @Test
- public void getSummary_twoSubsOneDefaultForEverythingDataDisabled() {
- setupMockSubscriptions(2);
-
- ShadowSubscriptionManager.setDefaultVoiceSubscriptionId(1);
- ShadowSubscriptionManager.setDefaultSmsSubscriptionId(1);
-
- assertThat(mController.getSummary(1, true)).isEqualTo(
- mContext.getString(R.string.default_for_calls_and_sms) + System.lineSeparator()
- + mContext.getString(R.string.mobile_data_off));
-
- assertThat(mController.getSummary(2, false)).isEqualTo(
- mContext.getString(R.string.subscription_available));
- }
-
- @Test
- public void getSummary_twoSubsOneForCallsAndDataOneForSms() {
- setupMockSubscriptions(2, 1, true);
-
- ShadowSubscriptionManager.setDefaultSmsSubscriptionId(2);
- ShadowSubscriptionManager.setDefaultVoiceSubscriptionId(1);
-
- assertThat(mController.getSummary(1, true)).isEqualTo(
- mContext.getString(R.string.default_for_calls) + System.lineSeparator()
- + mContext.getString(R.string.default_for_mobile_data));
-
- assertThat(mController.getSummary(2, false)).isEqualTo(
- mContext.getString(R.string.default_for_sms));
- }
-
- @Test
- public void setIcon_nullStrength_noCrash() {
- final List<SubscriptionInfo> subs = setupMockSubscriptions(2);
- setMockSubSignalStrength(subs, 0, -1);
- final Preference pref = mock(Preference.class);
-
- mController.setIcon(pref, 1, true /* isDefaultForData */);
- verify(mController).getIcon(eq(0), eq(NUM_SIGNAL_STRENGTH_BINS), eq(true));
- }
-
- @Test
- public void setIcon_noSignal_correctLevels() {
- final List<SubscriptionInfo> subs = setupMockSubscriptions(2, 1, true);
- setMockSubSignalStrength(subs, 0, SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
- setMockSubSignalStrength(subs, 1, SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
- setMockSubDataEnabled(subs, 0, true);
- final Preference pref = mock(Preference.class);
-
- mController.setIcon(pref, 1, true /* isDefaultForData */);
- verify(mController).getIcon(eq(0), eq(NUM_SIGNAL_STRENGTH_BINS), eq(false));
-
- mController.setIcon(pref, 2, false /* isDefaultForData */);
- verify(mController).getIcon(eq(0), eq(NUM_SIGNAL_STRENGTH_BINS), eq(true));
- }
-
- @Test
- public void setIcon_noSignal_withInflation_correctLevels() {
- final List<SubscriptionInfo> subs = setupMockSubscriptions(2, 1, true);
- setMockSubSignalStrength(subs, 0, SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
- setMockSubSignalStrength(subs, 1, SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
- final Preference pref = mock(Preference.class);
- doReturn(true).when(mController).shouldInflateSignalStrength(anyInt());
-
- mController.setIcon(pref, 1, true /* isDefaultForData */);
- verify(mController).getIcon(eq(1), eq(NUM_SIGNAL_STRENGTH_BINS + 1), eq(false));
-
- mController.setIcon(pref, 2, false /* isDefaultForData */);
- verify(mController).getIcon(eq(1), eq(NUM_SIGNAL_STRENGTH_BINS + 1), eq(true));
- }
-
- @Test
- public void setIcon_greatSignal_correctLevels() {
- final List<SubscriptionInfo> subs = setupMockSubscriptions(2, 1, true);
- setMockSubSignalStrength(subs, 0, SIGNAL_STRENGTH_GREAT);
- setMockSubSignalStrength(subs, 1, SIGNAL_STRENGTH_GREAT);
- final Preference pref = mock(Preference.class);
-
- mController.setIcon(pref, 1, true /* isDefaultForData */);
- verify(mController).getIcon(eq(4), eq(NUM_SIGNAL_STRENGTH_BINS), eq(false));
-
- mController.setIcon(pref, 2, false /* isDefaultForData */);
- verify(mController).getIcon(eq(4), eq(NUM_SIGNAL_STRENGTH_BINS), eq(true));
- }
-
- @Test
- public void onSignalStrengthChanged_subTwoGoesFromGoodToGreat_correctLevels() {
- final List<SubscriptionInfo> subs = setupMockSubscriptions(2);
- setMockSubSignalStrength(subs, 0, SIGNAL_STRENGTH_POOR);
- setMockSubSignalStrength(subs, 1, SIGNAL_STRENGTH_GOOD);
-
- mController.onResume();
- mController.displayPreference(mScreen);
-
- // Now change the signal strength for the 2nd subscription from Good to Great
- setMockSubSignalStrength(subs, 1, SIGNAL_STRENGTH_GREAT);
- mController.onSignalStrengthChanged();
-
- final ArgumentCaptor<Integer> level = ArgumentCaptor.forClass(Integer.class);
- verify(mController, times(4)).getIcon(level.capture(), eq(NUM_SIGNAL_STRENGTH_BINS),
- eq(true));
- assertThat(level.getAllValues().get(0)).isEqualTo(1);
- assertThat(level.getAllValues().get(1)).isEqualTo(3); // sub2, first time
- assertThat(level.getAllValues().get(2)).isEqualTo(1);
- assertThat(level.getAllValues().get(3)).isEqualTo(4); // sub2, after change
- }
-
- @Test
- public void displayPreference_mobileDataOff_bothSubsHaveCutOut() {
- setupMockSubscriptions(2, 1, false);
-
- mController.onResume();
- mController.displayPreference(mScreen);
-
- verify(mController, times(2)).getIcon(eq(SIGNAL_STRENGTH_GOOD),
- eq(NUM_SIGNAL_STRENGTH_BINS), eq(true));
- }
-
- @Test
- public void displayPreference_mobileDataOn_onlyNonDefaultSubHasCutOut() {
- final List<SubscriptionInfo> subs = setupMockSubscriptions(2, 1, true);
- setMockSubSignalStrength(subs, 1, SIGNAL_STRENGTH_POOR);
-
- mController.onResume();
- mController.displayPreference(mScreen);
-
- verify(mController).getIcon(eq(SIGNAL_STRENGTH_GOOD), eq(NUM_SIGNAL_STRENGTH_BINS),
- eq(false));
- verify(mController).getIcon(eq(SIGNAL_STRENGTH_POOR), eq(NUM_SIGNAL_STRENGTH_BINS),
- eq(true));
- }
-
- @Test
- public void displayPreference_subscriptionsWithSameGroupUUID_onlyOneWillBeSeen() {
- doReturn(false).when(mController).canSubscriptionBeDisplayed(any(), eq(3));
- final List<SubscriptionInfo> subs = setupMockSubscriptions(3);
- SubscriptionUtil.setActiveSubscriptionsForTesting(subs.subList(0, 3));
-
- mController.onResume();
- mController.displayPreference(mScreen);
-
- verify(mPreferenceCategory, times(2)).addPreference(any(Preference.class));
- }
-
- @Test
- public void onMobileDataEnabledChange_mobileDataTurnedOff_bothSubsHaveCutOut() {
- final List<SubscriptionInfo> subs = setupMockSubscriptions(2, 1, true);
-
- mController.onResume();
- mController.displayPreference(mScreen);
-
- setMockSubDataEnabled(subs, 0, false);
- mController.onMobileDataEnabledChange();
-
- final ArgumentCaptor<Boolean> cutOutCaptor = ArgumentCaptor.forClass(Boolean.class);
- verify(mController, times(4)).getIcon(eq(SIGNAL_STRENGTH_GOOD),
- eq(NUM_SIGNAL_STRENGTH_BINS), cutOutCaptor.capture());
- assertThat(cutOutCaptor.getAllValues().get(0)).isEqualTo(false); // sub1, first time
- assertThat(cutOutCaptor.getAllValues().get(1)).isEqualTo(true);
- assertThat(cutOutCaptor.getAllValues().get(2)).isEqualTo(true); // sub1, second time
- assertThat(cutOutCaptor.getAllValues().get(3)).isEqualTo(true);
- }
-
- private List<SubscriptionInfo> setupMockSubscriptions(int count) {
- return setupMockSubscriptions(count, 0, true);
- }
-
- /** Helper method to setup several mock active subscriptions. The generated subscription id's
- * start at 1.
- *
- * @param count How many subscriptions to create
- * @param defaultDataSubId The subscription id of the default data subscription - pass
- * INVALID_SUBSCRIPTION_ID if there should not be one
- * @param mobileDataEnabled Whether mobile data should be considered enabled for the default
- * data subscription
- */
- private List<SubscriptionInfo> setupMockSubscriptions(int count, int defaultDataSubId,
- boolean mobileDataEnabled) {
- if (defaultDataSubId != INVALID_SUBSCRIPTION_ID) {
- ShadowSubscriptionManager.setDefaultDataSubscriptionId(defaultDataSubId);
- }
- final ArrayList<SubscriptionInfo> infos = new ArrayList<>();
- for (int i = 0; i < count; i++) {
- final int subscriptionId = i + 1;
- final SubscriptionInfo info = mock(SubscriptionInfo.class);
- final TelephonyManager mgrForSub = mock(TelephonyManager.class);
- final SignalStrength signalStrength = mock(SignalStrength.class);
-
- if (subscriptionId == defaultDataSubId) {
- when(mgrForSub.isDataEnabled()).thenReturn(mobileDataEnabled);
- }
- when(info.getSubscriptionId()).thenReturn(i + 1);
- when(info.getDisplayName()).thenReturn("sub" + (i + 1));
- doReturn(mgrForSub).when(mTelephonyManager).createForSubscriptionId(eq(subscriptionId));
- when(mgrForSub.getSignalStrength()).thenReturn(signalStrength);
- when(signalStrength.getLevel()).thenReturn(SIGNAL_STRENGTH_GOOD);
-
- infos.add(info);
- }
- SubscriptionUtil.setActiveSubscriptionsForTesting(infos);
- return infos;
- }
-
- /**
- * Helper method to set the signal strength returned for a mock subscription
- * @param subs The list of subscriptions
- * @param index The index in of the subscription in |subs| to change
- * @param level The signal strength level to return for the subscription. Pass -1 to force
- * return of a null SignalStrength object for the subscription.
- */
- private void setMockSubSignalStrength(List<SubscriptionInfo> subs, int index, int level) {
- final TelephonyManager mgrForSub =
- mTelephonyManager.createForSubscriptionId(subs.get(index).getSubscriptionId());
- if (level == -1) {
- when(mgrForSub.getSignalStrength()).thenReturn(null);
- } else {
- final SignalStrength signalStrength = mgrForSub.getSignalStrength();
- when(signalStrength.getLevel()).thenReturn(level);
- }
- }
-
- private void setMockSubDataEnabled(List<SubscriptionInfo> subs, int index, boolean enabled) {
- final TelephonyManager mgrForSub =
- mTelephonyManager.createForSubscriptionId(subs.get(index).getSubscriptionId());
- when(mgrForSub.isDataEnabled()).thenReturn(enabled);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/wifi/slice/WifiScanWorkerTest.java b/tests/robotests/src/com/android/settings/wifi/slice/WifiScanWorkerTest.java
index 395048c..2a8d265 100644
--- a/tests/robotests/src/com/android/settings/wifi/slice/WifiScanWorkerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/slice/WifiScanWorkerTest.java
@@ -20,11 +20,14 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import androidx.lifecycle.Lifecycle;
+import com.android.wifitrackerlib.MergedCarrierEntry;
import com.android.wifitrackerlib.WifiEntry;
import com.android.wifitrackerlib.WifiPickerTracker;
@@ -44,6 +47,8 @@
private WifiScanWorker mWifiScanWorker;
@Mock
WifiPickerTracker mWifiPickerTracker;
+ @Mock
+ MergedCarrierEntry mMergedCarrierEntry;
@Before
public void setUp() {
@@ -51,6 +56,7 @@
mWifiScanWorker = new WifiScanWorker(RuntimeEnvironment.application, WIFI_SLICE_URI);
mWifiScanWorker.mWifiPickerTracker = mWifiPickerTracker;
+ when(mWifiPickerTracker.getMergedCarrierEntry()).thenReturn(mMergedCarrierEntry);
}
@Test
@@ -102,4 +108,24 @@
assertThat(mWifiScanWorker.getWifiEntry(key)).isEqualTo(reachableWifiEntry);
}
+
+ @Test
+ public void setCarrierNetworkEnabled_shouldCallMergedCarrierEntrySetEnabled() {
+ mWifiScanWorker.setCarrierNetworkEnabled(true);
+
+ verify(mMergedCarrierEntry).setEnabled(true);
+
+ mWifiScanWorker.setCarrierNetworkEnabled(false);
+
+ verify(mMergedCarrierEntry).setEnabled(false);
+ }
+
+ @Test
+ public void connectCarrierNetwork_shouldCallMergedCarrierEntryConnect() {
+ when(mMergedCarrierEntry.canConnect()).thenReturn(true);
+
+ mWifiScanWorker.connectCarrierNetwork();
+
+ verify(mMergedCarrierEntry).connect(any());
+ }
}
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java
deleted file mode 100644
index c7d0695..0000000
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package com.android.settings.wifi.tether;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.wifi.SoftApConfiguration;
-import android.net.wifi.WifiManager;
-
-import androidx.preference.ListPreference;
-import androidx.preference.PreferenceScreen;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class WifiTetherSecurityPreferenceControllerTest {
-
- private static final String WPA2_PSK =
- String.valueOf(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
- private static final String NONE = String.valueOf(SoftApConfiguration.SECURITY_TYPE_OPEN);
- @Mock
- private WifiTetherBasePreferenceController.OnTetherConfigUpdateListener mListener;
- private Context mContext;
- @Mock
- private ConnectivityManager mConnectivityManager;
- @Mock
- private WifiManager mWifiManager;
- @Mock
- private PreferenceScreen mScreen;
- private WifiTetherSecurityPreferenceController mController;
- private ListPreference mPreference;
- private SoftApConfiguration mConfig;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mConfig = new SoftApConfiguration.Builder().setSsid("test_1234")
- .setPassphrase("test_password",
- SoftApConfiguration.SECURITY_TYPE_WPA2_PSK).build();
- mContext = spy(RuntimeEnvironment.application);
-
- when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager);
- when(mWifiManager.getSoftApConfiguration()).thenReturn(mConfig);
- when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
- .thenReturn(mConnectivityManager);
- when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{"1", "2"});
- when(mScreen.findPreference(anyString())).thenReturn(mPreference);
-
- mController = new WifiTetherSecurityPreferenceController(mContext, mListener);
- mPreference = new ListPreference(RuntimeEnvironment.application);
- mController.mPreference = mPreference;
- }
-
- @Test
- public void onPreferenceChange_securityValueUpdated() {
- mController.onPreferenceChange(mPreference, WPA2_PSK);
- assertThat(mController.getSecurityType()).isEqualTo(
- SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
- assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2-Personal");
-
- mController.onPreferenceChange(mPreference, NONE);
- assertThat(mController.getSecurityType()).isEqualTo(
- SoftApConfiguration.SECURITY_TYPE_OPEN);
- assertThat(mPreference.getSummary().toString()).isEqualTo("None");
- }
-
- @Test
- public void updateDisplay_preferenceUpdated() {
- // test defaulting to WPA2-Personal on new config
- when(mWifiManager.getSoftApConfiguration()).thenReturn(null);
- mController.updateDisplay();
- assertThat(mController.getSecurityType()).isEqualTo(
- SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
- assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2-Personal");
-
- // test open tether network
- SoftApConfiguration config = new SoftApConfiguration.Builder(mConfig)
- .setPassphrase(null, SoftApConfiguration.SECURITY_TYPE_OPEN).build();
- when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
- mController.updateDisplay();
- assertThat(mController.getSecurityType()).isEqualTo(
- SoftApConfiguration.SECURITY_TYPE_OPEN);
- assertThat(mPreference.getSummary().toString()).isEqualTo("None");
-
- // test WPA2-Personal tether network
- SoftApConfiguration config2 = new SoftApConfiguration.Builder(mConfig)
- .setPassphrase("test_password",
- SoftApConfiguration.SECURITY_TYPE_WPA2_PSK).build();
- when(mWifiManager.getSoftApConfiguration()).thenReturn(config2);
- mController.updateDisplay();
- assertThat(mController.getSecurityType()).isEqualTo(
- SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
- assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2-Personal");
- }
-}
diff --git a/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java b/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
index 9c16b8a..f9450db 100644
--- a/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
+++ b/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
@@ -16,6 +16,8 @@
package com.android.settings.network;
+import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -113,13 +115,14 @@
// Set-up specs for SliceMetadata.
SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
- mMockNetworkProviderWorker = new MockNetworkProviderWorker(mContext,
- PROVIDER_MODEL_SLICE_URI);
+ mMockNetworkProviderWorker = spy(new MockNetworkProviderWorker(mContext,
+ PROVIDER_MODEL_SLICE_URI));
mMockProviderModelSlice = new MockProviderModelSlice(mContext, mMockNetworkProviderWorker);
mListBuilder = spy(new ListBuilder(mContext, PROVIDER_MODEL_SLICE_URI,
ListBuilder.INFINITY).setAccentColor(-1));
when(mProviderModelSliceHelper.createListBuilder(PROVIDER_MODEL_SLICE_URI)).thenReturn(
mListBuilder);
+ when(mProviderModelSliceHelper.getSubscriptionManager()).thenReturn(mSubscriptionManager);
mWifiList = new ArrayList<>();
mMockNetworkProviderWorker.updateSelfResults(mWifiList);
@@ -330,4 +333,33 @@
return mNetworkProviderWorker;
}
}
+
+ @Test
+ public void onNotifyChange_intentToggleActionOn_shouldSetCarrierNetworkEnabledTrue() {
+ Intent intent = mMockProviderModelSlice.getBroadcastIntent(mContext).getIntent();
+ intent.putExtra(EXTRA_TOGGLE_STATE, true);
+
+ mMockProviderModelSlice.onNotifyChange(intent);
+
+ verify(mMockNetworkProviderWorker).setCarrierNetworkEnabled(true);
+ }
+
+ @Test
+ public void onNotifyChange_intentToggleActionOff_shouldSetCarrierNetworkEnabledFalse() {
+ Intent intent = mMockProviderModelSlice.getBroadcastIntent(mContext).getIntent();
+ intent.putExtra(EXTRA_TOGGLE_STATE, false);
+
+ mMockProviderModelSlice.onNotifyChange(intent);
+
+ verify(mMockNetworkProviderWorker).setCarrierNetworkEnabled(false);
+ }
+
+ @Test
+ public void onNotifyChange_intentPrimaryAction_shouldConnectCarrierNetwork() {
+ Intent intent = mMockProviderModelSlice.getBroadcastIntent(mContext).getIntent();
+
+ mMockProviderModelSlice.onNotifyChange(intent);
+
+ verify(mMockNetworkProviderWorker).connectCarrierNetwork();
+ }
}
diff --git a/tests/unit/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java
new file mode 100644
index 0000000..5ee4c42
--- /dev/null
+++ b/tests/unit/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java
@@ -0,0 +1,649 @@
+/*
+ * Copyright (C) 2020 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.network;
+
+import static android.telephony.SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
+import static android.telephony.SignalStrength.SIGNAL_STRENGTH_GOOD;
+import static android.telephony.SignalStrength.SIGNAL_STRENGTH_GREAT;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;;
+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.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.os.Looper;
+import android.provider.Settings;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.Utils;
+import com.android.settings.network.SubscriptionsPreferenceController.SubsPrefCtrlInjector;
+import com.android.settings.testutils.ResourcesUtils;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class SubscriptionsPreferenceControllerTest {
+ private static final String KEY = "preference_group";
+
+ @Mock
+ private SubscriptionManager mSubscriptionManager;
+ @Mock
+ private ConnectivityManager mConnectivityManager;
+ @Mock
+ private TelephonyManager mTelephonyManager;
+ @Mock
+ private TelephonyManager mTelephonyManagerForSub;
+ @Mock
+ private Network mActiveNetwork;
+ @Mock
+ private Lifecycle mLifecycle;
+ @Mock
+ private LifecycleOwner mLifecycleOwner;
+ private LifecycleRegistry mLifecycleRegistry;
+ private int mOnChildUpdatedCount;
+ private Context mContext;
+ private SubscriptionsPreferenceController.UpdateListener mUpdateListener;
+ private PreferenceCategory mPreferenceCategory;
+ private PreferenceScreen mPreferenceScreen;
+ private PreferenceManager mPreferenceManager;
+ private NetworkCapabilities mNetworkCapabilities;
+
+ private FakeSubscriptionsPreferenceController mController;
+ private static SubsPrefCtrlInjector sInjector;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ mLifecycleRegistry = new LifecycleRegistry(mLifecycleOwner);
+
+ when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
+ when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(mConnectivityManager);
+ when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
+ when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
+ when(mConnectivityManager.getActiveNetwork()).thenReturn(mActiveNetwork);
+ when(mConnectivityManager.getNetworkCapabilities(mActiveNetwork))
+ .thenReturn(mNetworkCapabilities);
+ when(mLifecycleOwner.getLifecycle()).thenReturn(mLifecycleRegistry);
+
+ mPreferenceManager = new PreferenceManager(mContext);
+ mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
+ mPreferenceScreen.setInitialExpandedChildrenCount(3);
+ mPreferenceCategory = new PreferenceCategory(mContext);
+ mPreferenceCategory.setKey(KEY);
+ mPreferenceCategory.setOrderingAsAdded(true);
+ mPreferenceScreen.addPreference(mPreferenceCategory);
+
+ mOnChildUpdatedCount = 0;
+ mUpdateListener = () -> mOnChildUpdatedCount++;
+ sInjector = spy(new SubsPrefCtrlInjector());
+ initializeMethod(true, 1, 1, 1, false, false);
+ mController = new FakeSubscriptionsPreferenceController(mContext, mLifecycle,
+ mUpdateListener, KEY, 5);
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
+ }
+
+ @After
+ public void tearDown() {
+ SubscriptionUtil.setActiveSubscriptionsForTesting(null);
+ }
+
+ @Test
+ public void isAvailable_oneSubscription_availableFalse() {
+ setupMockSubscriptions(1);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_oneSubAndProviderOn_availableTrue() {
+ doReturn(true).when(sInjector).isProviderModelEnabled(mContext);
+ setupMockSubscriptions(1);
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void isAvailable_twoSubscriptions_availableTrue() {
+ setupMockSubscriptions(2);
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void isAvailable_fiveSubscriptions_availableTrue() {
+ doReturn(true).when(sInjector).canSubscriptionBeDisplayed(mContext, 0);
+ setupMockSubscriptions(5);
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void isAvailable_airplaneModeOn_availableFalse() {
+ setupMockSubscriptions(2);
+
+ assertThat(mController.isAvailable()).isTrue();
+
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ @UiThreadTest
+ public void onAirplaneModeChanged_airplaneModeTurnedOn_eventFired() {
+ setupMockSubscriptions(2);
+
+ mController.onResume();
+ mController.displayPreference(mPreferenceScreen);
+
+ assertThat(mController.isAvailable()).isTrue();
+
+ final int updateCountBeforeModeChange = mOnChildUpdatedCount;
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+
+ mController.onAirplaneModeChanged(true);
+
+ assertThat(mController.isAvailable()).isFalse();
+ assertThat(mOnChildUpdatedCount).isEqualTo(updateCountBeforeModeChange + 1);
+ }
+
+ @Test
+ @UiThreadTest
+ public void onAirplaneModeChanged_airplaneModeTurnedOff_eventFired() {
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+ setupMockSubscriptions(2);
+
+ mController.onResume();
+ mController.displayPreference(mPreferenceScreen);
+ assertThat(mController.isAvailable()).isFalse();
+
+ final int updateCountBeforeModeChange = mOnChildUpdatedCount;
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
+
+ mController.onAirplaneModeChanged(true);
+
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mOnChildUpdatedCount).isEqualTo(updateCountBeforeModeChange + 1);
+ }
+
+ @Test
+ @UiThreadTest
+ public void onSubscriptionsChanged_countBecameTwo_eventFired() {
+ final List<SubscriptionInfo> subs = setupMockSubscriptions(2);
+ SubscriptionUtil.setActiveSubscriptionsForTesting(subs.subList(0, 1));
+
+ mController.onResume();
+ mController.displayPreference(mPreferenceScreen);
+
+ assertThat(mController.isAvailable()).isFalse();
+
+ final int updateCountBeforeSubscriptionChange = mOnChildUpdatedCount;
+ SubscriptionUtil.setActiveSubscriptionsForTesting(subs);
+
+ mController.onSubscriptionsChanged();
+
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mOnChildUpdatedCount).isEqualTo(updateCountBeforeSubscriptionChange + 1);
+ }
+
+ @Test
+ @UiThreadTest
+ public void onSubscriptionsChanged_countBecameOne_eventFiredAndPrefsRemoved() {
+ final List<SubscriptionInfo> subs = setupMockSubscriptions(2);
+
+ mController.onResume();
+ mController.displayPreference(mPreferenceScreen);
+
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(2);
+
+ final int updateCountBeforeSubscriptionChange = mOnChildUpdatedCount;
+ SubscriptionUtil.setActiveSubscriptionsForTesting(subs.subList(0, 1));
+
+ mController.onSubscriptionsChanged();
+
+ assertThat(mController.isAvailable()).isFalse();
+ assertThat(mOnChildUpdatedCount).isEqualTo(updateCountBeforeSubscriptionChange + 1);
+ assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(0);
+ }
+
+ @Test
+ @UiThreadTest
+ public void onSubscriptionsChanged_subscriptionReplaced_preferencesChanged() {
+ final List<SubscriptionInfo> subs = setupMockSubscriptions(3);
+
+ // Start out with only sub1 and sub2.
+ SubscriptionUtil.setActiveSubscriptionsForTesting(subs.subList(0, 2));
+ mController.onResume();
+ mController.displayPreference(mPreferenceScreen);
+
+ assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(2);
+ assertThat(mPreferenceCategory.getPreference(0).getTitle()).isEqualTo("sub2");
+ assertThat(mPreferenceCategory.getPreference(1).getTitle()).isEqualTo("sub1");
+
+ // Now replace sub2 with sub3, and make sure the old preference was removed and the new
+ // preference was added.
+ final int updateCountBeforeSubscriptionChange = mOnChildUpdatedCount;
+ SubscriptionUtil.setActiveSubscriptionsForTesting(Arrays.asList(subs.get(0), subs.get(2)));
+ mController.onSubscriptionsChanged();
+
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mOnChildUpdatedCount).isEqualTo(updateCountBeforeSubscriptionChange + 1);
+ assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(2);
+ assertThat(mPreferenceCategory.getPreference(0).getTitle()).isEqualTo("sub3");
+ assertThat(mPreferenceCategory.getPreference(1).getTitle()).isEqualTo("sub1");
+ }
+
+ @Test
+ public void getSummary_twoSubsOneDefaultForEverythingDataActive() {
+ setupMockSubscriptions(2);
+
+ doReturn(11).when(sInjector).getDefaultSmsSubscriptionId();
+ doReturn(11).when(sInjector).getDefaultVoiceSubscriptionId();
+ when(mTelephonyManager.isDataEnabled()).thenReturn(true);
+ doReturn(true).when(sInjector).isActiveCellularNetwork(mContext);
+
+ assertThat(mController.getSummary(11, true)).isEqualTo(
+ ResourcesUtils.getResourcesString(mContext, "default_for_calls_and_sms")
+ + System.lineSeparator()
+ + ResourcesUtils.getResourcesString(mContext, "mobile_data_active"));
+
+ assertThat(mController.getSummary(22, false)).isEqualTo(
+ ResourcesUtils.getResourcesString(mContext, "subscription_available"));
+ }
+
+ @Test
+ public void getSummary_twoSubsOneDefaultForEverythingDataNotActive() {
+ setupMockSubscriptions(2, 1, true);
+
+ doReturn(1).when(sInjector).getDefaultSmsSubscriptionId();
+ doReturn(1).when(sInjector).getDefaultVoiceSubscriptionId();
+
+ assertThat(mController.getSummary(1, true)).isEqualTo(
+ ResourcesUtils.getResourcesString(mContext, "default_for_calls_and_sms")
+ + System.lineSeparator()
+ + ResourcesUtils.getResourcesString(mContext, "default_for_mobile_data"));
+
+ assertThat(mController.getSummary(2, false)).isEqualTo(
+ ResourcesUtils.getResourcesString(mContext, "subscription_available"));
+ }
+
+ @Test
+ public void getSummary_twoSubsOneDefaultForEverythingDataDisabled() {
+ setupMockSubscriptions(2);
+
+ doReturn(1).when(sInjector).getDefaultSmsSubscriptionId();
+ doReturn(1).when(sInjector).getDefaultVoiceSubscriptionId();
+
+ assertThat(mController.getSummary(1, true)).isEqualTo(
+ ResourcesUtils.getResourcesString(mContext, "default_for_calls_and_sms")
+ + System.lineSeparator()
+ + ResourcesUtils.getResourcesString(mContext, "mobile_data_off"));
+
+ assertThat(mController.getSummary(2, false)).isEqualTo(
+ ResourcesUtils.getResourcesString(mContext, "subscription_available"));
+ }
+
+ @Test
+ public void getSummary_twoSubsOneForCallsAndDataOneForSms() {
+ setupMockSubscriptions(2, 1, true);
+
+ doReturn(2).when(sInjector).getDefaultSmsSubscriptionId();
+ doReturn(1).when(sInjector).getDefaultVoiceSubscriptionId();
+
+ assertThat(mController.getSummary(1, true)).isEqualTo(
+ ResourcesUtils.getResourcesString(mContext, "default_for_calls")
+ + System.lineSeparator()
+ + ResourcesUtils.getResourcesString(mContext, "default_for_mobile_data"));
+
+ assertThat(mController.getSummary(2, false)).isEqualTo(
+ ResourcesUtils.getResourcesString(mContext, "default_for_sms"));
+ }
+
+ @Test
+ @UiThreadTest
+ public void setIcon_greatSignal_correctLevels() {
+ final List<SubscriptionInfo> subs = setupMockSubscriptions(2, 1, true);
+ setMockSubSignalStrength(subs, 0, SIGNAL_STRENGTH_GREAT);
+ setMockSubSignalStrength(subs, 1, SIGNAL_STRENGTH_GREAT);
+ final Preference pref = new Preference(mContext);
+ final Drawable greatDrawWithoutCutOff = mock(Drawable.class);
+ doReturn(greatDrawWithoutCutOff).when(sInjector)
+ .getIcon(mContext, 4, NUM_SIGNAL_STRENGTH_BINS, true);
+
+ mController.setIcon(pref, 1, true /* isDefaultForData */);
+ assertThat(pref.getIcon()).isEqualTo(greatDrawWithoutCutOff);
+
+ final Drawable greatDrawWithCutOff = mock(Drawable.class);
+ doReturn(greatDrawWithCutOff).when(sInjector)
+ .getIcon(mContext, 4, NUM_SIGNAL_STRENGTH_BINS, true);
+ mController.setIcon(pref, 2, false /* isDefaultForData */);
+ assertThat(pref.getIcon()).isEqualTo(greatDrawWithCutOff);
+ }
+
+ @Test
+ @UiThreadTest
+ public void displayPreference_providerAndHasSim_showPreference() {
+ final List<SubscriptionInfo> sub = setupMockSubscriptions(1);
+ doReturn(true).when(sInjector).isProviderModelEnabled(mContext);
+ doReturn(sub.get(0)).when(mSubscriptionManager).getDefaultDataSubscriptionInfo();
+
+ mController.onResume();
+ mController.displayPreference(mPreferenceScreen);
+
+ assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(1);
+ assertThat(mPreferenceCategory.getPreference(0).getTitle()).isEqualTo("sub1");
+ }
+
+ @Test
+ @UiThreadTest
+ public void displayPreference_providerAndHasMultiSim_showDataSubPreference() {
+ final List<SubscriptionInfo> sub = setupMockSubscriptions(2);
+ doReturn(true).when(sInjector).isProviderModelEnabled(mContext);
+ doReturn(sub.get(0)).when(mSubscriptionManager).getDefaultDataSubscriptionInfo();
+
+ mController.onResume();
+ mController.displayPreference(mPreferenceScreen);
+
+ assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(1);
+ assertThat(mPreferenceCategory.getPreference(0).getTitle()).isEqualTo("sub1");
+ }
+
+ @Test
+ @UiThreadTest
+ public void displayPreference_providerAndNoSim_noPreference() {
+ doReturn(true).when(sInjector).isProviderModelEnabled(mContext);
+ doReturn(null).when(mSubscriptionManager).getDefaultDataSubscriptionInfo();
+
+ mController.onResume();
+ mController.displayPreference(mPreferenceScreen);
+
+ assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(0);
+ }
+
+ @Test
+ @UiThreadTest
+ public void onAirplaneModeChanged_providerAndHasSim_noPreference() {
+ setupMockSubscriptions(1);
+ doReturn(true).when(sInjector).isProviderModelEnabled(mContext);
+ mController.onResume();
+ mController.displayPreference(mPreferenceScreen);
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+
+ mController.onAirplaneModeChanged(true);
+
+ assertThat(mController.isAvailable()).isFalse();
+ assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(0);
+ }
+
+ @Test
+ @UiThreadTest
+ public void dataSubscriptionChanged_providerAndHasMultiSim_showSubId1Preference() {
+ final List<SubscriptionInfo> sub = setupMockSubscriptions(2);
+ doReturn(true).when(sInjector).isProviderModelEnabled(mContext);
+ doReturn(sub.get(0)).when(mSubscriptionManager).getDefaultDataSubscriptionInfo();
+ Intent intent = new Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
+
+ mController.onResume();
+ mController.displayPreference(mPreferenceScreen);
+ mController.mDataSubscriptionChangedReceiver.onReceive(mContext, intent);
+
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(1);
+ assertThat(mPreferenceCategory.getPreference(0).getTitle()).isEqualTo("sub1");
+ }
+
+ @Test
+ @UiThreadTest
+ public void dataSubscriptionChanged_providerAndHasMultiSim_showSubId2Preference() {
+ final List<SubscriptionInfo> sub = setupMockSubscriptions(2);
+ final int subId = sub.get(0).getSubscriptionId();
+ doReturn(true).when(sInjector).isProviderModelEnabled(mContext);
+ doReturn(sub.get(0)).when(mSubscriptionManager).getDefaultDataSubscriptionInfo();
+ Intent intent = new Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
+
+ mController.onResume();
+ mController.displayPreference(mPreferenceScreen);
+
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(1);
+ assertThat(mPreferenceCategory.getPreference(0).getTitle()).isEqualTo("sub1");
+
+ doReturn(sub.get(1)).when(mSubscriptionManager).getDefaultDataSubscriptionInfo();
+
+ mController.mDataSubscriptionChangedReceiver.onReceive(mContext, intent);
+
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(1);
+ assertThat(mPreferenceCategory.getPreference(0).getTitle()).isEqualTo("sub2");
+ }
+
+ @Test
+ @UiThreadTest
+ public void getIcon_cellularIsActive_iconColorIsAccentDefaultColor() {
+ final List<SubscriptionInfo> sub = setupMockSubscriptions(1);
+ doReturn(true).when(sInjector).isProviderModelEnabled(mContext);
+ doReturn(sub.get(0)).when(mSubscriptionManager).getDefaultDataSubscriptionInfo();
+ Drawable icon = mock(Drawable.class);
+ doReturn(icon).when(sInjector).getIcon(any(), anyInt(), anyInt(), eq(false));
+ setupGetIconConditions(sub.get(0).getSubscriptionId(), true, true,
+ TelephonyManager.DATA_CONNECTED, ServiceState.STATE_IN_SERVICE);
+
+ mController.onResume();
+ mController.displayPreference(mPreferenceScreen);
+
+ verify(icon).setTint(Utils.getColorAccentDefaultColor(mContext));
+ }
+
+ @Test
+ @UiThreadTest
+ public void getIcon_dataStateConnectedAndMobileDataOn_iconIsSignalIcon() {
+ final List<SubscriptionInfo> subs = setupMockSubscriptions(1);
+ final int subId = subs.get(0).getSubscriptionId();
+ doReturn(true).when(sInjector).isProviderModelEnabled(mContext);
+ doReturn(subs.get(0)).when(mSubscriptionManager).getDefaultDataSubscriptionInfo();
+ Drawable icon = mock(Drawable.class);
+ doReturn(icon).when(sInjector).getIcon(any(), anyInt(), anyInt(), eq(false));
+ setupGetIconConditions(subId, false, true,
+ TelephonyManager.DATA_CONNECTED, ServiceState.STATE_IN_SERVICE);
+ mController.onResume();
+ mController.displayPreference(mPreferenceScreen);
+ Drawable actualIcon = mPreferenceCategory.getPreference(0).getIcon();
+
+ assertThat(icon).isEqualTo(actualIcon);
+ }
+
+ @Test
+ @UiThreadTest
+ public void getIcon_voiceInServiceAndMobileDataOff_iconIsSignalIcon() {
+ final List<SubscriptionInfo> subs = setupMockSubscriptions(1);
+ final int subId = subs.get(0).getSubscriptionId();
+ doReturn(true).when(sInjector).isProviderModelEnabled(mContext);
+ doReturn(subs.get(0)).when(mSubscriptionManager).getDefaultDataSubscriptionInfo();
+ Drawable icon = mock(Drawable.class);
+ doReturn(icon).when(sInjector).getIcon(any(), anyInt(), anyInt(), eq(false));
+
+ setupGetIconConditions(subId, false, false,
+ TelephonyManager.DATA_DISCONNECTED, ServiceState.STATE_IN_SERVICE);
+
+ mController.onResume();
+ mController.displayPreference(mPreferenceScreen);
+ Drawable actualIcon = mPreferenceCategory.getPreference(0).getIcon();
+ doReturn(TelephonyManager.DATA_CONNECTED).when(mTelephonyManagerForSub).getDataState();
+
+ assertThat(icon).isEqualTo(actualIcon);
+ }
+
+ private void setupGetIconConditions(int subId, boolean isActiveCellularNetwork,
+ boolean isDataEnable, int dataState, int servicestate) {
+ doReturn(mTelephonyManagerForSub).when(mTelephonyManager).createForSubscriptionId(subId);
+ doReturn(isActiveCellularNetwork).when(sInjector).isActiveCellularNetwork(mContext);
+ doReturn(isDataEnable).when(mTelephonyManagerForSub).isDataEnabled();
+ doReturn(dataState).when(mTelephonyManagerForSub).getDataState();
+ ServiceState ss = mock(ServiceState.class);
+ doReturn(ss).when(mTelephonyManagerForSub).getServiceState();
+ doReturn(servicestate).when(ss).getState();
+ }
+
+ private List<SubscriptionInfo> setupMockSubscriptions(int count) {
+ return setupMockSubscriptions(count, 0, true);
+ }
+
+ /** Helper method to setup several mock active subscriptions. The generated subscription id's
+ * start at 1.
+ *
+ * @param count How many subscriptions to create
+ * @param defaultDataSubId The subscription id of the default data subscription - pass
+ * INVALID_SUBSCRIPTION_ID if there should not be one
+ * @param mobileDataEnabled Whether mobile data should be considered enabled for the default
+ * data subscription
+ */
+ private List<SubscriptionInfo> setupMockSubscriptions(int count, int defaultDataSubId,
+ boolean mobileDataEnabled) {
+ if (defaultDataSubId != INVALID_SUBSCRIPTION_ID) {
+ when(sInjector.getDefaultDataSubscriptionId()).thenReturn(defaultDataSubId);
+ }
+ final ArrayList<SubscriptionInfo> infos = new ArrayList<>();
+ for (int i = 0; i < count; i++) {
+ final int subscriptionId = i + 1;
+ final SubscriptionInfo info = mock(SubscriptionInfo.class);
+ final TelephonyManager mgrForSub = mock(TelephonyManager.class);
+ final SignalStrength signalStrength = mock(SignalStrength.class);
+
+ if (subscriptionId == defaultDataSubId) {
+ when(mgrForSub.isDataEnabled()).thenReturn(mobileDataEnabled);
+ }
+ when(info.getSubscriptionId()).thenReturn(subscriptionId);
+ when(info.getDisplayName()).thenReturn("sub" + (subscriptionId));
+ doReturn(mgrForSub).when(mTelephonyManager).createForSubscriptionId(eq(subscriptionId));
+ when(mgrForSub.getSignalStrength()).thenReturn(signalStrength);
+ when(signalStrength.getLevel()).thenReturn(SIGNAL_STRENGTH_GOOD);
+ doReturn(true).when(sInjector).canSubscriptionBeDisplayed(mContext, subscriptionId);
+ infos.add(info);
+ }
+ SubscriptionUtil.setActiveSubscriptionsForTesting(infos);
+ return infos;
+ }
+
+ /**
+ * Helper method to set the signal strength returned for a mock subscription
+ * @param subs The list of subscriptions
+ * @param index The index in of the subscription in |subs| to change
+ * @param level The signal strength level to return for the subscription. Pass -1 to force
+ * return of a null SignalStrength object for the subscription.
+ */
+ private void setMockSubSignalStrength(List<SubscriptionInfo> subs, int index, int level) {
+ final int subId = subs.get(index).getSubscriptionId();
+ doReturn(mTelephonyManagerForSub).when(mTelephonyManager).createForSubscriptionId(subId);
+ if (level == -1) {
+ when(mTelephonyManagerForSub.getSignalStrength()).thenReturn(null);
+ } else {
+ final SignalStrength signalStrength = mock(SignalStrength.class);
+ doReturn(signalStrength).when(mTelephonyManagerForSub).getSignalStrength();
+ when(signalStrength.getLevel()).thenReturn(level);
+ }
+ }
+
+ private void initializeMethod(boolean isSubscriptionCanBeDisplayed,
+ int defaultSmsSubscriptionId, int defaultVoiceSubscriptionId,
+ int defaultDataSubscriptionId, boolean isActiveCellularNetwork,
+ boolean isProviderModelEnabled) {
+ doReturn(isSubscriptionCanBeDisplayed)
+ .when(sInjector).canSubscriptionBeDisplayed(mContext, eq(anyInt()));
+ doReturn(defaultSmsSubscriptionId).when(sInjector).getDefaultSmsSubscriptionId();
+ doReturn(defaultVoiceSubscriptionId).when(sInjector).getDefaultVoiceSubscriptionId();
+ doReturn(defaultDataSubscriptionId).when(sInjector).getDefaultDataSubscriptionId();
+ doReturn(isActiveCellularNetwork).when(sInjector).isActiveCellularNetwork(mContext);
+ doReturn(isProviderModelEnabled).when(sInjector).isProviderModelEnabled(mContext);
+ doReturn(mock(Drawable.class))
+ .when(sInjector).getIcon(any(), anyInt(), anyInt(), eq(false));
+ }
+
+ private static class FakeSubscriptionsPreferenceController
+ extends SubscriptionsPreferenceController {
+
+ /**
+ * @param context the context for the UI where we're placing these preferences
+ * @param lifecycle for listening to lifecycle events for the UI
+ * @param updateListener called to let our parent controller know that our
+ * availability has
+ * changed, or that one or more of the preferences we've placed
+ * in the
+ * PreferenceGroup has changed
+ * @param preferenceGroupKey the key used to lookup the PreferenceGroup where Preferences
+ * will
+ * be placed
+ * @param startOrder the order that should be given to the first Preference
+ * placed into
+ * the PreferenceGroup; the second will use startOrder+1, third
+ * will
+ * use startOrder+2, etc. - this is useful for when the parent
+ * wants
+ * to have other preferences in the same PreferenceGroup and wants
+ */
+ FakeSubscriptionsPreferenceController(Context context, Lifecycle lifecycle,
+ UpdateListener updateListener, String preferenceGroupKey, int startOrder) {
+ super(context, lifecycle, updateListener, preferenceGroupKey, startOrder);
+ }
+
+ @Override
+ protected SubsPrefCtrlInjector createSubsPrefCtrlInjector() {
+ return sInjector;
+ }
+ }
+}
diff --git a/tests/unit/src/com/android/settings/wifi/WifiUtilsTest.java b/tests/unit/src/com/android/settings/wifi/WifiUtilsTest.java
index 7a75443..1a5e852 100644
--- a/tests/unit/src/com/android/settings/wifi/WifiUtilsTest.java
+++ b/tests/unit/src/com/android/settings/wifi/WifiUtilsTest.java
@@ -21,6 +21,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.net.wifi.SoftApConfiguration;
import android.net.wifi.WifiConfiguration;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -46,12 +47,48 @@
public void testPassword() {
final String longPassword = "123456789012345678901234567890"
+ "1234567890123456789012345678901234567890";
- assertThat(WifiUtils.isHotspotWpa2PasswordValid("123")).isFalse();
- assertThat(WifiUtils.isHotspotWpa2PasswordValid("12345678")).isTrue();
- assertThat(WifiUtils.isHotspotWpa2PasswordValid("1234567890")).isTrue();
- assertThat(WifiUtils.isHotspotWpa2PasswordValid(longPassword)).isFalse();
- assertThat(WifiUtils.isHotspotWpa2PasswordValid("")).isFalse();
- assertThat(WifiUtils.isHotspotWpa2PasswordValid("€¥£")).isFalse();
+ assertThat(WifiUtils.isHotspotPasswordValid("123",
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)).isFalse();
+ assertThat(WifiUtils.isHotspotPasswordValid("12345678",
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)).isTrue();
+ assertThat(WifiUtils.isHotspotPasswordValid("1234567890",
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)).isTrue();
+ assertThat(WifiUtils.isHotspotPasswordValid(longPassword,
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)).isFalse();
+ assertThat(WifiUtils.isHotspotPasswordValid("",
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)).isFalse();
+ assertThat(WifiUtils.isHotspotPasswordValid("€¥£",
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)).isFalse();
+
+ // The WPA3_SAE_TRANSITION password limitation should be same as WPA2_PSK
+ assertThat(WifiUtils.isHotspotPasswordValid("123",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)).isFalse();
+ assertThat(WifiUtils.isHotspotPasswordValid("12345678",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)).isTrue();
+ assertThat(WifiUtils.isHotspotPasswordValid("1234567890",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)).isTrue();
+ assertThat(WifiUtils.isHotspotPasswordValid(longPassword,
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)).isFalse();
+ assertThat(WifiUtils.isHotspotPasswordValid("",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)).isFalse();
+ assertThat(WifiUtils.isHotspotPasswordValid("€¥£",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)).isFalse();
+
+ // The WA3_SAE password is requested that length > 1 only.
+ assertThat(WifiUtils.isHotspotPasswordValid("",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)).isFalse();
+ assertThat(WifiUtils.isHotspotPasswordValid("1",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)).isTrue();
+ assertThat(WifiUtils.isHotspotPasswordValid("123",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)).isTrue();
+ assertThat(WifiUtils.isHotspotPasswordValid("12345678",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)).isTrue();
+ assertThat(WifiUtils.isHotspotPasswordValid("1234567890",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)).isTrue();
+ assertThat(WifiUtils.isHotspotPasswordValid(longPassword,
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)).isTrue();
+ assertThat(WifiUtils.isHotspotPasswordValid("€¥£",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)).isTrue();
}
@Test
diff --git a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java
new file mode 100644
index 0000000..836d4e4
--- /dev/null
+++ b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2020 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.wifi.tether;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.wifi.SoftApConfiguration;
+import android.net.wifi.WifiManager;
+import android.os.Looper;
+
+import androidx.preference.ListPreference;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class WifiTetherSecurityPreferenceControllerTest {
+
+ private static final String PREF_KEY = "wifi_tether_security";
+ private static final String WPA3_SAE =
+ String.valueOf(SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
+ private static final String WPA3_SAE_TRANSITION =
+ String.valueOf(SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
+ private static final String WPA2_PSK =
+ String.valueOf(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+ private static final String NONE = String.valueOf(SoftApConfiguration.SECURITY_TYPE_OPEN);
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Mock
+ private WifiManager mWifiManager;
+ @Mock
+ private WifiTetherBasePreferenceController.OnTetherConfigUpdateListener mListener;
+
+ private WifiTetherSecurityPreferenceController mController;
+ private ListPreference mPreference;
+ private SoftApConfiguration mConfig;
+
+ @Before
+ public void setUp() {
+ final Context context = spy(ApplicationProvider.getApplicationContext());
+ mConfig = new SoftApConfiguration.Builder().setSsid("test_1234")
+ .setPassphrase(null, SoftApConfiguration.SECURITY_TYPE_OPEN).build();
+ when(context.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager);
+ when(mWifiManager.getSoftApConfiguration()).thenReturn(mConfig);
+
+ mController = new WifiTetherSecurityPreferenceController(context, mListener);
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ final PreferenceManager preferenceManager = new PreferenceManager(context);
+ final PreferenceScreen screen = preferenceManager.createPreferenceScreen(context);
+ mPreference = new ListPreference(context);
+ mPreference.setKey(PREF_KEY);
+ screen.addPreference(mPreference);
+ mController.displayPreference(screen);
+ }
+
+ @Test
+ public void onPreferenceChange_toWpa3Sae_shouldUpdateSecurityValue() {
+ mController.onPreferenceChange(mPreference, WPA3_SAE);
+
+ assertThat(mController.getSecurityType())
+ .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
+ assertThat(mPreference.getSummary().toString()).isEqualTo("WPA3-Personal");
+ }
+
+ @Test
+ public void onPreferenceChange_toWpa3SaeTransition_shouldUpdateSecurityValue() {
+ mController.onPreferenceChange(mPreference, WPA3_SAE_TRANSITION);
+
+ assertThat(mController.getSecurityType())
+ .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
+ assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2/WPA3-Personal");
+ }
+
+ @Test
+ public void onPreferenceChange_toWpa2Psk_shouldUpdateSecurityValue() {
+ mController.onPreferenceChange(mPreference, WPA2_PSK);
+
+ assertThat(mController.getSecurityType())
+ .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+ assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2-Personal");
+ }
+
+ @Test
+ public void onPreferenceChange_toNone_shouldUpdateSecurityValue() {
+ mController.onPreferenceChange(mPreference, NONE);
+
+ assertThat(mController.getSecurityType())
+ .isEqualTo(SoftApConfiguration.SECURITY_TYPE_OPEN);
+ assertThat(mPreference.getSummary().toString()).isEqualTo("None");
+ }
+
+ @Test
+ public void updateDisplay_toWpa3Sae_shouldUpdateSecurityValue() {
+ SoftApConfiguration config = new SoftApConfiguration.Builder(mConfig)
+ .setPassphrase("test_password",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE).build();
+ when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+
+ mController.updateDisplay();
+
+ assertThat(mController.getSecurityType())
+ .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
+ assertThat(mPreference.getSummary().toString()).isEqualTo("WPA3-Personal");
+ }
+
+ @Test
+ public void updateDisplay_toWpa3SaeTransition_shouldUpdateSecurityValue() {
+ SoftApConfiguration config = new SoftApConfiguration.Builder(mConfig)
+ .setPassphrase("test_password",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION).build();
+ when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+
+ mController.updateDisplay();
+
+ assertThat(mController.getSecurityType())
+ .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
+ assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2/WPA3-Personal");
+ }
+
+ @Test
+ public void updateDisplay_toWpa2Psk_shouldUpdateSecurityValue() {
+ SoftApConfiguration config = new SoftApConfiguration.Builder(mConfig)
+ .setPassphrase("test_password",
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK).build();
+ when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+
+ mController.updateDisplay();
+
+ assertThat(mController.getSecurityType())
+ .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+ assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2-Personal");
+ }
+
+ @Test
+ public void updateDisplay_toNone_shouldUpdateSecurityValue() {
+ SoftApConfiguration config = new SoftApConfiguration.Builder(mConfig)
+ .setPassphrase(null, SoftApConfiguration.SECURITY_TYPE_OPEN).build();
+ when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+
+ mController.updateDisplay();
+
+ assertThat(mController.getSecurityType())
+ .isEqualTo(SoftApConfiguration.SECURITY_TYPE_OPEN);
+ assertThat(mPreference.getSummary().toString()).isEqualTo("None");
+ }
+
+ @Test
+ public void updateDisplay_toWpa3SaeButNotSupportWpa3_shouldBeDefaultToWpa2() {
+ mController.mIsWpa3Supported = false;
+ SoftApConfiguration config = new SoftApConfiguration.Builder(mConfig)
+ .setPassphrase("test_password",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE).build();
+ when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+
+ mController.updateDisplay();
+
+ assertThat(mController.getSecurityType())
+ .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+ assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2-Personal");
+ }
+
+ @Test
+ public void updateDisplay_toWpa3SaeTransitionButNotSupportWpa3_shouldBeDefaultToWpa2() {
+ mController.mIsWpa3Supported = false;
+ SoftApConfiguration config = new SoftApConfiguration.Builder(mConfig)
+ .setPassphrase("test_password",
+ SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION).build();
+ when(mWifiManager.getSoftApConfiguration()).thenReturn(config);
+
+ mController.updateDisplay();
+
+ assertThat(mController.getSecurityType())
+ .isEqualTo(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+ assertThat(mPreference.getSummary().toString()).isEqualTo("WPA2-Personal");
+ }
+}