Snap for 5422062 from 299a04c59b to qt-release
Change-Id: Ia15c10f0820164fc5db00fcef087cbabe50dafcd
This commit is contained in:
@@ -620,8 +620,7 @@
|
||||
|
||||
<activity
|
||||
android:name="Settings$ManageAssistActivity"
|
||||
android:label="@string/assist_and_voice_input_title"
|
||||
android:parentActivityName="Settings">
|
||||
android:label="@string/assist_and_voice_input_title">
|
||||
<intent-filter android:priority="1">
|
||||
<action android:name="android.settings.VOICE_INPUT_SETTINGS" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
@@ -795,7 +794,8 @@
|
||||
|
||||
<activity android:name="Settings$WallpaperSettingsActivity"
|
||||
android:label="@string/wallpaper_settings_fragment_title"
|
||||
android:icon="@drawable/ic_wallpaper">
|
||||
android:icon="@drawable/ic_wallpaper"
|
||||
android:exported="true">
|
||||
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
|
||||
android:value="com.android.settings.wallpaper.WallpaperTypeSettings" />
|
||||
</activity>
|
||||
@@ -2454,6 +2454,18 @@
|
||||
android:value="true" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="Settings$AppBubbleNotificationSettingsActivity"
|
||||
android:label="@string/bubbles_app_toggle_title"
|
||||
android:parentActivityName="Settings$NotificationAppListActivity">
|
||||
<intent-filter android:priority="1">
|
||||
<action android:name="android.settings.APP_NOTIFICATION_BUBBLE_SETTINGS" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
|
||||
android:value="com.android.settings.notification.AppBubbleNotificationSettings" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="Settings$SoundSettingsActivity"
|
||||
android:label="@string/sound_settings"
|
||||
@@ -2566,7 +2578,7 @@
|
||||
|
||||
<receiver android:name=".sim.SimSelectNotification">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PRIMARY_SUBSCRIPTION_LIST_CHANGED"/>
|
||||
<action android:name="android.telephony.action.PRIMARY_SUBSCRIPTION_LIST_CHANGED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
android:layout_marginBottom="8dp"
|
||||
style="?android:attr/progressBarStyleHorizontal"/>
|
||||
|
||||
<com.android.settings.wifi.qrcode.QrPreviewLayout
|
||||
<FrameLayout
|
||||
android:layout_width="@dimen/qrcode_preview_size"
|
||||
android:layout_height="@dimen/qrcode_preview_size">
|
||||
<TextureView
|
||||
@@ -54,7 +54,7 @@
|
||||
android:id="@+id/decorate_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"/>
|
||||
</com.android.settings.wifi.qrcode.QrPreviewLayout>
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/error_message"
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/condition_expand_show"
|
||||
style="@style/ContextualCardStyle">
|
||||
|
||||
<LinearLayout
|
||||
|
||||
@@ -43,18 +43,21 @@
|
||||
android:layout_marginBottom="8dp"
|
||||
style="?android:attr/progressBarStyleHorizontal"/>
|
||||
|
||||
<com.android.settings.wifi.qrcode.QrPreviewLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<TextureView
|
||||
android:id="@+id/preview_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintDimensionRatio="1:1"/>
|
||||
<com.android.settings.wifi.qrcode.QrDecorateView
|
||||
android:id="@+id/decorate_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
</com.android.settings.wifi.qrcode.QrPreviewLayout>
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintDimensionRatio="1:1"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/error_message"
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
<resources>
|
||||
<color name="switchbar_text_color">@android:color/black</color>
|
||||
<color name="switch_bar_background">#dadce0</color>
|
||||
<color name="switchbar_switch_track_tint">#82000000</color>
|
||||
<color name="switchbar_switch_thumb_tint">@android:color/black</color>
|
||||
<color name="homepage_accessibility_background">#783BE5</color>
|
||||
|
||||
@@ -29,9 +29,7 @@
|
||||
<item name="android:colorControlNormal">?android:attr/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.SubSettings" parent="Theme.SubSettings.Base">
|
||||
<item name="android:colorControlNormal">?android:attr/colorAccent</item>
|
||||
</style>
|
||||
<style name="Theme.SubSettings" parent="Theme.SubSettings.Base"/>
|
||||
|
||||
<style name="Theme.AlertDialog.Base" parent="@style/Theme.AppCompat.DayNight.Dialog.Alert">
|
||||
<item name="colorAccent">@*android:color/accent_device_default_dark</item>
|
||||
|
||||
@@ -56,7 +56,6 @@
|
||||
<color name="material_blue_700">#3367D6</color>
|
||||
<color name="material_grey_100">#f5f5f5</color>
|
||||
<color name="material_grey_200">#ffffff</color>
|
||||
<color name="switch_bar_background">#757575</color>
|
||||
|
||||
<color name="message_text_incoming">#ffffffff</color>
|
||||
<color name="message_text_outgoing">#ff323232</color>
|
||||
|
||||
@@ -346,6 +346,7 @@
|
||||
<dimen name="homepage_card_icon_padding_start">14dp</dimen>
|
||||
<dimen name="homepage_card_text_padding_start">16dp</dimen>
|
||||
<dimen name="homepage_card_padding_end">16dp</dimen>
|
||||
<dimen name="homepage_card_corner_radius">@*android:dimen/config_dialogCornerRadius</dimen>
|
||||
<dimen name="homepage_full_card_padding_end">12dp</dimen>
|
||||
<dimen name="homepage_half_card_padding_top">12dp</dimen>
|
||||
<dimen name="homepage_half_card_padding_bottom">16dp</dimen>
|
||||
|
||||
@@ -2284,6 +2284,8 @@
|
||||
</plurals>
|
||||
<!-- Wi-Fi settings screen, advanced, settings section. This is a header shown above advanced wifi settings. [CHAR LIMIT=30] -->
|
||||
<string name="wifi_advanced_titlebar">Advanced Wi\u2011Fi</string>
|
||||
<!-- Wi-Fi settings screen, advanced, title of the item to show the Wi-Fi device's SSID. [CHAR LIMIT=20] -->
|
||||
<string name="wifi_advanced_ssid_title">SSID</string>
|
||||
<!-- Wi-Fi settings screen, advanced, title of the item to show the Wi-Fi device's MAC address. -->
|
||||
<string name="wifi_advanced_mac_address_title">MAC address</string>
|
||||
<!-- Title of the screen to adjust IP settings -->
|
||||
@@ -7789,9 +7791,9 @@
|
||||
<string name="notification_badging_title">Allow notification dots</string>
|
||||
|
||||
<!-- Configure Notifications: Title for the notification bubbles option. [CHAR LIMIT=60] -->
|
||||
<string name="notification_bubbles_title">Allow bubbles</string>
|
||||
<string name="notification_bubbles_title">Bubbles</string>
|
||||
<!-- Configure Notifications: Summary for the notification bubbles option. [CHAR LIMIT=NONE] -->
|
||||
<string name="notification_bubbles_summary">Allow apps to show some notifications as bubbles</string>
|
||||
<string name="notification_bubbles_summary">Quickly access app content from anywhere using floating shortcuts</string>
|
||||
<!-- Feature education for bubbles. [CHAR LIMIT=NONE] -->
|
||||
<string name="bubbles_feature_education">Some notifications and other content can appear as bubbles on the screen. To open a bubble, tap it. To dismiss it, drag it down the screen.</string>
|
||||
<!-- Title for the toggle shown on the app-level bubbles page [CHAR LIMIT=60] -->
|
||||
@@ -8832,7 +8834,7 @@
|
||||
<string name="app_usage_preference">App usage preferences</string>
|
||||
|
||||
<!-- Link title to show stats about how much time user spent in an app [CHAR LIMIT=45] -->
|
||||
<string name="time_spent_in_app_pref_title">Time spent in app</string>
|
||||
<string name="time_spent_in_app_pref_title">Screen time</string>
|
||||
|
||||
<!-- Description of the usage access setting [CHAR LIMIT=NONE] -->
|
||||
<string name="usage_access_description">Usage access allows an app to track what other apps you\u2019re using and how often, as well as your carrier, language settings, and other details.</string>
|
||||
@@ -11013,11 +11015,11 @@
|
||||
<!-- Message for forget passpoint dialog [CHAR LIMIT=none] -->
|
||||
<string name="forget_passpoint_dialog_message">You may lose access to any remaining time or data. Check with your provider before removing.</string>
|
||||
|
||||
<!-- Keywords for Content Capture feature [CHAR_LIMIT=32] -->
|
||||
<string name="keywords_content_capture">content capture</string>
|
||||
<!-- Keywords for Content Capture / Smart Suggestions feature [CHAR_LIMIT=none] -->
|
||||
<string name="keywords_content_capture">content capture, smart suggestions</string>
|
||||
<!-- Title of the 'Content Capture' feature toggle in the Settings -> Privacy screen [CHAR LIMIT=none]-->
|
||||
<string name="content_capture">Content Capture</string>
|
||||
<!-- Description of the 'Content Capture' feature toggle in the Settings -> Privacy screen [CHAR LIMIT=NONE]-->
|
||||
<string name="content_capture">Smart Suggestions</string>
|
||||
<!-- Description of the 'Content Capture / Smart Suggestions' feature toggle in the Settings -> Privacy screen [CHAR LIMIT=NONE]-->
|
||||
<string name="content_capture_summary">Allow Android to save information seen on your screen or heard in video or audio content. Android makes helpful suggestions based on your device activity.</string>
|
||||
|
||||
<!-- Title for the button to initiate a heap dump for the system server. [CHAR LIMIT=NONE] -->
|
||||
@@ -11030,4 +11032,7 @@
|
||||
<string name="automatic_system_heap_dump_title">Automatically capture system heap dumps</string>
|
||||
<!-- Summary of toggle for whether to enable automatic heap dumps for the system server or not. [CHAR LIMIT=NONE] -->
|
||||
<string name="automatic_system_heap_dump_summary">Automatically capture a heap dump for Android System when it uses too much memory</string>
|
||||
|
||||
<!-- Button label to disconnect a Wi-Fi network. [CHAR LIMIT=40] -->
|
||||
<string name="wifi_disconnect_button_text">Disconnect</string>
|
||||
</resources>
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
<item name="android:layout_marginStart">@dimen/homepage_card_side_margin</item>
|
||||
<item name="android:layout_marginEnd">@dimen/homepage_card_side_margin</item>
|
||||
<item name="cardBackgroundColor">@color/contextual_card_background</item>
|
||||
<item name="cardCornerRadius">@*android:dimen/config_dialogCornerRadius</item>
|
||||
<item name="cardCornerRadius">@dimen/homepage_card_corner_radius</item>
|
||||
<item name="cardElevation">0dp</item>
|
||||
<item name="strokeColor">@color/homepage_card_stroke_color</item>
|
||||
<item name="strokeWidth">1dp</item>
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
<style name="ThemeOverlay.SwitchBar.Settings" parent="@android:style/ThemeOverlay.Material.ActionBar">
|
||||
<item name="switchBarMarginStart">@dimen/switchbar_subsettings_margin_start</item>
|
||||
<item name="switchBarMarginEnd">@dimen/switchbar_subsettings_margin_end</item>
|
||||
<item name="switchBarBackgroundColor">@color/switch_bar_background</item>
|
||||
<item name="switchBarBackgroundColor">?android:attr/textColorSecondary</item>
|
||||
<item name="switchBarBackgroundActivatedColor">?android:attr/colorAccent</item>
|
||||
<item name="switchBarRestrictionIcon">@*android:drawable/ic_info</item>
|
||||
</style>
|
||||
@@ -103,6 +103,7 @@
|
||||
<item name="android:trackTint">@color/switchbar_switch_track_tint</item>
|
||||
<item name="android:thumbTint">@color/switchbar_switch_thumb_tint</item>
|
||||
<item name="android:minHeight">@dimen/min_tap_target_size</item>
|
||||
<item name="android:minWidth">@dimen/min_tap_target_size</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.CryptKeeper" parent="@android:style/Theme.Material.NoActionBar">
|
||||
|
||||
@@ -58,12 +58,10 @@
|
||||
android:title="@string/screen_zoom_title"
|
||||
settings:searchable="false"/>
|
||||
|
||||
<ListPreference
|
||||
<Preference
|
||||
android:key="dark_ui_mode_accessibility"
|
||||
android:fragment="com.android.settings.display.DarkUISettings"
|
||||
android:title="@string/dark_ui_mode"
|
||||
android:dialogTitle="@string/dark_ui_mode_title"
|
||||
android:entries="@array/dark_ui_mode_entries"
|
||||
android:entryValues="@array/dark_ui_mode_values"
|
||||
settings:searchable="false" />
|
||||
|
||||
<Preference
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:key="apps_and_notification_screen"
|
||||
android:title="@string/app_and_notification_dashboard_title"
|
||||
settings:initialExpandedChildrenCount="8">
|
||||
settings:initialExpandedChildrenCount="3">
|
||||
<!-- the initial count should include the dynamic tiles -->
|
||||
|
||||
<Preference
|
||||
|
||||
34
res/xml/app_bubble_notification_settings.xml
Normal file
34
res/xml/app_bubble_notification_settings.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2019 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:title="@string/bubbles_app_toggle_title"
|
||||
android:key="app_bubble_notification_settings">
|
||||
<com.android.settingslib.widget.LayoutPreference
|
||||
android:key="pref_app_header"
|
||||
android:layout="@layout/settings_entity_header"/>
|
||||
|
||||
<com.android.settingslib.RestrictedSwitchPreference
|
||||
android:key="bubble_pref"
|
||||
android:title="@string/notification_bubbles_title"/>
|
||||
|
||||
<com.android.settingslib.widget.FooterPreference
|
||||
android:key="notification_bubbles_footer"
|
||||
android:title="@string/bubbles_feature_education"
|
||||
android:selectable="false" />
|
||||
|
||||
</PreferenceScreen>
|
||||
@@ -60,11 +60,10 @@
|
||||
settings:useAdditionalSummary="true"
|
||||
android:order="1001"
|
||||
settings:restrictedSwitchSummary="@string/enabled_by_admin" />
|
||||
<com.android.settingslib.RestrictedSwitchPreference
|
||||
android:key="bubble_pref"
|
||||
<Preference
|
||||
android:key="bubble_link_pref"
|
||||
android:title="@string/notification_bubbles_title"
|
||||
android:order="1002"
|
||||
settings:restrictedSwitchSummary="@string/enabled_by_admin" />
|
||||
android:order="1002" />
|
||||
<Preference
|
||||
android:key="app_link"
|
||||
android:order="1003"
|
||||
|
||||
33
res/xml/bubble_notification_settings.xml
Normal file
33
res/xml/bubble_notification_settings.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2019 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:title="@string/bubbles_app_toggle_title"
|
||||
android:key="bubble_notification_settings">
|
||||
<!-- Notification bubbles -->
|
||||
<SwitchPreference
|
||||
android:key="global_notification_bubbles"
|
||||
android:title="@string/notification_bubbles_title"
|
||||
android:summary="@string/notification_bubbles_summary"
|
||||
settings:controller="com.android.settings.notification.BubbleNotificationPreferenceController"/>
|
||||
|
||||
<com.android.settingslib.widget.FooterPreference
|
||||
android:key="notification_bubbles_footer"
|
||||
android:title="@string/bubbles_feature_education"
|
||||
android:selectable="false" />
|
||||
|
||||
</PreferenceScreen>
|
||||
@@ -63,8 +63,7 @@
|
||||
android:dialogTitle="@string/notification_channel_sound_title"
|
||||
android:order="11"
|
||||
android:showSilent="true"
|
||||
android:showDefault="true"
|
||||
android:ringtoneType="notification" />
|
||||
android:showDefault="true"/>
|
||||
|
||||
<!-- Vibration -->
|
||||
<com.android.settingslib.RestrictedSwitchPreference
|
||||
|
||||
@@ -70,11 +70,11 @@
|
||||
settings:controller="com.android.settings.notification.BadgingNotificationPreferenceController"/>
|
||||
|
||||
<!-- Notification bubbles -->
|
||||
<SwitchPreference
|
||||
<Preference
|
||||
android:key="notification_bubbles"
|
||||
android:title="@string/notification_bubbles_title"
|
||||
android:summary="@string/notification_bubbles_summary"
|
||||
settings:controller="com.android.settings.notification.BubbleNotificationPreferenceController"/>
|
||||
settings:controller="com.android.settings.notification.BubbleSummaryNotificationPreferenceController"
|
||||
android:fragment="com.android.settings.notification.BubbleNotificationSettings"/>
|
||||
|
||||
<!-- Pulse notification light -->
|
||||
<SwitchPreference
|
||||
|
||||
@@ -26,13 +26,11 @@
|
||||
android:title="@string/summary_placeholder"
|
||||
android:selectable="false"
|
||||
android:layout="@layout/battery_header"
|
||||
settings:allowDividerBelow="true"
|
||||
settings:controller="com.android.settings.fuelgauge.BatteryHeaderPreferenceController" />
|
||||
|
||||
<com.android.settings.widget.CardPreference
|
||||
android:key="battery_tip"
|
||||
android:title="@string/summary_placeholder"
|
||||
settings:allowDividerAbove="true"
|
||||
settings:controller="com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController" />
|
||||
|
||||
<Preference
|
||||
|
||||
@@ -62,26 +62,6 @@
|
||||
android:summary="@string/summary_placeholder"
|
||||
settings:searchable="false"/>
|
||||
|
||||
<!-- Content Capture -->
|
||||
|
||||
<!-- NOTE: content capture has a different preference, depending whether or not the
|
||||
ContentCaptureService implementations defines a custom settings activitiy on its manifest.
|
||||
Hence, we show both here, but the controller itself will decide if it's available or not.
|
||||
-->
|
||||
|
||||
<SwitchPreference
|
||||
android:key="content_capture"
|
||||
android:title="@string/content_capture"
|
||||
android:summary="@string/content_capture_summary"
|
||||
settings:controller="com.android.settings.privacy.EnableContentCapturePreferenceController"/>
|
||||
|
||||
<com.android.settings.widget.MasterSwitchPreference
|
||||
android:key="content_capture_custom_settings"
|
||||
android:title="@string/content_capture"
|
||||
android:summary="@string/content_capture_summary"
|
||||
settings:controller="com.android.settings.privacy.EnableContentCaptureWithServiceSettingsPreferenceController">
|
||||
</com.android.settings.widget.MasterSwitchPreference>
|
||||
|
||||
<!-- Privacy Service -->
|
||||
<PreferenceCategory
|
||||
android:key="privacy_services"/>
|
||||
@@ -105,4 +85,24 @@
|
||||
settings:searchable="false"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<!-- Content Capture -->
|
||||
|
||||
<!-- NOTE: content capture has a different preference, depending whether or not the
|
||||
ContentCaptureService implementations defines a custom settings activitiy on its manifest.
|
||||
Hence, we show both here, but the controller itself will decide if it's available or not.
|
||||
-->
|
||||
|
||||
<SwitchPreference
|
||||
android:key="content_capture"
|
||||
android:title="@string/content_capture"
|
||||
android:summary="@string/content_capture_summary"
|
||||
settings:controller="com.android.settings.privacy.EnableContentCapturePreferenceController"/>
|
||||
|
||||
<com.android.settings.widget.MasterSwitchPreference
|
||||
android:key="content_capture_custom_settings"
|
||||
android:title="@string/content_capture"
|
||||
android:summary="@string/content_capture_summary"
|
||||
settings:controller="com.android.settings.privacy.EnableContentCaptureWithServiceSettingsPreferenceController">
|
||||
</com.android.settings.widget.MasterSwitchPreference>
|
||||
|
||||
</PreferenceScreen>
|
||||
@@ -84,6 +84,11 @@
|
||||
<PreferenceCategory
|
||||
android:key="ip_details_category"
|
||||
android:title="@string/wifi_setup_detail">
|
||||
<Preference
|
||||
android:key="ssid"
|
||||
android:title="@string/wifi_advanced_ssid_title"
|
||||
android:selectable="false"
|
||||
settings:enableCopying="true"/>
|
||||
<Preference
|
||||
android:key="mac_address"
|
||||
android:title="@string/wifi_advanced_mac_address_title"
|
||||
|
||||
@@ -113,6 +113,7 @@ public class Settings extends SettingsActivity {
|
||||
public static class ZenModeEventRuleSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class SoundSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class ConfigureNotificationSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class AppBubbleNotificationSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class NotificationAssistantSettingsActivity extends SettingsActivity{ /* empty */ }
|
||||
public static class NotificationAppListActivity extends SettingsActivity { /* empty */ }
|
||||
public static class AppNotificationSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
|
||||
@@ -30,46 +30,59 @@ public class SetupWizardUtils {
|
||||
if (theme == null) {
|
||||
theme = SetupWizardProperties.theme().orElse("");
|
||||
}
|
||||
// TODO(yukl): Move to ThemeResolver and add any additional required attributes in
|
||||
// onApplyThemeResource using Theme overlays
|
||||
if (theme != null) {
|
||||
switch (theme) {
|
||||
case ThemeHelper.THEME_GLIF_V3_LIGHT:
|
||||
return R.style.GlifV3Theme_Light;
|
||||
case ThemeHelper.THEME_GLIF_V3:
|
||||
return R.style.GlifV3Theme;
|
||||
case ThemeHelper.THEME_GLIF_V2_LIGHT:
|
||||
return R.style.GlifV2Theme_Light;
|
||||
case ThemeHelper.THEME_GLIF_V2:
|
||||
return R.style.GlifV2Theme;
|
||||
case ThemeHelper.THEME_GLIF_LIGHT:
|
||||
return R.style.GlifTheme_Light;
|
||||
case ThemeHelper.THEME_GLIF:
|
||||
return R.style.GlifTheme;
|
||||
if (WizardManagerHelper.isAnySetupWizard(intent)) {
|
||||
switch (theme) {
|
||||
case ThemeHelper.THEME_GLIF_V3_LIGHT:
|
||||
return R.style.GlifV3Theme_Light;
|
||||
case ThemeHelper.THEME_GLIF_V3:
|
||||
return R.style.GlifV3Theme;
|
||||
case ThemeHelper.THEME_GLIF_V2_LIGHT:
|
||||
return R.style.GlifV2Theme_Light;
|
||||
case ThemeHelper.THEME_GLIF_V2:
|
||||
return R.style.GlifV2Theme;
|
||||
case ThemeHelper.THEME_GLIF_LIGHT:
|
||||
return R.style.GlifTheme_Light;
|
||||
case ThemeHelper.THEME_GLIF:
|
||||
return R.style.GlifTheme;
|
||||
}
|
||||
} else {
|
||||
switch (theme) {
|
||||
case ThemeHelper.THEME_GLIF_V3_LIGHT:
|
||||
case ThemeHelper.THEME_GLIF_V3:
|
||||
return R.style.GlifV3Theme;
|
||||
case ThemeHelper.THEME_GLIF_V2_LIGHT:
|
||||
case ThemeHelper.THEME_GLIF_V2:
|
||||
return R.style.GlifV2Theme;
|
||||
case ThemeHelper.THEME_GLIF_LIGHT:
|
||||
case ThemeHelper.THEME_GLIF:
|
||||
return R.style.GlifTheme;
|
||||
}
|
||||
}
|
||||
}
|
||||
return R.style.GlifTheme_Light;
|
||||
return R.style.GlifTheme;
|
||||
}
|
||||
|
||||
public static int getTransparentTheme(Intent intent) {
|
||||
final int suwTheme = getTheme(intent);
|
||||
int wifiDialogTheme = R.style.GlifV2Theme_Light_Transparent;
|
||||
int transparentTheme = R.style.GlifV2Theme_Light_Transparent;
|
||||
if (suwTheme == R.style.GlifV3Theme) {
|
||||
wifiDialogTheme = R.style.GlifV3Theme_Transparent;
|
||||
transparentTheme = R.style.GlifV3Theme_Transparent;
|
||||
} else if (suwTheme == R.style.GlifV3Theme_Light) {
|
||||
wifiDialogTheme = R.style.GlifV3Theme_Light_Transparent;
|
||||
transparentTheme = R.style.GlifV3Theme_Light_Transparent;
|
||||
} else if (suwTheme == R.style.GlifV2Theme) {
|
||||
wifiDialogTheme = R.style.GlifV2Theme_Transparent;
|
||||
transparentTheme = R.style.GlifV2Theme_Transparent;
|
||||
} else if (suwTheme == R.style.GlifTheme_Light) {
|
||||
wifiDialogTheme = R.style.SetupWizardTheme_Light_Transparent;
|
||||
transparentTheme = R.style.SetupWizardTheme_Light_Transparent;
|
||||
} else if (suwTheme == R.style.GlifTheme) {
|
||||
wifiDialogTheme = R.style.SetupWizardTheme_Transparent;
|
||||
transparentTheme = R.style.SetupWizardTheme_Transparent;
|
||||
}
|
||||
return wifiDialogTheme;
|
||||
return transparentTheme;
|
||||
}
|
||||
|
||||
public static void copySetupExtras(Intent fromIntent, Intent toIntent) {
|
||||
toIntent.putExtra(WizardManagerHelper.EXTRA_THEME,
|
||||
fromIntent.getStringExtra(WizardManagerHelper.EXTRA_THEME));
|
||||
toIntent.putExtra(WizardManagerHelper.EXTRA_USE_IMMERSIVE_MODE,
|
||||
fromIntent.getBooleanExtra(WizardManagerHelper.EXTRA_USE_IMMERSIVE_MODE, false));
|
||||
WizardManagerHelper.copyWizardManagerExtras(fromIntent, toIntent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
private SwitchPreference mToggleInversionPreference;
|
||||
private ColorInversionPreferenceController mInversionPreferenceController;
|
||||
private AccessibilityHearingAidPreferenceController mHearingAidPreferenceController;
|
||||
private ListPreference mDarkUIModePreference;
|
||||
private Preference mDarkUIModePreference;
|
||||
private DarkUIPreferenceController mDarkUIPreferenceController;
|
||||
private LiveCaptionPreferenceController mLiveCaptionPreferenceController;
|
||||
|
||||
|
||||
@@ -33,13 +33,10 @@ import android.content.res.Resources;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.webkit.IWebViewUpdateService;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.fragment.app.Fragment;
|
||||
@@ -438,10 +435,6 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
if (isFallbackPackage(mAppEntry.info.packageName)) {
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
mButtonsPref.setButton2Enabled(enabled);
|
||||
}
|
||||
|
||||
@@ -466,22 +459,6 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean isFallbackPackage(String packageName) {
|
||||
try {
|
||||
IWebViewUpdateService webviewUpdateService =
|
||||
IWebViewUpdateService.Stub.asInterface(
|
||||
ServiceManager.getService("webviewupdate"));
|
||||
if (webviewUpdateService.isFallbackPackage(packageName)) {
|
||||
return true;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void updateForceStopButton() {
|
||||
if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
|
||||
|
||||
@@ -32,7 +32,6 @@ import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.webkit.IWebViewUpdateService;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
@@ -48,7 +47,6 @@ public class ResetAppsHelper implements DialogInterface.OnClickListener,
|
||||
private final PackageManager mPm;
|
||||
private final IPackageManager mIPm;
|
||||
private final INotificationManager mNm;
|
||||
private final IWebViewUpdateService mWvus;
|
||||
private final NetworkPolicyManager mNpm;
|
||||
private final AppOpsManager mAom;
|
||||
private final Context mContext;
|
||||
@@ -61,7 +59,6 @@ public class ResetAppsHelper implements DialogInterface.OnClickListener,
|
||||
mIPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
|
||||
mNm = INotificationManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
|
||||
mWvus = IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
|
||||
mNpm = NetworkPolicyManager.from(context);
|
||||
mAom = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
|
||||
}
|
||||
@@ -122,8 +119,7 @@ public class ResetAppsHelper implements DialogInterface.OnClickListener,
|
||||
}
|
||||
if (!app.enabled) {
|
||||
if (mPm.getApplicationEnabledSetting(app.packageName)
|
||||
== PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER
|
||||
&& !isNonEnableableFallback(app.packageName)) {
|
||||
== PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
|
||||
mPm.setApplicationEnabledSetting(app.packageName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
|
||||
PackageManager.DONT_KILL_APP);
|
||||
@@ -147,12 +143,4 @@ public class ResetAppsHelper implements DialogInterface.OnClickListener,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isNonEnableableFallback(String packageName) {
|
||||
try {
|
||||
return mWvus.isFallbackPackage(packageName);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,15 @@ package com.android.settings.aware;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
public interface AwareFeatureProvider {
|
||||
/** Returns true if the aware sensor is supported. */
|
||||
boolean isSupported(Context context);
|
||||
|
||||
/** Returns true if the aware feature is enabled. */
|
||||
boolean isEnabled(Context context);
|
||||
|
||||
/** Show information dialog. */
|
||||
void showRestrictionDialog(Fragment parent);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.android.settings.aware;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
public class AwareFeatureProviderImpl implements AwareFeatureProvider {
|
||||
@Override
|
||||
public boolean isSupported(Context context) {
|
||||
@@ -28,4 +30,8 @@ public class AwareFeatureProviderImpl implements AwareFeatureProvider {
|
||||
public boolean isEnabled(Context context) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showRestrictionDialog(Fragment parent) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,9 @@ import com.android.settings.network.MobileNetworkListFragment;
|
||||
import com.android.settings.network.NetworkDashboardFragment;
|
||||
import com.android.settings.nfc.AndroidBeam;
|
||||
import com.android.settings.nfc.PaymentSettings;
|
||||
import com.android.settings.notification.AppBubbleNotificationSettings;
|
||||
import com.android.settings.notification.AppNotificationSettings;
|
||||
import com.android.settings.notification.BubbleNotificationSettings;
|
||||
import com.android.settings.notification.ChannelGroupNotificationSettings;
|
||||
import com.android.settings.notification.ChannelNotificationSettings;
|
||||
import com.android.settings.notification.ConfigureNotificationSettings;
|
||||
@@ -211,6 +213,8 @@ public class SettingsGateway {
|
||||
DreamSettings.class.getName(),
|
||||
UserSettings.class.getName(),
|
||||
NotificationAccessSettings.class.getName(),
|
||||
BubbleNotificationSettings.class.getName(),
|
||||
AppBubbleNotificationSettings.class.getName(),
|
||||
ZenAccessSettings.class.getName(),
|
||||
ZenAccessDetails.class.getName(),
|
||||
ZenModeAutomationSettings.class.getName(),
|
||||
|
||||
@@ -39,4 +39,9 @@ public class DeviceModelPreferenceController extends HardwareInfoPreferenceContr
|
||||
public boolean isSliceable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
return HardwareInfoPreferenceController.getDeviceModel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ import java.util.Objects;
|
||||
public class ActionDisabledByAdminDialogHelper {
|
||||
|
||||
private static final String TAG = ActionDisabledByAdminDialogHelper.class.getName();
|
||||
private EnforcedAdmin mEnforcedAdmin;
|
||||
@VisibleForTesting EnforcedAdmin mEnforcedAdmin;
|
||||
private ViewGroup mDialogView;
|
||||
private String mRestriction = null;
|
||||
private Activity mActivity;
|
||||
@@ -80,20 +80,28 @@ public class ActionDisabledByAdminDialogHelper {
|
||||
EnforcedAdmin enforcedAdmin) {
|
||||
mEnforcedAdmin = enforcedAdmin;
|
||||
mRestriction = restriction;
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
|
||||
mDialogView = (ViewGroup) LayoutInflater.from(builder.getContext()).inflate(
|
||||
R.layout.admin_support_details_dialog, null);
|
||||
initializeDialogViews(mDialogView, mEnforcedAdmin.component, getEnforcementAdminUserId(),
|
||||
mRestriction);
|
||||
return builder
|
||||
.setPositiveButton(R.string.okay, null)
|
||||
.setNeutralButton(R.string.learn_more,
|
||||
(dialog, which) -> {
|
||||
showAdminPolicies(mEnforcedAdmin, mActivity);
|
||||
mActivity.finish();
|
||||
})
|
||||
.setView(mDialogView);
|
||||
builder.setPositiveButton(R.string.okay, null).setView(mDialogView);
|
||||
maybeSetLearnMoreButton(builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void maybeSetLearnMoreButton(AlertDialog.Builder builder) {
|
||||
// The "Learn more" button appears only if the restriction is enforced by an admin in the
|
||||
// same profile group. Otherwise the admin package and its policies are not accessible to
|
||||
// the current user.
|
||||
final UserManager um = UserManager.get(mActivity.getApplicationContext());
|
||||
if (um.isSameProfileGroup(getEnforcementAdminUserId(mEnforcedAdmin), um.getUserHandle())) {
|
||||
builder.setNeutralButton(R.string.learn_more, (dialog, which) -> {
|
||||
showAdminPolicies(mEnforcedAdmin, mActivity);
|
||||
mActivity.finish();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void updateDialog(String restriction, EnforcedAdmin admin) {
|
||||
|
||||
@@ -20,6 +20,8 @@ import android.content.Context;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.Global;
|
||||
import android.text.TextUtils;
|
||||
import com.android.settingslib.fuelgauge.BatterySaverUtils;
|
||||
|
||||
/**
|
||||
* Responds to user actions in the Settings > Battery > Set a Schedule Screen
|
||||
@@ -66,24 +68,34 @@ public class BatterySaverScheduleRadioButtonsController {
|
||||
|
||||
public boolean setDefaultKey(String key) {
|
||||
final ContentResolver resolver = mContext.getContentResolver();
|
||||
switch(key) {
|
||||
case KEY_NO_SCHEDULE:
|
||||
Settings.Global.putInt(resolver, Global.AUTOMATIC_POWER_SAVE_MODE,
|
||||
PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
|
||||
Settings.Global.putInt(resolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
|
||||
break;
|
||||
case KEY_PERCENTAGE:
|
||||
Settings.Global.putInt(resolver, Global.AUTOMATIC_POWER_SAVE_MODE,
|
||||
PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
|
||||
Settings.Global.putInt(resolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 5);
|
||||
break;
|
||||
case KEY_ROUTINE:
|
||||
Settings.Global.putInt(resolver, Global.AUTOMATIC_POWER_SAVE_MODE,
|
||||
PowerManager.POWER_SAVE_MODE_TRIGGER_DYNAMIC);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException(
|
||||
"Not a valid key for " + this.getClass().getSimpleName());
|
||||
|
||||
int mode = PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE;
|
||||
int triggerLevel = 0;
|
||||
if (!TextUtils.equals(key, KEY_NO_SCHEDULE)
|
||||
&& BatterySaverUtils.maybeShowBatterySaverConfirmation(
|
||||
mContext, true /* confirmOnly */)) {
|
||||
return true;
|
||||
} else {
|
||||
switch (key) {
|
||||
case KEY_NO_SCHEDULE:
|
||||
break;
|
||||
case KEY_PERCENTAGE:
|
||||
triggerLevel = 5;
|
||||
break;
|
||||
case KEY_ROUTINE:
|
||||
mode = PowerManager.POWER_SAVE_MODE_TRIGGER_DYNAMIC;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException(
|
||||
"Not a valid key for " + this.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger level is intentionally left alone when going between dynamic and percentage modes
|
||||
// so that a users percentage based schedule is preserved when they toggle between the two.
|
||||
Settings.Global.putInt(resolver, Global.AUTOMATIC_POWER_SAVE_MODE, mode);
|
||||
if (mode != PowerManager.POWER_SAVE_MODE_TRIGGER_DYNAMIC) {
|
||||
Settings.Global.putInt(resolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, triggerLevel);
|
||||
}
|
||||
mSeekBarController.updateSeekBar();
|
||||
return true;
|
||||
|
||||
@@ -71,6 +71,7 @@ public class ContextualCard {
|
||||
private final Drawable mIconDrawable;
|
||||
@LayoutRes
|
||||
private final int mViewType;
|
||||
private final boolean mIsPendingDismiss;
|
||||
|
||||
public String getName() {
|
||||
return mName;
|
||||
@@ -156,6 +157,10 @@ public class ContextualCard {
|
||||
return mViewType;
|
||||
}
|
||||
|
||||
public boolean isPendingDismiss() {
|
||||
return mIsPendingDismiss;
|
||||
}
|
||||
|
||||
public Builder mutate() {
|
||||
return mBuilder;
|
||||
}
|
||||
@@ -181,6 +186,7 @@ public class ContextualCard {
|
||||
mIconDrawable = builder.mIconDrawable;
|
||||
mIsLargeCard = builder.mIsLargeCard;
|
||||
mViewType = builder.mViewType;
|
||||
mIsPendingDismiss = builder.mIsPendingDismiss;
|
||||
}
|
||||
|
||||
ContextualCard(Cursor c) {
|
||||
@@ -226,6 +232,8 @@ public class ContextualCard {
|
||||
mBuilder.setIconDrawable(mIconDrawable);
|
||||
mViewType = getViewTypeByCardType(mCardType);
|
||||
mBuilder.setViewType(mViewType);
|
||||
mIsPendingDismiss = false;
|
||||
mBuilder.setIsPendingDismiss(mIsPendingDismiss);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -277,6 +285,7 @@ public class ContextualCard {
|
||||
private boolean mIsLargeCard;
|
||||
@LayoutRes
|
||||
private int mViewType;
|
||||
private boolean mIsPendingDismiss;
|
||||
|
||||
public Builder setName(String name) {
|
||||
mName = name;
|
||||
@@ -373,6 +382,11 @@ public class ContextualCard {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setIsPendingDismiss(boolean isPendingDismiss) {
|
||||
mIsPendingDismiss = isPendingDismiss;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ContextualCard build() {
|
||||
return new ContextualCard(this);
|
||||
}
|
||||
|
||||
@@ -32,5 +32,5 @@ public interface ContextualCardFeatureProvider {
|
||||
List<ContextualCard> hiddenCards);
|
||||
|
||||
/** When user clicks toggle/title area of a contextual card. */
|
||||
void logContextualCardClick(ContextualCard card, int row, int tapTarget);
|
||||
void logContextualCardClick(ContextualCard card, int sliceRow, int tapTarget, int uiPosition);
|
||||
}
|
||||
|
||||
@@ -63,6 +63,9 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP
|
||||
// contextual card tap target
|
||||
private static final String EXTRA_CONTEXTUALCARD_TAP_TARGET = "target";
|
||||
|
||||
// contextual card ui position
|
||||
private static final String EXTRA_CONTEXTUALCARD_UI_POSTITION = "ui_position";
|
||||
|
||||
// contextual homepage display latency
|
||||
private static final String EXTRA_LATENCY = "latency";
|
||||
|
||||
@@ -122,7 +125,7 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP
|
||||
|
||||
@Override
|
||||
public void logContextualCardClick(ContextualCard card, int row,
|
||||
int actionType) {
|
||||
int actionType, int uiPosition) {
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(EXTRA_CONTEXTUALCARD_ACTION_TYPE, CONTEXTUAL_CARD_CLICK);
|
||||
intent.putExtra(EXTRA_CONTEXTUALCARD_NAME, card.getName());
|
||||
@@ -130,6 +133,7 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP
|
||||
intent.putExtra(EXTRA_CONTEXTUALCARD_SCORE, card.getRankingScore());
|
||||
intent.putExtra(EXTRA_CONTEXTUALCARD_ROW, row);
|
||||
intent.putExtra(EXTRA_CONTEXTUALCARD_TAP_TARGET, actionTypeToTapTarget(actionType));
|
||||
intent.putExtra(EXTRA_CONTEXTUALCARD_UI_POSTITION, uiPosition);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardRenderer;
|
||||
import com.android.settings.homepage.contextualcards.slices.SwipeDismissalDelegate.DismissalItemTouchHelperListener;
|
||||
import com.android.settings.homepage.contextualcards.slices.SwipeDismissalDelegate;
|
||||
import com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -36,7 +36,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ContextualCardsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
||||
implements ContextualCardUpdateListener, DismissalItemTouchHelperListener {
|
||||
implements ContextualCardUpdateListener, SwipeDismissalDelegate.Listener {
|
||||
static final int SPAN_COUNT = 2;
|
||||
|
||||
private static final String TAG = "ContextualCardsAdapter";
|
||||
@@ -140,6 +140,9 @@ public class ContextualCardsAdapter extends RecyclerView.Adapter<RecyclerView.Vi
|
||||
|
||||
@Override
|
||||
public void onSwiped(int position) {
|
||||
|
||||
final ContextualCard card = mContextualCards.get(position).mutate()
|
||||
.setIsPendingDismiss(true).build();
|
||||
mContextualCards.set(position, card);
|
||||
notifyItemChanged(position);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,15 +176,10 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
.setSubtitle(getSubTitle(mPackageName, mUid))
|
||||
.setPrimaryAction(getPrimarySliceAction(icon, title, getIntent())));
|
||||
|
||||
// Get rows by notification channel.
|
||||
// Add notification channel rows.
|
||||
final List<ListBuilder.RowBuilder> rows = getNotificationChannelRows(packageInfo, icon);
|
||||
|
||||
// Get displayable notification channel count.
|
||||
final int channelCount = Math.min(rows.size(), DEFAULT_EXPANDED_ROW_COUNT);
|
||||
|
||||
// According to the displayable channel count to add rows.
|
||||
for (int i = 0; i < channelCount; i++) {
|
||||
listBuilder.addRow(rows.get(i));
|
||||
for (ListBuilder.RowBuilder rowBuilder : rows) {
|
||||
listBuilder.addRow(rowBuilder);
|
||||
}
|
||||
|
||||
return listBuilder.build();
|
||||
@@ -279,10 +274,9 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
private List<ListBuilder.RowBuilder> getNotificationChannelRows(PackageInfo packageInfo,
|
||||
IconCompat icon) {
|
||||
final List<ListBuilder.RowBuilder> notificationChannelRows = new ArrayList<>();
|
||||
final List<NotificationChannel> enabledChannels = getEnabledChannels(mPackageName, mUid,
|
||||
mAppRow);
|
||||
final List<NotificationChannel> displayableChannels = getDisplayableChannels(mAppRow);
|
||||
|
||||
for (NotificationChannel channel : enabledChannels) {
|
||||
for (NotificationChannel channel : displayableChannels) {
|
||||
notificationChannelRows.add(new ListBuilder.RowBuilder()
|
||||
.setTitle(channel.getName())
|
||||
.setSubtitle(NotificationBackend.getSentSummary(
|
||||
@@ -356,10 +350,9 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
title);
|
||||
}
|
||||
|
||||
private List<NotificationChannel> getEnabledChannels(String packageName, int uid,
|
||||
NotificationBackend.AppRow appRow) {
|
||||
private List<NotificationChannel> getDisplayableChannels(NotificationBackend.AppRow appRow) {
|
||||
final List<NotificationChannelGroup> channelGroupList =
|
||||
mNotificationBackend.getGroups(packageName, uid).getList();
|
||||
mNotificationBackend.getGroups(appRow.pkg, appRow.uid).getList();
|
||||
final List<NotificationChannel> channels = channelGroupList.stream()
|
||||
.flatMap(group -> group.getChannels().stream().filter(
|
||||
channel -> isChannelEnabled(group, channel, appRow)))
|
||||
@@ -376,8 +369,11 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
}
|
||||
|
||||
// Sort the notification channels with notification sent count by descending.
|
||||
return channelStates.stream().sorted(CHANNEL_STATE_COMPARATOR).map(
|
||||
state -> state.getNotificationChannel()).collect(Collectors.toList());
|
||||
return channelStates.stream()
|
||||
.sorted(CHANNEL_STATE_COMPARATOR)
|
||||
.map(state -> state.getNotificationChannel())
|
||||
.limit(DEFAULT_EXPANDED_ROW_COUNT)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private PackageInfo getMaxSentNotificationsPackage(List<PackageInfo> packageInfoList) {
|
||||
@@ -391,10 +387,14 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
for (PackageInfo packageInfo : packageInfoList) {
|
||||
final NotificationBackend.AppRow appRow = mNotificationBackend.loadAppRow(mContext,
|
||||
mContext.getPackageManager(), packageInfo);
|
||||
// Ignore packages which are banned notifications or block all displayable channels.
|
||||
if (appRow.banned || isAllChannelsBlocked(getDisplayableChannels(appRow))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get sent notification count from app.
|
||||
final int sentCount = appRow.sentByApp.sentCount;
|
||||
if (!appRow.banned && sentCount >= MIN_NOTIFICATION_SENT_COUNT
|
||||
&& sentCount > maxSentCount) {
|
||||
if (sentCount >= MIN_NOTIFICATION_SENT_COUNT && sentCount > maxSentCount) {
|
||||
maxSentCount = sentCount;
|
||||
maxSentCountPackage = packageInfo;
|
||||
mAppRow = appRow;
|
||||
@@ -404,6 +404,15 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
return maxSentCountPackage;
|
||||
}
|
||||
|
||||
private boolean isAllChannelsBlocked(List<NotificationChannel> channels) {
|
||||
for (NotificationChannel channel : channels) {
|
||||
if (channel.getImportance() != IMPORTANCE_NONE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected CharSequence getSubTitle(String packageName, int uid) {
|
||||
final int channelCount = mNotificationBackend.getChannelCount(packageName, uid);
|
||||
|
||||
|
||||
@@ -64,7 +64,6 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, Life
|
||||
private final Context mContext;
|
||||
private final LifecycleOwner mLifecycleOwner;
|
||||
private final ControllerRendererPool mControllerRendererPool;
|
||||
private final Set<ContextualCard> mCardSet;
|
||||
private final SliceDeferredSetupCardRendererHelper mDeferredSetupCardHelper;
|
||||
private final SliceFullCardRendererHelper mFullCardHelper;
|
||||
private final SliceHalfCardRendererHelper mHalfCardHelper;
|
||||
@@ -75,7 +74,6 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, Life
|
||||
mLifecycleOwner = lifecycleOwner;
|
||||
mSliceLiveDataMap = new ArrayMap<>();
|
||||
mControllerRendererPool = controllerRendererPool;
|
||||
mCardSet = new ArraySet<>();
|
||||
mFlippedCardSet = new ArraySet<>();
|
||||
mLifecycleOwner.getLifecycle().addObserver(this);
|
||||
mFullCardHelper = new SliceFullCardRendererHelper(context);
|
||||
@@ -110,7 +108,6 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, Life
|
||||
sliceLiveData = SliceLiveData.fromUri(mContext, uri);
|
||||
mSliceLiveDataMap.put(uri, sliceLiveData);
|
||||
}
|
||||
mCardSet.add(card);
|
||||
|
||||
sliceLiveData.removeObservers(mLifecycleOwner);
|
||||
sliceLiveData.observe(mLifecycleOwner, slice -> {
|
||||
@@ -129,7 +126,7 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, Life
|
||||
mHalfCardHelper.bindView(holder, card, slice);
|
||||
break;
|
||||
default:
|
||||
mFullCardHelper.bindView(holder, card, slice, mCardSet);
|
||||
mFullCardHelper.bindView(holder, card, slice);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -138,23 +135,19 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, Life
|
||||
// Deferred setup is never dismissible.
|
||||
break;
|
||||
case VIEW_TYPE_HALF_WIDTH:
|
||||
initDismissalActions(holder, card, R.id.content);
|
||||
initDismissalActions(holder, card);
|
||||
break;
|
||||
default:
|
||||
initDismissalActions(holder, card, R.id.slice_view);
|
||||
initDismissalActions(holder, card);
|
||||
}
|
||||
|
||||
if (card.isPendingDismiss()) {
|
||||
flipCardToDismissalView(holder);
|
||||
mFlippedCardSet.add(holder);
|
||||
}
|
||||
}
|
||||
|
||||
private void initDismissalActions(RecyclerView.ViewHolder holder, ContextualCard card,
|
||||
int initialViewId) {
|
||||
// initialView is the first view in the ViewFlipper.
|
||||
final View initialView = holder.itemView.findViewById(initialViewId);
|
||||
initialView.setOnLongClickListener(v -> {
|
||||
flipCardToDismissalView(holder);
|
||||
mFlippedCardSet.add(holder);
|
||||
return true;
|
||||
});
|
||||
|
||||
private void initDismissalActions(RecyclerView.ViewHolder holder, ContextualCard card) {
|
||||
final Button btnKeep = holder.itemView.findViewById(R.id.keep);
|
||||
btnKeep.setOnClickListener(v -> {
|
||||
mFlippedCardSet.remove(holder);
|
||||
|
||||
@@ -68,7 +68,7 @@ class SliceDeferredSetupCardRendererHelper {
|
||||
final ContextualCardFeatureProvider contextualCardFeatureProvider =
|
||||
FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(mContext);
|
||||
contextualCardFeatureProvider.logContextualCardClick(card, 0 /* row */,
|
||||
EventInfo.ACTION_TYPE_CONTENT);
|
||||
EventInfo.ACTION_TYPE_CONTENT, view.getAdapterPosition());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.settings.homepage.contextualcards.slices;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -36,13 +37,11 @@ import java.util.Set;
|
||||
/**
|
||||
* Card renderer helper for {@link ContextualCard} built as slice full card.
|
||||
*/
|
||||
class SliceFullCardRendererHelper implements SliceView.OnSliceActionListener {
|
||||
class SliceFullCardRendererHelper {
|
||||
private static final String TAG = "SliceFCRendererHelper";
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
private Set<ContextualCard> mCardSet;
|
||||
|
||||
SliceFullCardRendererHelper(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
@@ -51,17 +50,22 @@ class SliceFullCardRendererHelper implements SliceView.OnSliceActionListener {
|
||||
return new SliceViewHolder(view);
|
||||
}
|
||||
|
||||
void bindView(RecyclerView.ViewHolder holder, ContextualCard card, Slice slice,
|
||||
Set<ContextualCard> cardSet) {
|
||||
void bindView(RecyclerView.ViewHolder holder, ContextualCard card, Slice slice) {
|
||||
final SliceViewHolder cardHolder = (SliceViewHolder) holder;
|
||||
cardHolder.sliceView.setScrollable(false);
|
||||
cardHolder.sliceView.setTag(card.getSliceUri());
|
||||
//TODO(b/114009676): We will soon have a field to decide what slice mode we should set.
|
||||
cardHolder.sliceView.setMode(SliceView.MODE_LARGE);
|
||||
cardHolder.sliceView.setSlice(slice);
|
||||
mCardSet = cardSet;
|
||||
// Set this listener so we can log the interaction users make on the slice
|
||||
cardHolder.sliceView.setOnSliceActionListener(this);
|
||||
cardHolder.sliceView.setOnSliceActionListener(
|
||||
(eventInfo, sliceItem) -> {
|
||||
final ContextualCardFeatureProvider contextualCardFeatureProvider =
|
||||
FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(
|
||||
mContext);
|
||||
contextualCardFeatureProvider.logContextualCardClick(card, eventInfo.rowIndex,
|
||||
eventInfo.actionType, cardHolder.getAdapterPosition());
|
||||
});
|
||||
|
||||
// Customize slice view for Settings
|
||||
cardHolder.sliceView.showTitleItems(true);
|
||||
@@ -71,23 +75,6 @@ class SliceFullCardRendererHelper implements SliceView.OnSliceActionListener {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSliceAction(@NonNull EventInfo eventInfo, @NonNull SliceItem sliceItem) {
|
||||
// sliceItem.getSlice().getUri() is like
|
||||
// content://android.settings.slices/action/wifi/_gen/0/_gen/0
|
||||
// contextualCard.getSliceUri() is prefix of sliceItem.getSlice().getUri()
|
||||
final ContextualCardFeatureProvider contextualCardFeatureProvider =
|
||||
FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(mContext);
|
||||
for (ContextualCard card : mCardSet) {
|
||||
if (sliceItem.getSlice().getUri().toString().startsWith(
|
||||
card.getSliceUri().toString())) {
|
||||
contextualCardFeatureProvider.logContextualCardClick(card, eventInfo.rowIndex,
|
||||
eventInfo.actionType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class SliceViewHolder extends RecyclerView.ViewHolder {
|
||||
public final SliceView sliceView;
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ class SliceHalfCardRendererHelper {
|
||||
final ContextualCardFeatureProvider contextualCardFeatureProvider =
|
||||
FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(mContext);
|
||||
contextualCardFeatureProvider.logContextualCardClick(card, 0 /* row */,
|
||||
EventInfo.ACTION_TYPE_CONTENT);
|
||||
EventInfo.ACTION_TYPE_CONTENT, view.getAdapterPosition());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -18,31 +18,74 @@ package com.android.settings.homepage.contextualcards.slices;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import android.widget.ViewFlipper;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.homepage.contextualcards.ContextualCard;
|
||||
|
||||
public class SwipeDismissalDelegate extends ItemTouchHelper.Callback {
|
||||
|
||||
private static final String TAG = "DismissItemTouchHelper";
|
||||
private static final String TAG = "SwipeDismissalDelegate";
|
||||
|
||||
public interface DismissalItemTouchHelperListener {
|
||||
public interface Listener {
|
||||
void onSwiped(int position);
|
||||
}
|
||||
|
||||
private final Context mContext;
|
||||
private final DismissalItemTouchHelperListener mListener;
|
||||
private final SwipeDismissalDelegate.Listener mListener;
|
||||
private final Drawable mIconDelete;
|
||||
private final Paint mBgPaint;
|
||||
private final int mBgCornerRadius;
|
||||
|
||||
public SwipeDismissalDelegate(Context context, DismissalItemTouchHelperListener listener) {
|
||||
public SwipeDismissalDelegate(Context context, SwipeDismissalDelegate.Listener listener) {
|
||||
mContext = context;
|
||||
mListener = listener;
|
||||
mIconDelete = mContext.getDrawable(R.drawable.ic_delete);
|
||||
mBgPaint = new Paint();
|
||||
mBgPaint.setColor(mContext.getColor(R.color.homepage_card_dismissal_background));
|
||||
mBgCornerRadius = mContext.getResources()
|
||||
.getDimensionPixelSize(R.dimen.homepage_card_corner_radius);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the ability to drag or swipe should be enabled or not.
|
||||
*
|
||||
* Only allow swipe on {@link ContextualCard} built with view type
|
||||
* {@link SliceContextualCardRenderer#VIEW_TYPE_FULL_WIDTH} or
|
||||
* {@link SliceContextualCardRenderer#VIEW_TYPE_HALF_WIDTH}.
|
||||
*
|
||||
* When the dismissal view is displayed, the swipe will also be disabled.
|
||||
*/
|
||||
@Override
|
||||
public int getMovementFlags(@NonNull RecyclerView recyclerView,
|
||||
@NonNull RecyclerView.ViewHolder viewHolder) {
|
||||
return 0;
|
||||
switch (viewHolder.getItemViewType()) {
|
||||
case SliceContextualCardRenderer.VIEW_TYPE_FULL_WIDTH:
|
||||
case SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH:
|
||||
//TODO(b/129438972): Convert this to a regular view.
|
||||
final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.view_flipper);
|
||||
|
||||
// As we are using ViewFlipper to switch between the initial view and
|
||||
// dismissal view, here we are making sure the current displayed view is the
|
||||
// initial view of either slice full card or half card, and only allow swipe on
|
||||
// these two types.
|
||||
if (viewFlipper.getCurrentView().getId() != getInitialViewId(viewHolder)) {
|
||||
// Disable swiping when we are in the dismissal view
|
||||
return 0;
|
||||
}
|
||||
return makeMovementFlags(0 /*dragFlags*/,
|
||||
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT /*swipeFlags*/);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,5 +105,36 @@ public class SwipeDismissalDelegate extends ItemTouchHelper.Callback {
|
||||
@NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState,
|
||||
boolean isCurrentlyActive) {
|
||||
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
|
||||
|
||||
final View itemView = viewHolder.itemView;
|
||||
final int iconMargin = mContext.getResources()
|
||||
.getDimensionPixelSize(R.dimen.homepage_card_dismissal_side_margin);
|
||||
final int iconTop =
|
||||
itemView.getTop() + (itemView.getHeight() - mIconDelete.getIntrinsicHeight()) / 2;
|
||||
final int iconBottom = iconTop + mIconDelete.getIntrinsicHeight();
|
||||
|
||||
if (dX > 0) { //swipe to the right
|
||||
final int iconLeft = itemView.getLeft() + iconMargin;
|
||||
final int iconRight = iconLeft + mIconDelete.getIntrinsicWidth();
|
||||
final RectF rect = new RectF(itemView.getLeft(), itemView.getTop(),
|
||||
itemView.getLeft() + ((int) dX) + mBgCornerRadius, itemView.getBottom());
|
||||
mIconDelete.setBounds(iconLeft, iconTop, iconRight, iconBottom);
|
||||
c.drawRoundRect(rect, mBgCornerRadius, mBgCornerRadius, mBgPaint);
|
||||
} else if (dX < 0) {
|
||||
final int iconRight = itemView.getRight() - iconMargin;
|
||||
final int iconLeft = iconRight - mIconDelete.getIntrinsicWidth();
|
||||
final RectF rect = new RectF(itemView.getRight() + ((int) dX), itemView.getTop(),
|
||||
itemView.getRight(), itemView.getBottom());
|
||||
mIconDelete.setBounds(iconLeft, iconTop, iconRight, iconBottom);
|
||||
c.drawRoundRect(rect, mBgCornerRadius, mBgCornerRadius, mBgPaint);
|
||||
}
|
||||
mIconDelete.draw(c);
|
||||
}
|
||||
|
||||
private int getInitialViewId(RecyclerView.ViewHolder viewHolder) {
|
||||
if (viewHolder.getItemViewType() == SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH) {
|
||||
return R.id.content;
|
||||
}
|
||||
return R.id.slice_view;
|
||||
}
|
||||
}
|
||||
@@ -20,35 +20,51 @@ import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_INDIC
|
||||
|
||||
import android.annotation.ColorInt;
|
||||
import android.app.PendingIntent;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.builders.ListBuilder;
|
||||
import androidx.slice.builders.SliceAction;
|
||||
|
||||
import com.android.internal.util.CollectionUtils;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.slices.CustomSliceable;
|
||||
import com.android.settings.slices.SliceBackgroundWorker;
|
||||
import com.android.settingslib.bluetooth.A2dpProfile;
|
||||
import com.android.settingslib.bluetooth.HearingAidProfile;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||
import com.android.settingslib.media.MediaOutputSliceConstants;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MediaOutputIndicatorSlice implements CustomSliceable {
|
||||
|
||||
private static final String TAG = "MediaOutputIndicatorSlice";
|
||||
|
||||
private Context mContext;
|
||||
@VisibleForTesting
|
||||
MediaOutputIndicatorWorker mWorker;
|
||||
private LocalBluetoothManager mLocalBluetoothManager;
|
||||
private LocalBluetoothProfileManager mProfileManager;
|
||||
|
||||
public MediaOutputIndicatorSlice(Context context) {
|
||||
mContext = context;
|
||||
mLocalBluetoothManager = com.android.settings.bluetooth.Utils.getLocalBtManager(context);
|
||||
if (mLocalBluetoothManager == null) {
|
||||
Log.e(TAG, "Bluetooth is not supported on this device");
|
||||
return;
|
||||
}
|
||||
mProfileManager = mLocalBluetoothManager.getProfileManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice getSlice() {
|
||||
if (!getWorker().isVisible()) {
|
||||
if (!isVisible()) {
|
||||
return null;
|
||||
}
|
||||
final IconCompat icon = IconCompat.createWithResource(mContext,
|
||||
@@ -66,18 +82,11 @@ public class MediaOutputIndicatorSlice implements CustomSliceable {
|
||||
.setAccentColor(color)
|
||||
.addRow(new ListBuilder.RowBuilder()
|
||||
.setTitle(title)
|
||||
.setSubtitle(getWorker().findActiveDeviceName())
|
||||
.setSubtitle(findActiveDeviceName())
|
||||
.setPrimaryAction(primarySliceAction));
|
||||
return listBuilder.build();
|
||||
}
|
||||
|
||||
private MediaOutputIndicatorWorker getWorker() {
|
||||
if (mWorker == null) {
|
||||
mWorker = (MediaOutputIndicatorWorker) SliceBackgroundWorker.getInstance(getUri());
|
||||
}
|
||||
return mWorker;
|
||||
}
|
||||
|
||||
private Intent getMediaOutputSliceIntent() {
|
||||
final Intent intent = new Intent()
|
||||
.setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
|
||||
@@ -101,4 +110,65 @@ public class MediaOutputIndicatorSlice implements CustomSliceable {
|
||||
public Class getBackgroundWorkerClass() {
|
||||
return MediaOutputIndicatorWorker.class;
|
||||
}
|
||||
|
||||
private boolean isVisible() {
|
||||
// To decide Slice's visibility.
|
||||
// return true if device is connected or previously connected, false for other cases.
|
||||
return !CollectionUtils.isEmpty(getConnectableA2dpDevices())
|
||||
|| !CollectionUtils.isEmpty(getConnectableHearingAidDevices());
|
||||
}
|
||||
|
||||
private List<BluetoothDevice> getConnectableA2dpDevices() {
|
||||
// Get A2dp devices on all states
|
||||
// (STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED, STATE_DISCONNECTING)
|
||||
final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
|
||||
if (a2dpProfile == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return a2dpProfile.getConnectableDevices();
|
||||
}
|
||||
|
||||
private List<BluetoothDevice> getConnectableHearingAidDevices() {
|
||||
// Get hearing aid profile devices on all states
|
||||
// (STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED, STATE_DISCONNECTING)
|
||||
final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
|
||||
if (hapProfile == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
return hapProfile.getConnectableDevices();
|
||||
}
|
||||
|
||||
private CharSequence findActiveDeviceName() {
|
||||
// Return Hearing Aid device name if it is active
|
||||
BluetoothDevice activeDevice = findActiveHearingAidDevice();
|
||||
if (activeDevice != null) {
|
||||
return activeDevice.getAliasName();
|
||||
}
|
||||
// Return A2DP device name if it is active
|
||||
final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
|
||||
if (a2dpProfile != null) {
|
||||
activeDevice = a2dpProfile.getActiveDevice();
|
||||
if (activeDevice != null) {
|
||||
return activeDevice.getAliasName();
|
||||
}
|
||||
}
|
||||
// No active device, return default summary
|
||||
return mContext.getText(R.string.media_output_default_summary);
|
||||
}
|
||||
|
||||
private BluetoothDevice findActiveHearingAidDevice() {
|
||||
final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
|
||||
if (hearingAidProfile == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final List<BluetoothDevice> activeDevices = hearingAidProfile.getActiveDevices();
|
||||
for (BluetoothDevice btDevice : activeDevices) {
|
||||
if (btDevice != null) {
|
||||
return btDevice;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,26 +16,18 @@
|
||||
|
||||
package com.android.settings.media;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.CollectionUtils;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.bluetooth.Utils;
|
||||
import com.android.settings.slices.SliceBackgroundWorker;
|
||||
import com.android.settingslib.bluetooth.A2dpProfile;
|
||||
import com.android.settingslib.bluetooth.BluetoothCallback;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.HearingAidProfile;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Listener for background change from {@code BluetoothCallback} to update media output indicator.
|
||||
@@ -45,7 +37,6 @@ public class MediaOutputIndicatorWorker extends SliceBackgroundWorker implements
|
||||
private static final String TAG = "MediaOutputIndicatorWorker";
|
||||
|
||||
private LocalBluetoothManager mLocalBluetoothManager;
|
||||
private LocalBluetoothProfileManager mProfileManager;
|
||||
|
||||
public MediaOutputIndicatorWorker(Context context, Uri uri) {
|
||||
super(context, uri);
|
||||
@@ -53,12 +44,11 @@ public class MediaOutputIndicatorWorker extends SliceBackgroundWorker implements
|
||||
|
||||
@Override
|
||||
protected void onSlicePinned() {
|
||||
LocalBluetoothManager mLocalBluetoothManager = Utils.getLocalBtManager(getContext());
|
||||
mLocalBluetoothManager = Utils.getLocalBtManager(getContext());
|
||||
if (mLocalBluetoothManager == null) {
|
||||
Log.e(TAG, "Bluetooth is not supported on this device");
|
||||
return;
|
||||
}
|
||||
mProfileManager = mLocalBluetoothManager.getProfileManager();
|
||||
mLocalBluetoothManager.getEventManager().registerCallback(this);
|
||||
}
|
||||
|
||||
@@ -74,7 +64,6 @@ public class MediaOutputIndicatorWorker extends SliceBackgroundWorker implements
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
mLocalBluetoothManager = null;
|
||||
mProfileManager = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -89,73 +78,4 @@ public class MediaOutputIndicatorWorker extends SliceBackgroundWorker implements
|
||||
notifySliceChange();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To decide Slice's visibility.
|
||||
*
|
||||
* @return true if device is connected or previously connected, false for other cases.
|
||||
*/
|
||||
public boolean isVisible() {
|
||||
return !CollectionUtils.isEmpty(getConnectableA2dpDevices())
|
||||
|| !CollectionUtils.isEmpty(getConnectableHearingAidDevices());
|
||||
}
|
||||
|
||||
private List<BluetoothDevice> getConnectableA2dpDevices() {
|
||||
// get A2dp devices on all states
|
||||
// (STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED, STATE_DISCONNECTING)
|
||||
final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
|
||||
if (a2dpProfile == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return a2dpProfile.getConnectableDevices();
|
||||
}
|
||||
|
||||
private List<BluetoothDevice> getConnectableHearingAidDevices() {
|
||||
// get hearing aid profile devices on all states
|
||||
// (STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED, STATE_DISCONNECTING)
|
||||
final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
|
||||
if (hapProfile == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
return hapProfile.getConnectableDevices();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get active devices name.
|
||||
*
|
||||
* @return active Bluetooth device alias, or default summary if no active device.
|
||||
*/
|
||||
public CharSequence findActiveDeviceName() {
|
||||
// Return Hearing Aid device name if it is active
|
||||
BluetoothDevice activeDevice = findActiveHearingAidDevice();
|
||||
if (activeDevice != null) {
|
||||
return activeDevice.getAliasName();
|
||||
}
|
||||
// Return A2DP device name if it is active
|
||||
final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
|
||||
if (a2dpProfile != null) {
|
||||
activeDevice = a2dpProfile.getActiveDevice();
|
||||
if (activeDevice != null) {
|
||||
return activeDevice.getAliasName();
|
||||
}
|
||||
}
|
||||
// No active device, return default summary
|
||||
return getContext().getText(R.string.media_output_default_summary);
|
||||
}
|
||||
|
||||
private BluetoothDevice findActiveHearingAidDevice() {
|
||||
final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
|
||||
if (hearingAidProfile == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final List<BluetoothDevice> activeDevices = hearingAidProfile.getActiveDevices();
|
||||
for (BluetoothDevice btDevice : activeDevices) {
|
||||
if (btDevice != null) {
|
||||
return btDevice;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.notification;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@SearchIndexable
|
||||
public class AppBubbleNotificationSettings extends NotificationSettingsBase {
|
||||
private static final String TAG = "AppBubNotiSettings";
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.APP_BUBBLE_SETTINGS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.app_bubble_notification_settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
|
||||
mControllers = getPreferenceControllers(context, this);
|
||||
return new ArrayList<>(mControllers);
|
||||
}
|
||||
|
||||
protected static List<NotificationPreferenceController> getPreferenceControllers(
|
||||
Context context, AppBubbleNotificationSettings fragment) {
|
||||
List<NotificationPreferenceController> controllers = new ArrayList<>();
|
||||
controllers.add(new HeaderPreferenceController(context, fragment));
|
||||
controllers.add(new BubblePreferenceController(context, new NotificationBackend()));
|
||||
return controllers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null) {
|
||||
Log.w(TAG, "Missing package or uid or packageinfo");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
for (NotificationPreferenceController controller : mControllers) {
|
||||
controller.onResume(mAppRow, mChannel, mChannelGroup, mSuspendedAppsAdmin);
|
||||
controller.displayPreference(getPreferenceScreen());
|
||||
}
|
||||
updatePreferenceStates();
|
||||
}
|
||||
|
||||
/**
|
||||
* For Search.
|
||||
*/
|
||||
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider() {
|
||||
@Override
|
||||
public List<SearchIndexableResource> getXmlResourcesToIndex(
|
||||
Context context, boolean enabled) {
|
||||
final SearchIndexableResource sir = new SearchIndexableResource(context);
|
||||
sir.xmlResId = R.xml.app_bubble_notification_settings;
|
||||
return Arrays.asList(sir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AbstractPreferenceController> createPreferenceControllers(Context
|
||||
context) {
|
||||
return new ArrayList<>(AppBubbleNotificationSettings.getPreferenceControllers(
|
||||
context, null));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -152,7 +152,7 @@ public class AppNotificationSettings extends NotificationSettingsBase {
|
||||
mControllers.add(new DescriptionPreferenceController(context));
|
||||
mControllers.add(new NotificationsOffPreferenceController(context));
|
||||
mControllers.add(new DeletedChannelsPreferenceController(context, mBackend));
|
||||
mControllers.add(new BubblePreferenceController(context, mBackend));
|
||||
mControllers.add(new BubbleSummaryPreferenceController(context, mBackend));
|
||||
return new ArrayList<>(mControllers);
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ public class BubbleNotificationPreferenceController extends TogglePreferenceCont
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
Preference preference = screen.findPreference(NOTIFICATION_BUBBLES);
|
||||
Preference preference = screen.findPreference(getPreferenceKey());
|
||||
if (preference != null) {
|
||||
mSettingObserver = new SettingObserver(preference);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.notification;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.provider.SearchIndexableResource;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.OnActivityResultListener;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@SearchIndexable
|
||||
public class BubbleNotificationSettings extends DashboardFragment implements
|
||||
OnActivityResultListener {
|
||||
private static final String TAG = "BubbleNotiSettings";
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.BUBBLE_SETTINGS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.bubble_notification_settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* For Search.
|
||||
*/
|
||||
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider() {
|
||||
@Override
|
||||
public List<SearchIndexableResource> getXmlResourcesToIndex(
|
||||
Context context, boolean enabled) {
|
||||
final SearchIndexableResource sir = new SearchIndexableResource(context);
|
||||
sir.xmlResId = R.xml.bubble_notification_settings;
|
||||
return Arrays.asList(sir);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settingslib.RestrictedSwitchPreference;
|
||||
|
||||
@@ -74,6 +75,8 @@ public class BubblePreferenceController extends NotificationPreferenceController
|
||||
pref.setEnabled(isChannelConfigurable() && !pref.isDisabledByAdmin());
|
||||
} else {
|
||||
pref.setChecked(mAppRow.allowBubbles);
|
||||
pref.setSummary(mContext.getString(
|
||||
R.string.bubbles_app_toggle_summary, mAppRow.label));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.notification;
|
||||
|
||||
import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
public class BubbleSummaryNotificationPreferenceController extends BasePreferenceController {
|
||||
|
||||
@VisibleForTesting
|
||||
static final int ON = 1;
|
||||
|
||||
public BubbleSummaryNotificationPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
return mContext.getString(
|
||||
areBubblesEnabled() ? R.string.switch_on_text : R.string.switch_off_text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
private boolean areBubblesEnabled() {
|
||||
return Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
NOTIFICATION_BUBBLES, ON) == ON;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.notification;
|
||||
|
||||
import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.applications.AppInfoBase;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
public class BubbleSummaryPreferenceController extends NotificationPreferenceController {
|
||||
|
||||
private static final String KEY = "bubble_link_pref";
|
||||
private static final int SYSTEM_WIDE_ON = 1;
|
||||
private static final int SYSTEM_WIDE_OFF = 0;
|
||||
|
||||
public BubbleSummaryPreferenceController(Context context, NotificationBackend backend) {
|
||||
super(context, backend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreferenceKey() {
|
||||
return KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
if (!super.isAvailable()) {
|
||||
return false;
|
||||
}
|
||||
if (mAppRow == null && mChannel == null) {
|
||||
return false;
|
||||
}
|
||||
if (Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON) == SYSTEM_WIDE_OFF) {
|
||||
return false;
|
||||
}
|
||||
if (mChannel != null) {
|
||||
if (isDefaultChannel()) {
|
||||
return true;
|
||||
} else {
|
||||
return mAppRow == null ? false : mAppRow.allowBubbles;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
super.updateState(preference);
|
||||
|
||||
if (mAppRow != null) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(AppInfoBase.ARG_PACKAGE_NAME, mAppRow.pkg);
|
||||
args.putInt(AppInfoBase.ARG_PACKAGE_UID, mAppRow.uid);
|
||||
|
||||
preference.setIntent(new SubSettingLauncher(mContext)
|
||||
.setDestination(AppBubbleNotificationSettings.class.getName())
|
||||
.setArguments(args)
|
||||
.setSourceMetricsCategory(
|
||||
SettingsEnums.NOTIFICATION_APP_NOTIFICATION)
|
||||
.toIntent());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
boolean canBubble = false;
|
||||
if (mAppRow != null) {
|
||||
if (mChannel != null) {
|
||||
canBubble |= mChannel.canBubble();
|
||||
} else {
|
||||
canBubble |= mAppRow.allowBubbles;
|
||||
}
|
||||
}
|
||||
return mContext.getString(canBubble ? R.string.switch_on_text : R.string.switch_off_text);
|
||||
}
|
||||
}
|
||||
@@ -126,6 +126,11 @@ public abstract class NotificationPreferenceController extends AbstractPreferenc
|
||||
return mChannel.getImportance() == IMPORTANCE_NONE;
|
||||
}
|
||||
|
||||
if (mChannel.isImportanceLockedByOEM()
|
||||
|| mChannel.isImportanceLockedByCriticalDeviceFunction()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mChannel.isBlockableSystem() || !mAppRow.systemApp
|
||||
|| mChannel.getImportance() == IMPORTANCE_NONE;
|
||||
}
|
||||
|
||||
@@ -16,10 +16,14 @@
|
||||
|
||||
package com.android.settings.notification;
|
||||
|
||||
import static android.media.AudioAttributes.USAGE_ALARM;
|
||||
import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
@@ -91,6 +95,16 @@ public class SoundPreferenceController extends NotificationPreferenceController
|
||||
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||
if (KEY_SOUND.equals(preference.getKey()) && mFragment != null) {
|
||||
NotificationSoundPreference pref = (NotificationSoundPreference) preference;
|
||||
if (mChannel != null && mChannel.getAudioAttributes() != null) {
|
||||
if (USAGE_ALARM == mChannel.getAudioAttributes().getUsage()) {
|
||||
pref.setRingtoneType(RingtoneManager.TYPE_ALARM);
|
||||
} else if (USAGE_NOTIFICATION_RINGTONE
|
||||
== mChannel.getAudioAttributes().getUsage()) {
|
||||
pref.setRingtoneType(RingtoneManager.TYPE_RINGTONE);
|
||||
} else {
|
||||
pref.setRingtoneType(RingtoneManager.TYPE_NOTIFICATION);
|
||||
}
|
||||
}
|
||||
pref.onPrepareRingtonePickerIntent(pref.getIntent());
|
||||
mFragment.startActivityForResult(preference.getIntent(), CODE);
|
||||
return true;
|
||||
|
||||
@@ -39,6 +39,8 @@ import com.android.settingslib.core.lifecycle.events.OnResume;
|
||||
public class VibrateWhenRingPreferenceController extends TogglePreferenceController
|
||||
implements LifecycleObserver, OnResume, OnPause {
|
||||
|
||||
/** Flag for whether or not to apply ramping ringer on incoming phone calls. */
|
||||
private static final String RAMPING_RINGER_ENABLED = "ramping_ringer_enabled";
|
||||
private static final String KEY_VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
|
||||
private final int DEFAULT_VALUE = 0;
|
||||
private final int NOTIFICATION_VIBRATE_WHEN_RINGING = 1;
|
||||
@@ -130,8 +132,8 @@ public class VibrateWhenRingPreferenceController extends TogglePreferenceControl
|
||||
}
|
||||
|
||||
private boolean isRampingRingerEnabled() {
|
||||
return DeviceConfig.getBoolean(DeviceConfig.Telephony.NAMESPACE,
|
||||
DeviceConfig.Telephony.RAMPING_RINGER_ENABLED, false);
|
||||
return DeviceConfig.getBoolean(
|
||||
DeviceConfig.NAMESPACE_TELEPHONY, RAMPING_RINGER_ENABLED, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -183,6 +183,7 @@ public class ChooseLockGeneric extends SettingsActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
final Activity activity = getActivity();
|
||||
if (!Utils.isDeviceProvisioned(activity) && !canRunBeforeDeviceProvisioned()) {
|
||||
Log.i(TAG, "Refusing to start because device is not provisioned");
|
||||
activity.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package com.android.settings.privacy;
|
||||
|
||||
import static android.Manifest.permission_group.CAMERA;
|
||||
import static android.Manifest.permission_group.LOCATION;
|
||||
import static android.Manifest.permission_group.MICROPHONE;
|
||||
|
||||
import static com.android.settingslib.widget.BarChartPreference.MAXIMUM_BAR_VIEWS;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.DAYS;
|
||||
@@ -131,8 +135,28 @@ public class PermissionBarChartPreferenceController extends BasePreferenceContro
|
||||
|
||||
@Override
|
||||
public void onPermissionUsageResult(@NonNull List<RuntimePermissionUsageInfo> usageInfos) {
|
||||
usageInfos.sort(Comparator.comparingInt(
|
||||
RuntimePermissionUsageInfo::getAppAccessCount).reversed());
|
||||
usageInfos.sort((x, y) -> {
|
||||
int usageDiff = y.getAppAccessCount() - x.getAppAccessCount();
|
||||
if (usageDiff != 0) {
|
||||
return usageDiff;
|
||||
}
|
||||
String xName = x.getName();
|
||||
String yName = y.getName();
|
||||
if (xName.equals(LOCATION)) {
|
||||
return -1;
|
||||
} else if (yName.equals(LOCATION)) {
|
||||
return 1;
|
||||
} else if (xName.equals(MICROPHONE)) {
|
||||
return -1;
|
||||
} else if (yName.equals(MICROPHONE)) {
|
||||
return 1;
|
||||
} else if (xName.equals(CAMERA)) {
|
||||
return -1;
|
||||
} else if (yName.equals(CAMERA)) {
|
||||
return 1;
|
||||
}
|
||||
return x.getName().compareTo(y.getName());
|
||||
});
|
||||
|
||||
// If the result is different, we need to update bar views.
|
||||
if (!areSamePermissionGroups(usageInfos)) {
|
||||
@@ -176,6 +200,7 @@ public class PermissionBarChartPreferenceController extends BasePreferenceContro
|
||||
barViewInfos[index].setClickListener((View v) -> {
|
||||
final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
|
||||
intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, permissionGroupInfo.getName());
|
||||
intent.putExtra(Intent.EXTRA_DURATION_MILLIS, DAYS.toMillis(1));
|
||||
mContext.startActivity(intent);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ public class SimDialogActivity extends Activity {
|
||||
builder.setTitle(R.string.select_sim_for_calls);
|
||||
break;
|
||||
case SMS_PICK:
|
||||
builder.setTitle(R.string.sim_card_select_title);
|
||||
builder.setTitle(R.string.select_sim_for_sms);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid dialog type "
|
||||
|
||||
@@ -30,6 +30,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Settings.SimSettingsActivity;
|
||||
@@ -45,6 +46,9 @@ public class SimSelectNotification extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (!TelephonyManager.ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED.equals(intent.getAction())) {
|
||||
return;
|
||||
}
|
||||
// Cancel any previous notifications
|
||||
cancelNotification(context);
|
||||
// Create a notification to tell the user that some defaults are missing
|
||||
|
||||
@@ -20,12 +20,14 @@ import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.provider.SearchIndexableResource;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.search.Indexable;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
@@ -40,6 +42,8 @@ public class SystemDashboardFragment extends DashboardFragment {
|
||||
|
||||
private static final String KEY_RESET = "reset_dashboard";
|
||||
|
||||
public static final String EXTRA_SHOW_AWARE_DISABLED = "show_aware_dialog_disabled";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
@@ -49,6 +53,17 @@ public class SystemDashboardFragment extends DashboardFragment {
|
||||
if (getVisiblePreferenceCount(screen) == screen.getInitialExpandedChildrenCount() + 1) {
|
||||
screen.setInitialExpandedChildrenCount(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
showRestrictionDialog();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void showRestrictionDialog() {
|
||||
final Bundle args = getArguments();
|
||||
if (args != null && args.getBoolean(EXTRA_SHOW_AWARE_DISABLED, false)) {
|
||||
FeatureFactory.getFactory(getContext()).getAwareFeatureProvider()
|
||||
.showRestrictionDialog(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -143,6 +143,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
|
||||
}
|
||||
mMppe.setChecked(mProfile.mppe);
|
||||
mL2tpSecret.setText(mProfile.l2tpSecret);
|
||||
mL2tpSecret.setTextAppearance(android.R.style.TextAppearance_DeviceDefault_Medium);
|
||||
mIpsecIdentifier.setText(mProfile.ipsecIdentifier);
|
||||
mIpsecSecret.setText(mProfile.ipsecSecret);
|
||||
loadCertificates(mIpsecUserCert, Credentials.USER_PRIVATE_KEY, 0, mProfile.ipsecUserCert);
|
||||
@@ -152,6 +153,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
|
||||
R.string.vpn_no_server_cert, mProfile.ipsecServerCert);
|
||||
mSaveLogin.setChecked(mProfile.saveLogin);
|
||||
mAlwaysOnVpn.setChecked(mProfile.key.equals(VpnUtils.getLockdownVpn()));
|
||||
mPassword.setTextAppearance(android.R.style.TextAppearance_DeviceDefault_Medium);
|
||||
|
||||
// Hide lockdown VPN on devices that require IMS authentication
|
||||
if (SystemProperties.getBoolean("persist.radio.imsregrequired", false)) {
|
||||
|
||||
@@ -28,10 +28,18 @@ import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.search.Indexable;
|
||||
import com.android.settings.search.SearchIndexableRaw;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
|
||||
public class WallpaperSuggestionActivity extends Activity {
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SearchIndexable
|
||||
public class WallpaperSuggestionActivity extends Activity implements Indexable {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -79,4 +87,30 @@ public class WallpaperSuggestionActivity extends Activity {
|
||||
return context.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_enableWallpaperService);
|
||||
}
|
||||
|
||||
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider() {
|
||||
private static final String SUPPORT_SEARCH_INDEX_KEY = "wallpaper_type";
|
||||
|
||||
@Override
|
||||
public List<SearchIndexableRaw> getRawDataToIndex(Context context,
|
||||
boolean enabled) {
|
||||
|
||||
final List<SearchIndexableRaw> result = new ArrayList<>();
|
||||
|
||||
SearchIndexableRaw data = new SearchIndexableRaw(context);
|
||||
data.title = context.getString(R.string.wallpaper_settings_fragment_title);
|
||||
data.screenTitle = context.getString(
|
||||
R.string.wallpaper_settings_fragment_title);
|
||||
data.intentTargetPackage = context.getString(
|
||||
R.string.config_wallpaper_picker_package);
|
||||
data.intentTargetClass = context.getString(
|
||||
R.string.config_wallpaper_picker_class);
|
||||
data.intentAction = Intent.ACTION_MAIN;
|
||||
data.key = SUPPORT_SEARCH_INDEX_KEY;
|
||||
result.add(data);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,21 +17,11 @@
|
||||
package com.android.settings.wallpaper;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.search.SearchIndexableRaw;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
|
||||
public class WallpaperTypeSettings extends DashboardFragment {
|
||||
private static final String TAG = "WallpaperTypeSettings";
|
||||
|
||||
@@ -54,42 +44,4 @@ public class WallpaperTypeSettings extends DashboardFragment {
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.wallpaper_settings;
|
||||
}
|
||||
|
||||
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider() {
|
||||
@Override
|
||||
public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
|
||||
final List<SearchIndexableRaw> result = new ArrayList<>();
|
||||
|
||||
final Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER);
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
final List<ResolveInfo> rList = pm.queryIntentActivities(intent,
|
||||
PackageManager.MATCH_DEFAULT_ONLY);
|
||||
|
||||
// Add indexable data for package that is in config_wallpaper_picker_package
|
||||
final String wallpaperPickerPackage =
|
||||
context.getString(R.string.config_wallpaper_picker_package);
|
||||
for (ResolveInfo info : rList) {
|
||||
if (!wallpaperPickerPackage.equals(info.activityInfo.packageName)) {
|
||||
continue;
|
||||
}
|
||||
CharSequence label = info.loadLabel(pm);
|
||||
if (label == null) {
|
||||
label = info.activityInfo.packageName;
|
||||
}
|
||||
final SearchIndexableRaw data = new SearchIndexableRaw(context);
|
||||
data.title = label.toString();
|
||||
data.key = "wallpaper_type_settings";
|
||||
data.screenTitle = context.getResources().getString(
|
||||
R.string.wallpaper_settings_fragment_title);
|
||||
data.intentAction = Intent.ACTION_SET_WALLPAPER;
|
||||
data.intentTargetPackage = info.activityInfo.packageName;
|
||||
data.intentTargetClass = info.activityInfo.name;
|
||||
data.keywords = context.getString(R.string.keywords_wallpaper);
|
||||
result.add(data);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -138,9 +138,9 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
|
||||
.setOnItemClickListener(
|
||||
(parent, view, position, id) -> this.onClick(dialog, position));
|
||||
|
||||
// Don't dismiss dialog when touching outside. User report it is easy to touch outside.
|
||||
// This causes dialog to close. Which is concerned as a bad UX (b/128877712).
|
||||
dialog.setCanceledOnTouchOutside(false);
|
||||
// Don't dismiss dialog when touching outside. User reports it is easy to touch outside.
|
||||
// This causes dialog to close.
|
||||
setCancelable(false);
|
||||
|
||||
dialog.setOnShowListener((dialogInterface) -> {
|
||||
// Replace NeutralButton onClickListener to avoid closing dialog
|
||||
|
||||
@@ -55,6 +55,7 @@ import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
@@ -64,6 +65,7 @@ import androidx.annotation.VisibleForTesting;
|
||||
import com.android.settings.ProxySelector;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.wifi.details.WifiPrivacyPreferenceController;
|
||||
import com.android.settings.wifi.dpp.WifiDppUtils;
|
||||
import com.android.settingslib.Utils;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
import com.android.settingslib.wifi.AccessPoint;
|
||||
@@ -129,6 +131,8 @@ public class WifiConfigController implements TextWatcher,
|
||||
@VisibleForTesting
|
||||
int mAccessPointSecurity;
|
||||
private TextView mPasswordView;
|
||||
private ImageButton mSsidScanButton;
|
||||
private ImageButton mPasswordScanButton;
|
||||
|
||||
private String mUnspecifiedCertString;
|
||||
private String mMultipleCertSetString;
|
||||
@@ -239,6 +243,8 @@ public class WifiConfigController implements TextWatcher,
|
||||
mDoNotValidateEapServerString =
|
||||
mContext.getString(R.string.wifi_do_not_validate_eap_server);
|
||||
|
||||
mSsidScanButton = (ImageButton) mView.findViewById(R.id.ssid_scanner_button);
|
||||
mPasswordScanButton = (ImageButton) mView.findViewById(R.id.password_scanner_button);
|
||||
mDialogContainer = mView.findViewById(R.id.dialog_scrollview);
|
||||
mIpSettingsSpinner = (Spinner) mView.findViewById(R.id.ip_settings);
|
||||
mIpSettingsSpinner.setOnItemSelectedListener(this);
|
||||
@@ -264,6 +270,7 @@ public class WifiConfigController implements TextWatcher,
|
||||
if (mAccessPoint == null) { // new network
|
||||
configureSecuritySpinner();
|
||||
mConfigUi.setSubmitButton(res.getString(R.string.wifi_save));
|
||||
mPasswordScanButton.setVisibility(View.GONE);
|
||||
} else {
|
||||
mConfigUi.setTitle(mAccessPoint.getTitle());
|
||||
|
||||
@@ -408,6 +415,11 @@ public class WifiConfigController implements TextWatcher,
|
||||
mConfigUi.setForgetButton(res.getString(R.string.wifi_forget));
|
||||
}
|
||||
}
|
||||
|
||||
if (!WifiDppUtils.isSupportEnrolleeQrCodeScanner(mContext, mAccessPointSecurity)) {
|
||||
mPasswordScanButton.setVisibility(View.GONE);
|
||||
}
|
||||
mSsidScanButton.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (!isSplitSystemUser()) {
|
||||
@@ -1444,6 +1456,12 @@ public class WifiConfigController implements TextWatcher,
|
||||
// Convert menu position to actual Wi-Fi security type
|
||||
mAccessPointSecurity = mSecurityInPosition[position];
|
||||
showSecurityFields();
|
||||
|
||||
if (WifiDppUtils.isSupportEnrolleeQrCodeScanner(mContext, mAccessPointSecurity)) {
|
||||
mSsidScanButton.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mSsidScanButton.setVisibility(View.GONE);
|
||||
}
|
||||
} else if (parent == mEapMethodSpinner || parent == mEapCaCertSpinner) {
|
||||
showSecurityFields();
|
||||
} else if (parent == mPhase2Spinner
|
||||
|
||||
@@ -115,6 +115,8 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
|
||||
@VisibleForTesting
|
||||
static final String KEY_SECURITY_PREF = "security";
|
||||
@VisibleForTesting
|
||||
static final String KEY_SSID_PREF = "ssid";
|
||||
@VisibleForTesting
|
||||
static final String KEY_MAC_ADDRESS_PREF = "mac_address";
|
||||
@VisibleForTesting
|
||||
static final String KEY_IP_ADDRESS_PREF = "ip_address";
|
||||
@@ -158,6 +160,7 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
|
||||
private final WifiTracker mWifiTracker;
|
||||
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
||||
private boolean mIsOutOfRange;
|
||||
private boolean mIsEphemeral;
|
||||
private boolean mConnected;
|
||||
private int mConnectingState;
|
||||
private WifiManager.ActionListener mConnectListener;
|
||||
@@ -170,6 +173,7 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
|
||||
private Preference mRxLinkSpeedPref;
|
||||
private Preference mFrequencyPref;
|
||||
private Preference mSecurityPref;
|
||||
private Preference mSsidPref;
|
||||
private Preference mMacAddressPref;
|
||||
private Preference mIpAddressPref;
|
||||
private Preference mGatewayPref;
|
||||
@@ -248,12 +252,14 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
|
||||
|
||||
@Override
|
||||
public void onLost(Network network) {
|
||||
// If support detail page for saved network, should update as disconnect but not exit.
|
||||
if (SavedAccessPointsWifiSettings.usingDetailsFragment(mContext)) {
|
||||
return;
|
||||
}
|
||||
final boolean lostCurrentNetwork = network.equals(mNetwork);
|
||||
if (lostCurrentNetwork) {
|
||||
// If support detail page for saved network, should update as disconnect but not
|
||||
// exit. Except for ephemeral network which should not show on saved network list.
|
||||
if (SavedAccessPointsWifiSettings.usingDetailsFragment(mContext) && !mIsEphemeral) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (network.equals(mNetwork)) {
|
||||
exitActivity();
|
||||
}
|
||||
}
|
||||
@@ -347,6 +353,9 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
|
||||
mWifiTracker = null;
|
||||
}
|
||||
mConnected = mAccessPoint.isActive();
|
||||
// When lost the network connection, WifiInfo/NetworkInfo will be clear. So causes we
|
||||
// could not check if the AccessPoint is ephemeral. Need to cache it in first.
|
||||
mIsEphemeral = mAccessPoint.isEphemeral();
|
||||
mConnectingState = STATE_NONE;
|
||||
mConnectListener = new WifiManager.ActionListener() {
|
||||
@Override
|
||||
@@ -399,6 +408,7 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
|
||||
mFrequencyPref = screen.findPreference(KEY_FREQUENCY_PREF);
|
||||
mSecurityPref = screen.findPreference(KEY_SECURITY_PREF);
|
||||
|
||||
mSsidPref = screen.findPreference(KEY_SSID_PREF);
|
||||
mMacAddressPref = screen.findPreference(KEY_MAC_ADDRESS_PREF);
|
||||
mIpAddressPref = screen.findPreference(KEY_IP_ADDRESS_PREF);
|
||||
mGatewayPref = screen.findPreference(KEY_GATEWAY_PREF);
|
||||
@@ -497,6 +507,8 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
|
||||
refreshRxSpeed();
|
||||
// IP related information
|
||||
refreshIpLayerInfo();
|
||||
// SSID Pref
|
||||
refreshSsid();
|
||||
// MAC Address Pref
|
||||
refreshMacAddress();
|
||||
}
|
||||
@@ -645,6 +657,15 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
|
||||
R.string.rx_link_speed, mWifiInfo.getRxLinkSpeedMbps()));
|
||||
}
|
||||
|
||||
private void refreshSsid() {
|
||||
if (mAccessPoint.isPasspoint() || mAccessPoint.isOsuProvider()) {
|
||||
mSsidPref.setVisible(true);
|
||||
mSsidPref.setSummary(mAccessPoint.getSsidStr());
|
||||
} else {
|
||||
mSsidPref.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshMacAddress() {
|
||||
String macAddress = getMacAddress();
|
||||
if (macAddress == null) {
|
||||
@@ -663,7 +684,8 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
|
||||
}
|
||||
|
||||
// return randomized MAC address
|
||||
if (mWifiConfig.macRandomizationSetting == WifiConfiguration.RANDOMIZATION_PERSISTENT) {
|
||||
if (mWifiConfig != null &&
|
||||
mWifiConfig.macRandomizationSetting == WifiConfiguration.RANDOMIZATION_PERSISTENT) {
|
||||
return mWifiConfig.getRandomizedMacAddress().toString();
|
||||
}
|
||||
|
||||
@@ -687,6 +709,10 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
|
||||
}
|
||||
|
||||
private void refreshButtons() {
|
||||
// Ephemeral network won't be removed permanently, but be putted in blacklist.
|
||||
mButtonsPref.setButton1Text(
|
||||
mIsEphemeral ? R.string.wifi_disconnect_button_text : R.string.forget);
|
||||
|
||||
mButtonsPref.setButton1Visible(canForgetNetwork());
|
||||
mButtonsPref.setButton2Visible(canSignIntoNetwork());
|
||||
mButtonsPref.setButton3Visible(canConnectNetwork());
|
||||
|
||||
@@ -140,6 +140,8 @@ public class WifiNetworkDetailsFragment extends DashboardFragment {
|
||||
context);
|
||||
privacyController.setWifiConfiguration(mAccessPoint.getConfig());
|
||||
privacyController.setIsEphemeral(mAccessPoint.isEphemeral());
|
||||
privacyController.setIsPasspoint(
|
||||
mAccessPoint.isPasspoint() || mAccessPoint.isPasspointConfig());
|
||||
controllers.add(privacyController);
|
||||
|
||||
return controllers;
|
||||
|
||||
@@ -41,6 +41,7 @@ public class WifiPrivacyPreferenceController extends BasePreferenceController im
|
||||
private WifiConfiguration mWifiConfiguration;
|
||||
private WifiManager mWifiManager;
|
||||
private boolean mIsEphemeral = false;
|
||||
private boolean mIsPasspoint = false;
|
||||
|
||||
public WifiPrivacyPreferenceController(Context context) {
|
||||
super(context, KEY_WIFI_PRIVACY);
|
||||
@@ -56,6 +57,10 @@ public class WifiPrivacyPreferenceController extends BasePreferenceController im
|
||||
mIsEphemeral = isEphemeral;
|
||||
}
|
||||
|
||||
public void setIsPasspoint(boolean isPasspoint) {
|
||||
mIsPasspoint = isPasspoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return mContext.getResources().getBoolean(
|
||||
@@ -71,7 +76,7 @@ public class WifiPrivacyPreferenceController extends BasePreferenceController im
|
||||
updateSummary(dropDownPreference, randomizationLevel);
|
||||
|
||||
// Makes preference not selectable, when this is a ephemeral network.
|
||||
if (mIsEphemeral) {
|
||||
if (mIsEphemeral || mIsPasspoint) {
|
||||
preference.setSelectable(false);
|
||||
dropDownPreference.setSummary(R.string.wifi_privacy_settings_ephemeral_summary);
|
||||
}
|
||||
|
||||
@@ -134,6 +134,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
|
||||
|
||||
if (msg.arg1 == ARG_RESTART_CAMERA) {
|
||||
mProgressBar.setVisibility(View.INVISIBLE);
|
||||
mDecorateView.setFocused(false);
|
||||
restartCamera();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -323,31 +323,36 @@ public class WifiDppUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if QR code scanner supports to config other devices with the Wi-Fi network
|
||||
*
|
||||
* @param context The context to use for {@link WifiManager#isEasyConnectSupported()}
|
||||
* @param accessPoint The {@link AccessPoint} of the Wi-Fi network
|
||||
*/
|
||||
public static boolean isSupportConfiguratorQrCodeScanner(Context context,
|
||||
AccessPoint accessPoint) {
|
||||
if (!isWifiDppEnabled(context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// DPP 1.0 only supports SAE and PSK.
|
||||
final int security = accessPoint.getSecurity();
|
||||
if (security == AccessPoint.SECURITY_SAE || security == AccessPoint.SECURITY_PSK) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return isSupportWifiDpp(context, accessPoint.getSecurity());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if QR code generator supports to config other devices with the Wi-Fi network
|
||||
*
|
||||
* @param accessPoint The {@link AccessPoint} of the Wi-Fi network
|
||||
*/
|
||||
public static boolean isSupportConfiguratorQrCodeGenerator(AccessPoint accessPoint) {
|
||||
// QR code generator produces QR code with ZXing's Wi-Fi network config format,
|
||||
// it supports PSK and WEP and non security
|
||||
final int security = accessPoint.getSecurity();
|
||||
if (security == AccessPoint.SECURITY_PSK || security == AccessPoint.SECURITY_WEP ||
|
||||
security == AccessPoint.SECURITY_NONE) {
|
||||
return true;
|
||||
}
|
||||
return isSupportZxing(accessPoint.getSecurity());
|
||||
}
|
||||
|
||||
return false;
|
||||
/**
|
||||
* Checks if this device supports to be configured by the Wi-Fi network of the security
|
||||
*
|
||||
* @param context The context to use for {@link WifiManager#isEasyConnectSupported()}
|
||||
* @param accesspointSecurity The security constants defined in {@link AccessPoint}
|
||||
*/
|
||||
public static boolean isSupportEnrolleeQrCodeScanner(Context context,
|
||||
int accesspointSecurity) {
|
||||
return isSupportWifiDpp(context, accesspointSecurity) ||
|
||||
isSupportZxing(accesspointSecurity);
|
||||
}
|
||||
|
||||
private static boolean isSupportHotspotConfiguratorQrCodeGenerator(
|
||||
@@ -358,4 +363,27 @@ public class WifiDppUtils {
|
||||
return wifiConfiguration.allowedKeyManagement.get(KeyMgmt.WPA2_PSK) ||
|
||||
wifiConfiguration.allowedKeyManagement.get(KeyMgmt.NONE);
|
||||
}
|
||||
|
||||
private static boolean isSupportWifiDpp(Context context, int accesspointSecurity) {
|
||||
if (!isWifiDppEnabled(context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// DPP 1.0 only supports SAE and PSK.
|
||||
if (accesspointSecurity == AccessPoint.SECURITY_SAE ||
|
||||
accesspointSecurity == AccessPoint.SECURITY_PSK) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO (b/124131581 b/129396816): TO support WPA3 securities (SAE & OWE), change here at first
|
||||
private static boolean isSupportZxing(int accesspointSecurity) {
|
||||
if (accesspointSecurity == AccessPoint.SECURITY_PSK ||
|
||||
accesspointSecurity == AccessPoint.SECURITY_WEP ||
|
||||
accesspointSecurity == AccessPoint.SECURITY_NONE) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +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.wifi.qrcode;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
/**
|
||||
* A customize square {@link FrameLayout}.
|
||||
* This is used for camera preview. Choose the smaller size of both dimensions as length and width.
|
||||
*/
|
||||
public class QrPreviewLayout extends FrameLayout {
|
||||
public QrPreviewLayout(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public QrPreviewLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public QrPreviewLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
// Choose the smaller size of the two dimensions.
|
||||
if (MeasureSpec.getSize(widthMeasureSpec) > MeasureSpec.getSize(heightMeasureSpec)) {
|
||||
super.onMeasure(heightMeasureSpec, heightMeasureSpec);
|
||||
} else {
|
||||
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,6 +75,7 @@ com.android.settings.users.RestrictedProfileSettings
|
||||
com.android.settings.users.UserDetailsSettings
|
||||
com.android.settings.vpn2.AppManagementFragment
|
||||
com.android.settings.vpn2.VpnSettings
|
||||
com.android.settings.wallpaper.WallpaperTypeSettings
|
||||
com.android.settings.wifi.calling.WifiCallingSettingsForSub
|
||||
com.android.settings.wifi.ChangeWifiStateDetails
|
||||
com.android.settings.wifi.details.WifiNetworkDetailsFragment
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<item name="android:textColorPrimary">@android:color/white</item>
|
||||
<item name="switchBarMarginStart">@dimen/switchbar_subsettings_margin_start</item>
|
||||
<item name="switchBarMarginEnd">@dimen/switchbar_subsettings_margin_end</item>
|
||||
<item name="switchBarBackgroundColor">@color/switch_bar_background</item>
|
||||
<item name="switchBarBackgroundColor">?android:attr/textColorSecondary</item>
|
||||
<item name="switchBarBackgroundActivatedColor">?android:attr/colorAccent</item>
|
||||
<item name="switchBarRestrictionIcon">@drawable/ic_help</item>
|
||||
</style>
|
||||
|
||||
@@ -31,24 +31,27 @@ import org.robolectric.RobolectricTestRunner;
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class SetupWizardUtilsTest {
|
||||
|
||||
private static final String EXTRA_IS_SETUP_FLOW = "isSetupFlow";
|
||||
private static final String EXTRA_IS_FIRST_RUN = "firstRun";
|
||||
|
||||
@Test
|
||||
public void testCopySetupExtras() {
|
||||
Intent fromIntent = new Intent();
|
||||
final String theme = "TEST_THEME";
|
||||
fromIntent.putExtra(WizardManagerHelper.EXTRA_THEME, theme);
|
||||
fromIntent.putExtra(WizardManagerHelper.EXTRA_USE_IMMERSIVE_MODE, true);
|
||||
fromIntent.putExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, true);
|
||||
Intent toIntent = new Intent();
|
||||
SetupWizardUtils.copySetupExtras(fromIntent, toIntent);
|
||||
|
||||
assertThat(theme).isEqualTo(toIntent.getStringExtra(WizardManagerHelper.EXTRA_THEME));
|
||||
assertThat(toIntent.getBooleanExtra(WizardManagerHelper.EXTRA_USE_IMMERSIVE_MODE, false))
|
||||
assertThat(toIntent.getBooleanExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, false))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTheme_withIntentExtra_shouldReturnExtraTheme() {
|
||||
SetupWizardProperties.theme(ThemeHelper.THEME_GLIF);
|
||||
Intent intent = new Intent();
|
||||
Intent intent = createSetupWizardIntent();
|
||||
intent.putExtra(WizardManagerHelper.EXTRA_THEME, ThemeHelper.THEME_GLIF_V2);
|
||||
|
||||
assertThat(SetupWizardUtils.getTheme(intent)).isEqualTo(R.style.GlifV2Theme);
|
||||
@@ -57,7 +60,7 @@ public class SetupWizardUtilsTest {
|
||||
@Test
|
||||
public void testGetTheme_withEmptyIntent_shouldReturnSystemProperty() {
|
||||
SetupWizardProperties.theme(ThemeHelper.THEME_GLIF_V2_LIGHT);
|
||||
Intent intent = new Intent();
|
||||
Intent intent = createSetupWizardIntent();
|
||||
|
||||
assertThat(SetupWizardUtils.getTheme(intent)).isEqualTo(R.style.GlifV2Theme_Light);
|
||||
}
|
||||
@@ -65,10 +68,26 @@ public class SetupWizardUtilsTest {
|
||||
@Test
|
||||
public void testGetTheme_glifV3Light_shouldReturnThemeResource() {
|
||||
SetupWizardProperties.theme(ThemeHelper.THEME_GLIF_V3_LIGHT);
|
||||
Intent intent = new Intent();
|
||||
Intent intent = createSetupWizardIntent();
|
||||
|
||||
assertThat(SetupWizardUtils.getTheme(intent)).isEqualTo(R.style.GlifV3Theme_Light);
|
||||
assertThat(SetupWizardUtils.getTransparentTheme(intent))
|
||||
.isEqualTo(R.style.GlifV3Theme_Light_Transparent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTheme_nonSuw_shouldReturnDayNightTheme() {
|
||||
SetupWizardProperties.theme(ThemeHelper.THEME_GLIF_V3_LIGHT);
|
||||
Intent intent = new Intent();
|
||||
|
||||
assertThat(SetupWizardUtils.getTheme(intent)).isEqualTo(R.style.GlifV3Theme);
|
||||
assertThat(SetupWizardUtils.getTransparentTheme(intent))
|
||||
.isEqualTo(R.style.GlifV3Theme_Transparent);
|
||||
}
|
||||
|
||||
private Intent createSetupWizardIntent() {
|
||||
return new Intent()
|
||||
.putExtra(EXTRA_IS_SETUP_FLOW, true)
|
||||
.putExtra(EXTRA_IS_FIRST_RUN, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ public class AccessibilitySettingsTest {
|
||||
|
||||
@Test
|
||||
public void testDarkUIModePreferenceSummary_shouldUpdateSummary() {
|
||||
final ListPreference darkUIModePreference = new ListPreference(mContext);
|
||||
final Preference darkUIModePreference = new Preference(mContext);
|
||||
final DarkUIPreferenceController mController;
|
||||
doReturn(darkUIModePreference).when(mSettings).findPreference(
|
||||
DARK_UI_MODE_PREFERENCE);
|
||||
|
||||
@@ -119,7 +119,6 @@ public class AppButtonsPreferenceControllerTest {
|
||||
|
||||
mController = spy(new AppButtonsPreferenceController(mSettingsActivity, mFragment,
|
||||
mLifecycle, PACKAGE_NAME, mState, REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN));
|
||||
doReturn(false).when(mController).isFallbackPackage(anyString());
|
||||
|
||||
mAppEntry.info = mAppInfo;
|
||||
mAppInfo.packageName = PACKAGE_NAME;
|
||||
|
||||
@@ -20,6 +20,11 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
@@ -33,6 +38,8 @@ import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Settings;
|
||||
import com.android.settings.applications.specialaccess.deviceadmin.DeviceAdminAdd;
|
||||
@@ -179,5 +186,28 @@ public class ActionDisabledByAdminDialogHelperTest {
|
||||
mHelper.setAdminSupportDetails(mActivity, null, admin);
|
||||
assertNull(admin.component);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaybeSetLearnMoreButton() {
|
||||
final UserManager userManager = RuntimeEnvironment.application.getSystemService(
|
||||
UserManager.class);
|
||||
final ShadowUserManager userManagerShadow = Shadow.extract(userManager);
|
||||
final ComponentName component = new ComponentName("some.package.name",
|
||||
"some.package.name.SomeClass");
|
||||
mHelper.mEnforcedAdmin = new EnforcedAdmin(component, UserHandle.of(123));
|
||||
|
||||
// Set up for shadow call.
|
||||
userManagerShadow.getSameProfileGroupIds().put(123, 0);
|
||||
|
||||
// Test that the button is shown when user IDs are in the same profile group
|
||||
AlertDialog.Builder builder = mock(AlertDialog.Builder.class);
|
||||
mHelper.maybeSetLearnMoreButton(builder);
|
||||
verify(builder).setNeutralButton(anyInt(), any());
|
||||
|
||||
// Test that the button is not shown when user IDs are not in the same profile group
|
||||
userManagerShadow.getSameProfileGroupIds().clear();
|
||||
builder = mock(AlertDialog.Builder.class);
|
||||
mHelper.maybeSetLearnMoreButton(builder);
|
||||
verify(builder, never()).setNeutralButton(anyInt(), any());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.content.Context;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.Global;
|
||||
import android.provider.Settings.Secure;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -54,4 +55,13 @@ public class BatterySaverScheduleRadioButtonsControllerTest {
|
||||
assertThat(mController.getDefaultKey())
|
||||
.isEqualTo(BatterySaverScheduleRadioButtonsController.KEY_NO_SCHEDULE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setDefaultKey_any_defaultsToNoScheduleIfWarningNotSeen() {
|
||||
Secure.putString(
|
||||
mContext.getContentResolver(), Secure.LOW_POWER_WARNING_ACKNOWLEDGED, "null");
|
||||
mController.setDefaultKey(BatterySaverScheduleRadioButtonsController.KEY_ROUTINE);
|
||||
assertThat(mController.getDefaultKey())
|
||||
.isEqualTo(BatterySaverScheduleRadioButtonsController.KEY_NO_SCHEDULE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.settings.homepage.contextualcards.slices;
|
||||
|
||||
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||
import static android.app.slice.Slice.HINT_LIST_ITEM;
|
||||
import static android.app.slice.SliceItem.FORMAT_SLICE;
|
||||
@@ -116,7 +117,8 @@ public class NotificationChannelSliceTest {
|
||||
public void getSlice_hasSuggestedApp_shouldHaveNotificationChannelTitle() {
|
||||
addMockPackageToPackageManager(true /* isRecentlyInstalled */,
|
||||
ApplicationInfo.FLAG_INSTALLED);
|
||||
mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */);
|
||||
mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */,
|
||||
false /* isChannelBlocked */);
|
||||
|
||||
final Slice slice = mNotificationChannelSlice.getSlice();
|
||||
|
||||
@@ -130,7 +132,8 @@ public class NotificationChannelSliceTest {
|
||||
public void getSlice_hasSuggestedApp_shouldSortByNotificationSentCount() {
|
||||
addMockPackageToPackageManager(true /* isRecentlyInstalled */,
|
||||
ApplicationInfo.FLAG_INSTALLED);
|
||||
mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */);
|
||||
mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */,
|
||||
false /* isChannelBlocked */);
|
||||
|
||||
final Slice slice = mNotificationChannelSlice.getSlice();
|
||||
|
||||
@@ -157,7 +160,8 @@ public class NotificationChannelSliceTest {
|
||||
public void getSlice_noRecentlyInstalledApp_shouldHaveNoSuggestedAppTitle() {
|
||||
addMockPackageToPackageManager(false /* isRecentlyInstalled */,
|
||||
ApplicationInfo.FLAG_INSTALLED);
|
||||
mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */);
|
||||
mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */,
|
||||
false /* isChannelBlocked */);
|
||||
|
||||
final Slice slice = mNotificationChannelSlice.getSlice();
|
||||
|
||||
@@ -169,7 +173,8 @@ public class NotificationChannelSliceTest {
|
||||
public void getSlice_noMultiChannelApp_shouldHaveNoSuggestedAppTitle() {
|
||||
addMockPackageToPackageManager(true /* isRecentlyInstalled */,
|
||||
ApplicationInfo.FLAG_INSTALLED);
|
||||
mockNotificationBackend(1 /* channelCount */, NOTIFICATION_COUNT, false /* banned */);
|
||||
mockNotificationBackend(1 /* channelCount */, NOTIFICATION_COUNT, false /* banned */,
|
||||
false /* isChannelBlocked */);
|
||||
|
||||
final Slice slice = mNotificationChannelSlice.getSlice();
|
||||
|
||||
@@ -178,10 +183,12 @@ public class NotificationChannelSliceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowRestrictedLockUtilsInternal.class)
|
||||
public void getSlice_insufficientNotificationSentCount_shouldHaveNoSuggestedAppTitle() {
|
||||
addMockPackageToPackageManager(true /* isRecentlyInstalled */,
|
||||
ApplicationInfo.FLAG_INSTALLED);
|
||||
mockNotificationBackend(CHANNEL_COUNT, 1 /* notificationCount */, false /* banned */);
|
||||
mockNotificationBackend(CHANNEL_COUNT, 1 /* notificationCount */, false /* banned */,
|
||||
false /* isChannelBlocked */);
|
||||
|
||||
final Slice slice = mNotificationChannelSlice.getSlice();
|
||||
|
||||
@@ -192,7 +199,8 @@ public class NotificationChannelSliceTest {
|
||||
@Test
|
||||
public void getSlice_isSystemApp_shouldHaveNoSuggestedAppTitle() {
|
||||
addMockPackageToPackageManager(true /* isRecentlyInstalled */, ApplicationInfo.FLAG_SYSTEM);
|
||||
mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */);
|
||||
mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */,
|
||||
false /* isChannelBlocked */);
|
||||
|
||||
final Slice slice = mNotificationChannelSlice.getSlice();
|
||||
|
||||
@@ -204,7 +212,8 @@ public class NotificationChannelSliceTest {
|
||||
public void getSlice_isNotificationBanned_shouldHaveNoSuggestedAppTitle() {
|
||||
addMockPackageToPackageManager(true /* isRecentlyInstalled */,
|
||||
ApplicationInfo.FLAG_INSTALLED);
|
||||
mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, true /* banned */);
|
||||
mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, true /* banned */,
|
||||
false /* isChannelBlocked */);
|
||||
|
||||
final Slice slice = mNotificationChannelSlice.getSlice();
|
||||
|
||||
@@ -218,7 +227,7 @@ public class NotificationChannelSliceTest {
|
||||
addMockPackageToPackageManager(true /* isRecentlyInstalled */,
|
||||
ApplicationInfo.FLAG_INSTALLED);
|
||||
mockNotificationBackend(NotificationChannelSlice.DEFAULT_EXPANDED_ROW_COUNT * 2,
|
||||
NOTIFICATION_COUNT, false /* banned */);
|
||||
NOTIFICATION_COUNT, false /* banned */, false /* isChannelBlocked */);
|
||||
|
||||
final Slice slice = mNotificationChannelSlice.getSlice();
|
||||
|
||||
@@ -234,7 +243,8 @@ public class NotificationChannelSliceTest {
|
||||
public void getSlice_channelCountIsLessThanDefaultRows_subTitleShouldNotHaveTapToManagerAll() {
|
||||
addMockPackageToPackageManager(true /* isRecentlyInstalled */,
|
||||
ApplicationInfo.FLAG_INSTALLED);
|
||||
mockNotificationBackend(CHANNEL_COUNT - 1, NOTIFICATION_COUNT, false /* banned */);
|
||||
mockNotificationBackend(CHANNEL_COUNT - 1, NOTIFICATION_COUNT, false /* banned */,
|
||||
false /* isChannelBlocked */);
|
||||
|
||||
final Slice slice = mNotificationChannelSlice.getSlice();
|
||||
|
||||
@@ -249,7 +259,8 @@ public class NotificationChannelSliceTest {
|
||||
public void getSlice_channelCountIsEqualToDefaultRows_subTitleShouldNotHaveTapToManagerAll() {
|
||||
addMockPackageToPackageManager(true /* isRecentlyInstalled */,
|
||||
ApplicationInfo.FLAG_INSTALLED);
|
||||
mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */);
|
||||
mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */,
|
||||
false /* isChannelBlocked */);
|
||||
|
||||
final Slice slice = mNotificationChannelSlice.getSlice();
|
||||
|
||||
@@ -263,7 +274,8 @@ public class NotificationChannelSliceTest {
|
||||
public void getSlice_channelCountIsMoreThanDefaultRows_subTitleShouldHaveTapToManagerAll() {
|
||||
addMockPackageToPackageManager(true /* isRecentlyInstalled */,
|
||||
ApplicationInfo.FLAG_INSTALLED);
|
||||
mockNotificationBackend(CHANNEL_COUNT + 1, NOTIFICATION_COUNT, false /* banned */);
|
||||
mockNotificationBackend(CHANNEL_COUNT + 1, NOTIFICATION_COUNT, false /* banned */,
|
||||
false /* isChannelBlocked */);
|
||||
|
||||
final Slice slice = mNotificationChannelSlice.getSlice();
|
||||
|
||||
@@ -273,6 +285,20 @@ public class NotificationChannelSliceTest {
|
||||
CHANNEL_COUNT + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = ShadowRestrictedLockUtilsInternal.class)
|
||||
public void getSlice_isAllDisplayableChannelBlocked_shouldHaveNoSuggestedAppTitle() {
|
||||
addMockPackageToPackageManager(true /* isRecentlyInstalled */,
|
||||
ApplicationInfo.FLAG_INSTALLED);
|
||||
mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */,
|
||||
true /* isChannelBlocked */);
|
||||
|
||||
final Slice slice = mNotificationChannelSlice.getSlice();
|
||||
|
||||
final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
|
||||
assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.no_suggested_app));
|
||||
}
|
||||
|
||||
private void addMockPackageToPackageManager(boolean isRecentlyInstalled, int flags) {
|
||||
final ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
applicationInfo.name = APP_LABEL;
|
||||
@@ -294,8 +320,10 @@ public class NotificationChannelSliceTest {
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
private void mockNotificationBackend(int channelCount, int notificationCount, boolean banned) {
|
||||
final List<NotificationChannel> channels = buildNotificationChannel(channelCount);
|
||||
private void mockNotificationBackend(int channelCount, int notificationCount, boolean banned,
|
||||
boolean isChannelBlocked) {
|
||||
final List<NotificationChannel> channels = buildNotificationChannel(channelCount,
|
||||
isChannelBlocked);
|
||||
final AppRow appRow = buildAppRow(channelCount, notificationCount, banned);
|
||||
|
||||
doReturn(buildNotificationChannelGroups(channels)).when(mNotificationBackend).getGroups(
|
||||
@@ -308,6 +336,8 @@ public class NotificationChannelSliceTest {
|
||||
|
||||
private AppRow buildAppRow(int channelCount, int sentCount, boolean banned) {
|
||||
final AppRow appRow = new AppRow();
|
||||
appRow.pkg = PACKAGE_NAME;
|
||||
appRow.uid = UID;
|
||||
appRow.banned = banned;
|
||||
appRow.channelCount = channelCount;
|
||||
appRow.sentByApp = new NotificationsSentState();
|
||||
@@ -317,11 +347,12 @@ public class NotificationChannelSliceTest {
|
||||
return appRow;
|
||||
}
|
||||
|
||||
private List<NotificationChannel> buildNotificationChannel(int channelCount) {
|
||||
private List<NotificationChannel> buildNotificationChannel(int channelCount,
|
||||
boolean isChannelBlock) {
|
||||
final List<NotificationChannel> channels = new ArrayList<>();
|
||||
for (int i = 0; i < channelCount; i++) {
|
||||
channels.add(new NotificationChannel(CHANNEL_NAME_PREFIX + i, CHANNEL_NAME_PREFIX + i,
|
||||
IMPORTANCE_NONE));
|
||||
isChannelBlock ? IMPORTANCE_NONE : IMPORTANCE_LOW));
|
||||
}
|
||||
|
||||
return channels;
|
||||
@@ -369,4 +400,4 @@ public class NotificationChannelSliceTest {
|
||||
// Index 0: title; Index 1: summary.
|
||||
return rowSliceItems.get(1).getText();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,11 @@
|
||||
|
||||
package com.android.settings.homepage.contextualcards.slices;
|
||||
|
||||
import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_DEFERRED_SETUP;
|
||||
import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_FULL_WIDTH;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.Activity;
|
||||
@@ -118,34 +116,25 @@ public class SliceContextualCardRendererTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longClick_shouldFlipCard() {
|
||||
public void bindView_isPendingDismiss_shouldFlipToDismissalView() {
|
||||
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
|
||||
final View card = viewHolder.itemView.findViewById(R.id.slice_view);
|
||||
final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.view_flipper);
|
||||
final View dismissalView = viewHolder.itemView.findViewById(R.id.dismissal_view);
|
||||
mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
|
||||
final ContextualCard card = buildContextualCard(
|
||||
TEST_SLICE_URI).mutate().setIsPendingDismiss(true).build();
|
||||
|
||||
card.performLongClick();
|
||||
mRenderer.bindView(viewHolder, card);
|
||||
|
||||
assertThat(viewFlipper.getCurrentView()).isEqualTo(dismissalView);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longClick_deferredSetupCard_shouldNotBeClickable() {
|
||||
final RecyclerView.ViewHolder viewHolder = getDeferredSetupViewHolder();
|
||||
final View contentView = viewHolder.itemView.findViewById(R.id.content);
|
||||
mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
|
||||
|
||||
assertThat(contentView.isLongClickable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longClick_shouldAddViewHolderToSet() {
|
||||
public void bindView_isPendingDismiss_shouldAddViewHolderToSet() {
|
||||
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
|
||||
final View card = viewHolder.itemView.findViewById(R.id.slice_view);
|
||||
mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
|
||||
final ContextualCard card = buildContextualCard(
|
||||
TEST_SLICE_URI).mutate().setIsPendingDismiss(true).build();
|
||||
|
||||
card.performLongClick();
|
||||
mRenderer.bindView(viewHolder, card);
|
||||
|
||||
assertThat(mRenderer.mFlippedCardSet).contains(viewHolder);
|
||||
}
|
||||
@@ -153,12 +142,11 @@ public class SliceContextualCardRendererTest {
|
||||
@Test
|
||||
public void viewClick_keepCard_shouldFlipBackToSlice() {
|
||||
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
|
||||
final View card = viewHolder.itemView.findViewById(R.id.slice_view);
|
||||
final Button btnKeep = viewHolder.itemView.findViewById(R.id.keep);
|
||||
final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.view_flipper);
|
||||
mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
|
||||
viewFlipper.setDisplayedChild(1);
|
||||
|
||||
card.performLongClick();
|
||||
btnKeep.performClick();
|
||||
|
||||
assertThat(viewFlipper.getCurrentView()).isInstanceOf(SliceView.class);
|
||||
@@ -167,11 +155,10 @@ public class SliceContextualCardRendererTest {
|
||||
@Test
|
||||
public void viewClick_keepCard_shouldRemoveViewHolderFromSet() {
|
||||
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
|
||||
final View card = viewHolder.itemView.findViewById(R.id.slice_view);
|
||||
final Button btnKeep = viewHolder.itemView.findViewById(R.id.keep);
|
||||
mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
|
||||
mRenderer.mFlippedCardSet.add(viewHolder);
|
||||
|
||||
card.performLongClick();
|
||||
btnKeep.performClick();
|
||||
|
||||
assertThat(mRenderer.mFlippedCardSet).doesNotContain(viewHolder);
|
||||
@@ -180,14 +167,13 @@ public class SliceContextualCardRendererTest {
|
||||
@Test
|
||||
public void viewClick_removeCard_shouldRemoveViewHolderFromSet() {
|
||||
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
|
||||
final View card = viewHolder.itemView.findViewById(R.id.slice_view);
|
||||
final Button btnRemove = viewHolder.itemView.findViewById(R.id.remove);
|
||||
final ContextualCard contextualCard = buildContextualCard(TEST_SLICE_URI);
|
||||
mRenderer.bindView(viewHolder, contextualCard);
|
||||
doReturn(mController).when(mControllerRendererPool).getController(mActivity,
|
||||
ContextualCard.CardType.SLICE);
|
||||
mRenderer.mFlippedCardSet.add(viewHolder);
|
||||
|
||||
card.performLongClick();
|
||||
btnRemove.performClick();
|
||||
|
||||
assertThat(mRenderer.mFlippedCardSet).doesNotContain(viewHolder);
|
||||
@@ -196,7 +182,6 @@ public class SliceContextualCardRendererTest {
|
||||
@Test
|
||||
public void viewClick_removeCard_sliceLiveDataShouldRemoveObservers() {
|
||||
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
|
||||
final View card = viewHolder.itemView.findViewById(R.id.slice_view);
|
||||
final Button btnRemove = viewHolder.itemView.findViewById(R.id.remove);
|
||||
final ContextualCard contextualCard = buildContextualCard(TEST_SLICE_URI);
|
||||
mRenderer.mSliceLiveDataMap.put(TEST_SLICE_URI, mSliceLiveData);
|
||||
@@ -204,7 +189,6 @@ public class SliceContextualCardRendererTest {
|
||||
doReturn(mController).when(mControllerRendererPool).getController(mActivity,
|
||||
ContextualCard.CardType.SLICE);
|
||||
|
||||
card.performLongClick();
|
||||
btnRemove.performClick();
|
||||
|
||||
assertThat(mRenderer.mSliceLiveDataMap.get(TEST_SLICE_URI).hasObservers()).isFalse();
|
||||
@@ -213,11 +197,11 @@ public class SliceContextualCardRendererTest {
|
||||
@Test
|
||||
public void onStop_cardIsFlipped_shouldFlipBack() {
|
||||
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
|
||||
final View card = viewHolder.itemView.findViewById(R.id.slice_view);
|
||||
final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.view_flipper);
|
||||
mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
|
||||
viewFlipper.setDisplayedChild(1);
|
||||
mRenderer.mFlippedCardSet.add(viewHolder);
|
||||
|
||||
card.performLongClick();
|
||||
mRenderer.onStop();
|
||||
|
||||
assertThat(viewFlipper.getCurrentView()).isInstanceOf(SliceView.class);
|
||||
@@ -232,18 +216,6 @@ public class SliceContextualCardRendererTest {
|
||||
return mRenderer.createViewHolder(view, VIEW_TYPE_FULL_WIDTH);
|
||||
}
|
||||
|
||||
private RecyclerView.ViewHolder getDeferredSetupViewHolder() {
|
||||
final RecyclerView recyclerView = new RecyclerView(mActivity);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(mActivity));
|
||||
final View view = LayoutInflater.from(mActivity).inflate(VIEW_TYPE_DEFERRED_SETUP,
|
||||
recyclerView, false);
|
||||
final RecyclerView.ViewHolder viewHolder = spy(
|
||||
mRenderer.createViewHolder(view, VIEW_TYPE_DEFERRED_SETUP));
|
||||
doReturn(VIEW_TYPE_DEFERRED_SETUP).when(viewHolder).getItemViewType();
|
||||
|
||||
return viewHolder;
|
||||
}
|
||||
|
||||
private ContextualCard buildContextualCard(Uri sliceUri) {
|
||||
return new ContextualCard.Builder()
|
||||
.setName("test_name")
|
||||
|
||||
@@ -78,7 +78,7 @@ public class SliceFullCardRendererHelperTest {
|
||||
public void bindView_shouldSetScrollableToFalse() {
|
||||
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
|
||||
|
||||
mHelper.bindView(viewHolder, buildContextualCard(), buildSlice(), Collections.emptySet());
|
||||
mHelper.bindView(viewHolder, buildContextualCard(), buildSlice());
|
||||
|
||||
assertThat(((SliceViewHolder) viewHolder).sliceView.isScrollable()).isFalse();
|
||||
}
|
||||
@@ -88,7 +88,7 @@ public class SliceFullCardRendererHelperTest {
|
||||
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
|
||||
final ContextualCard card = buildContextualCard();
|
||||
|
||||
mHelper.bindView(viewHolder, card, buildSlice(), Collections.emptySet());
|
||||
mHelper.bindView(viewHolder, card, buildSlice());
|
||||
|
||||
assertThat(((SliceViewHolder) viewHolder).sliceView.getTag()).isEqualTo(card.getSliceUri());
|
||||
}
|
||||
@@ -97,7 +97,7 @@ public class SliceFullCardRendererHelperTest {
|
||||
public void bindView_shouldSetModeToLarge() {
|
||||
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
|
||||
|
||||
mHelper.bindView(viewHolder, buildContextualCard(), buildSlice(), Collections.emptySet());
|
||||
mHelper.bindView(viewHolder, buildContextualCard(), buildSlice());
|
||||
|
||||
assertThat(((SliceViewHolder) viewHolder).sliceView.getMode()).isEqualTo(
|
||||
SliceView.MODE_LARGE);
|
||||
@@ -107,7 +107,7 @@ public class SliceFullCardRendererHelperTest {
|
||||
public void bindView_shouldSetSlice() {
|
||||
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
|
||||
|
||||
mHelper.bindView(viewHolder, buildContextualCard(), buildSlice(), Collections.emptySet());
|
||||
mHelper.bindView(viewHolder, buildContextualCard(), buildSlice());
|
||||
|
||||
assertThat(((SliceViewHolder) viewHolder).sliceView.getSlice().getUri()).isEqualTo(
|
||||
TEST_SLICE_URI);
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.homepage.contextualcards.slices;
|
||||
|
||||
import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_DEFERRED_SETUP;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ViewFlipper;
|
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardRenderer;
|
||||
import com.android.settings.homepage.contextualcards.conditional.ConditionContextualCardRenderer.ConditionalCardHolder;
|
||||
import com.android.settings.homepage.contextualcards.slices.SliceDeferredSetupCardRendererHelper.DeferredSetupCardViewHolder;
|
||||
import com.android.settings.homepage.contextualcards.slices.SliceFullCardRendererHelper.SliceViewHolder;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.android.controller.ActivityController;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class SwipeDismissalDelegateTest {
|
||||
|
||||
@Mock
|
||||
private SwipeDismissalDelegate.Listener mDismissalDelegateListener;
|
||||
|
||||
private Activity mActivity;
|
||||
private RecyclerView mRecyclerView;
|
||||
private SwipeDismissalDelegate mDismissalDelegate;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
final ActivityController<Activity> activityController = Robolectric.buildActivity(
|
||||
Activity.class);
|
||||
mActivity = activityController.get();
|
||||
mActivity.setTheme(R.style.Theme_Settings_Home);
|
||||
activityController.create();
|
||||
mRecyclerView = new RecyclerView(mActivity);
|
||||
mRecyclerView.setLayoutManager(new LinearLayoutManager(mActivity));
|
||||
mDismissalDelegate = new SwipeDismissalDelegate(mActivity, mDismissalDelegateListener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMovementFlags_conditionalViewHolder_shouldDisableSwipe() {
|
||||
assertThat(mDismissalDelegate.getMovementFlags(mRecyclerView, getConditionalViewHolder()))
|
||||
.isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMovementFlags_deferredSetupViewHolder_shouldDisableSwipe() {
|
||||
assertThat(mDismissalDelegate.getMovementFlags(mRecyclerView, getDeferredSetupViewHolder()))
|
||||
.isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMovementFlags_dismissalView_shouldDisableSwipe() {
|
||||
final RecyclerView.ViewHolder holder = getSliceViewHolder();
|
||||
final ViewFlipper viewFlipper = holder.itemView.findViewById(R.id.view_flipper);
|
||||
viewFlipper.showNext();
|
||||
final View dismissalView = holder.itemView.findViewById(R.id.dismissal_view);
|
||||
|
||||
assertThat(viewFlipper.getCurrentView()).isEqualTo(dismissalView);
|
||||
assertThat(mDismissalDelegate.getMovementFlags(mRecyclerView, holder)).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMovementFlags_SliceViewHolder_shouldEnableSwipe() {
|
||||
final RecyclerView.ViewHolder holder = getSliceViewHolder();
|
||||
final ViewFlipper viewFlipper = holder.itemView.findViewById(R.id.view_flipper);
|
||||
viewFlipper.setDisplayedChild(0);
|
||||
final View sliceView = holder.itemView.findViewById(R.id.slice_view);
|
||||
|
||||
assertThat(viewFlipper.getCurrentView()).isEqualTo(sliceView);
|
||||
assertThat(mDismissalDelegate.getMovementFlags(mRecyclerView, getSliceViewHolder()))
|
||||
.isNotEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSwipe_shouldNotifyListener() {
|
||||
mDismissalDelegate.onSwiped(getSliceViewHolder(), 1);
|
||||
|
||||
verify(mDismissalDelegateListener).onSwiped(anyInt());
|
||||
}
|
||||
|
||||
private RecyclerView.ViewHolder getSliceViewHolder() {
|
||||
final View view = LayoutInflater.from(mActivity)
|
||||
.inflate(SliceContextualCardRenderer.VIEW_TYPE_FULL_WIDTH, mRecyclerView, false);
|
||||
final RecyclerView.ViewHolder viewHolder = spy(new SliceViewHolder(view));
|
||||
doReturn(SliceContextualCardRenderer.VIEW_TYPE_FULL_WIDTH).when(
|
||||
viewHolder).getItemViewType();
|
||||
|
||||
return viewHolder;
|
||||
}
|
||||
|
||||
private RecyclerView.ViewHolder getConditionalViewHolder() {
|
||||
final View view = LayoutInflater.from(mActivity)
|
||||
.inflate(ConditionContextualCardRenderer.VIEW_TYPE_FULL_WIDTH, mRecyclerView,
|
||||
false);
|
||||
final RecyclerView.ViewHolder viewHolder = spy(new ConditionalCardHolder(view));
|
||||
doReturn(ConditionContextualCardRenderer.VIEW_TYPE_FULL_WIDTH).when(
|
||||
viewHolder).getItemViewType();
|
||||
|
||||
return viewHolder;
|
||||
}
|
||||
|
||||
private RecyclerView.ViewHolder getDeferredSetupViewHolder() {
|
||||
final View view = LayoutInflater.from(mActivity)
|
||||
.inflate(VIEW_TYPE_DEFERRED_SETUP, mRecyclerView, false);
|
||||
final RecyclerView.ViewHolder viewHolder = spy(new DeferredSetupCardViewHolder(view));
|
||||
doReturn(VIEW_TYPE_DEFERRED_SETUP).when(viewHolder).getItemViewType();
|
||||
|
||||
return viewHolder;
|
||||
}
|
||||
}
|
||||
@@ -17,35 +17,29 @@
|
||||
|
||||
package com.android.settings.media;
|
||||
|
||||
import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_INDICATOR_SLICE_URI;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.SliceItem;
|
||||
import androidx.slice.SliceMetadata;
|
||||
import androidx.slice.SliceProvider;
|
||||
import androidx.slice.core.SliceAction;
|
||||
import androidx.slice.widget.SliceLiveData;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
|
||||
import com.android.settingslib.media.LocalMediaManager;
|
||||
import com.android.settingslib.media.MediaDevice;
|
||||
import com.android.settingslib.media.MediaOutputSliceConstants;
|
||||
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
|
||||
import com.android.settingslib.bluetooth.A2dpProfile;
|
||||
import com.android.settingslib.bluetooth.HearingAidProfile;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
@@ -53,59 +47,108 @@ import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadow.api.Shadow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowBluetoothAdapter.class})
|
||||
@Ignore("b/129292771")
|
||||
@Config(shadows = {ShadowBluetoothUtils.class})
|
||||
public class MediaOutputIndicatorSliceTest {
|
||||
|
||||
private static final String TEST_DEVICE_NAME = "test_device_name";
|
||||
private static final int TEST_DEVICE_1_ICON =
|
||||
com.android.internal.R.drawable.ic_bt_headphones_a2dp;
|
||||
private static final String TEST_A2DP_DEVICE_NAME = "Test_A2DP_BT_Device_NAME";
|
||||
private static final String TEST_HAP_DEVICE_NAME = "Test_HAP_BT_Device_NAME";
|
||||
private static final String TEST_A2DP_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
|
||||
private static final String TEST_HAP_DEVICE_ADDRESS = "00:B2:B2:B2:B2:B2";
|
||||
|
||||
@Mock
|
||||
private LocalMediaManager mLocalMediaManager;
|
||||
|
||||
private final List<MediaDevice> mDevices = new ArrayList<>();
|
||||
private A2dpProfile mA2dpProfile;
|
||||
@Mock
|
||||
private HearingAidProfile mHearingAidProfile;
|
||||
@Mock
|
||||
private LocalBluetoothManager mLocalBluetoothManager;
|
||||
@Mock
|
||||
private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
|
||||
|
||||
private BluetoothAdapter mBluetoothAdapter;
|
||||
private BluetoothDevice mA2dpDevice;
|
||||
private BluetoothDevice mHapDevice;
|
||||
private BluetoothManager mBluetoothManager;
|
||||
private Context mContext;
|
||||
private List<BluetoothDevice> mDevicesList;
|
||||
private MediaOutputIndicatorSlice mMediaOutputIndicatorSlice;
|
||||
private MediaOutputIndicatorWorker mMediaOutputIndicatorWorker;
|
||||
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
|
||||
// Set-up specs for SliceMetadata.
|
||||
SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
|
||||
|
||||
// Setup Bluetooth environment
|
||||
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
|
||||
mBluetoothManager = new BluetoothManager(mContext);
|
||||
mBluetoothAdapter = mBluetoothManager.getAdapter();
|
||||
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
|
||||
when(mLocalBluetoothProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
|
||||
when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
|
||||
|
||||
// Setup A2dp device
|
||||
mA2dpDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_A2DP_DEVICE_ADDRESS));
|
||||
when(mA2dpDevice.getName()).thenReturn(TEST_A2DP_DEVICE_NAME);
|
||||
when(mA2dpDevice.isConnected()).thenReturn(true);
|
||||
// Setup HearingAid device
|
||||
mHapDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_HAP_DEVICE_ADDRESS));
|
||||
when(mHapDevice.getName()).thenReturn(TEST_HAP_DEVICE_NAME);
|
||||
when(mHapDevice.isConnected()).thenReturn(true);
|
||||
|
||||
mMediaOutputIndicatorSlice = new MediaOutputIndicatorSlice(mContext);
|
||||
mMediaOutputIndicatorWorker = spy(new MediaOutputIndicatorWorker(
|
||||
mContext, MEDIA_OUTPUT_INDICATOR_SLICE_URI));
|
||||
mMediaOutputIndicatorSlice.mWorker = mMediaOutputIndicatorWorker;
|
||||
mDevicesList = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSlice_invisible_returnNull() {
|
||||
when(mMediaOutputIndicatorWorker.isVisible()).thenReturn(false);
|
||||
public void getSlice_noConnectableDevice_returnNull() {
|
||||
mDevicesList.clear();
|
||||
when(mA2dpProfile.getConnectableDevices()).thenReturn(mDevicesList);
|
||||
|
||||
assertThat(mMediaOutputIndicatorSlice.getSlice()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSlice_withActiveDevice_checkContent() {
|
||||
when(mMediaOutputIndicatorWorker.isVisible()).thenReturn(true);
|
||||
when(mMediaOutputIndicatorWorker.findActiveDeviceName()).thenReturn(TEST_DEVICE_NAME);
|
||||
public void getSlice_noActiveDevice_verifyDefaultName() {
|
||||
mDevicesList.add(mA2dpDevice);
|
||||
when(mA2dpProfile.getConnectableDevices()).thenReturn(mDevicesList);
|
||||
when(mA2dpProfile.getActiveDevice()).thenReturn(null);
|
||||
|
||||
// Verify slice title and subtitle
|
||||
final Slice mediaSlice = mMediaOutputIndicatorSlice.getSlice();
|
||||
final SliceMetadata metadata = SliceMetadata.from(mContext, mediaSlice);
|
||||
// Verify slice title and subtitle
|
||||
assertThat(metadata.getTitle()).isEqualTo(mContext.getText(R.string.media_output_title));
|
||||
assertThat(metadata.getSubtitle()).isEqualTo(TEST_DEVICE_NAME);
|
||||
assertThat(metadata.getSubtitle()).isEqualTo(mContext.getText(
|
||||
R.string.media_output_default_summary));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSlice_A2dpDeviceActive_verifyName() {
|
||||
mDevicesList.add(mA2dpDevice);
|
||||
when(mA2dpProfile.getConnectableDevices()).thenReturn(mDevicesList);
|
||||
when(mA2dpProfile.getActiveDevice()).thenReturn(mA2dpDevice);
|
||||
|
||||
final Slice mediaSlice = mMediaOutputIndicatorSlice.getSlice();
|
||||
final SliceMetadata metadata = SliceMetadata.from(mContext, mediaSlice);
|
||||
assertThat(metadata.getTitle()).isEqualTo(mContext.getText(R.string.media_output_title));
|
||||
assertThat(metadata.getSubtitle()).isEqualTo(TEST_A2DP_DEVICE_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSlice_HADeviceActive_verifyName() {
|
||||
mDevicesList.add(mHapDevice);
|
||||
when(mHearingAidProfile.getConnectableDevices()).thenReturn(mDevicesList);
|
||||
when(mHearingAidProfile.getActiveDevices()).thenReturn(mDevicesList);
|
||||
|
||||
// Verify slice title and subtitle
|
||||
final Slice mediaSlice = mMediaOutputIndicatorSlice.getSlice();
|
||||
final SliceMetadata metadata = SliceMetadata.from(mContext, mediaSlice);
|
||||
assertThat(metadata.getTitle()).isEqualTo(mContext.getText(R.string.media_output_title));
|
||||
assertThat(metadata.getSubtitle()).isEqualTo(TEST_HAP_DEVICE_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,28 +16,18 @@
|
||||
|
||||
package com.android.settings.media;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.bluetooth.Utils;
|
||||
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
|
||||
import com.android.settingslib.bluetooth.A2dpProfile;
|
||||
import com.android.settingslib.bluetooth.BluetoothEventManager;
|
||||
import com.android.settingslib.bluetooth.HearingAidProfile;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
@@ -45,119 +35,38 @@ import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowBluetoothDevice;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowBluetoothUtils.class,
|
||||
ShadowBluetoothDevice.class})
|
||||
@Ignore("b/129292771")
|
||||
@Config(shadows = {ShadowBluetoothUtils.class})
|
||||
public class MediaOutputIndicatorWorkerTest {
|
||||
|
||||
private static final String TEST_A2DP_DEVICE_NAME = "Test_A2DP_BT_Device_NAME";
|
||||
private static final String TEST_HAP_DEVICE_NAME = "Test_HAP_BT_Device_NAME";
|
||||
private static final String TEST_A2DP_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
|
||||
private static final String TEST_HAP_DEVICE_ADDRESS = "00:B2:B2:B2:B2:B2";
|
||||
private static final Uri URI = Uri.parse("content://com.android.settings.slices/test");
|
||||
|
||||
@Mock
|
||||
private A2dpProfile mA2dpProfile;
|
||||
@Mock
|
||||
private HearingAidProfile mHearingAidProfile;
|
||||
@Mock
|
||||
private LocalBluetoothManager mLocalManager;
|
||||
@Mock
|
||||
private BluetoothEventManager mBluetoothEventManager;
|
||||
@Mock
|
||||
private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
|
||||
|
||||
private BluetoothAdapter mBluetoothAdapter;
|
||||
private BluetoothDevice mA2dpDevice;
|
||||
private BluetoothDevice mHapDevice;
|
||||
private BluetoothManager mBluetoothManager;
|
||||
private Context mContext;
|
||||
private List<BluetoothDevice> mDevicesList;
|
||||
private LocalBluetoothManager mLocalBluetoothManager;
|
||||
private Context mContext;
|
||||
private MediaOutputIndicatorWorker mMediaDeviceUpdateWorker;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalManager;
|
||||
mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
|
||||
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
|
||||
when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager);
|
||||
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
|
||||
when(mLocalBluetoothProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
|
||||
when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
|
||||
mBluetoothManager = new BluetoothManager(mContext);
|
||||
mBluetoothAdapter = mBluetoothManager.getAdapter();
|
||||
|
||||
// Setup A2dp device
|
||||
mA2dpDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_A2DP_DEVICE_ADDRESS));
|
||||
when(mA2dpDevice.getName()).thenReturn(TEST_A2DP_DEVICE_NAME);
|
||||
when(mA2dpDevice.isConnected()).thenReturn(true);
|
||||
// Setup HearingAid device
|
||||
mHapDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_HAP_DEVICE_ADDRESS));
|
||||
when(mHapDevice.getName()).thenReturn(TEST_HAP_DEVICE_NAME);
|
||||
when(mHapDevice.isConnected()).thenReturn(true);
|
||||
|
||||
mMediaDeviceUpdateWorker = new MediaOutputIndicatorWorker(mContext, URI);
|
||||
mDevicesList = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isVisible_noConnectableDevice_returnFalse() {
|
||||
mDevicesList.clear();
|
||||
when(mA2dpProfile.getConnectableDevices()).thenReturn(mDevicesList);
|
||||
|
||||
assertThat(mMediaDeviceUpdateWorker.isVisible()).isFalse();
|
||||
public void onSlicePinned_registerCallback() {
|
||||
mMediaDeviceUpdateWorker.onSlicePinned();
|
||||
verify(mBluetoothEventManager).registerCallback(mMediaDeviceUpdateWorker);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isVisible_withConnectableA2dpDevice_returnTrue() {
|
||||
mDevicesList.clear();
|
||||
mDevicesList.add(mA2dpDevice);
|
||||
when(mHearingAidProfile.getConnectableDevices()).thenReturn(mDevicesList);
|
||||
|
||||
assertThat(mMediaDeviceUpdateWorker.isVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isVisible_withConnectableHADevice_returnTrue() {
|
||||
mDevicesList.clear();
|
||||
mDevicesList.add(mHapDevice);
|
||||
when(mA2dpProfile.getConnectableDevices()).thenReturn(mDevicesList);
|
||||
|
||||
assertThat(mMediaDeviceUpdateWorker.isVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findActiveDeviceName_A2dpDeviceActive_verifyName() {
|
||||
when(mA2dpProfile.getActiveDevice()).thenReturn(mA2dpDevice);
|
||||
|
||||
assertThat(mMediaDeviceUpdateWorker.findActiveDeviceName())
|
||||
.isEqualTo(mA2dpDevice.getAliasName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findActiveDeviceName_HADeviceActive_verifyName() {
|
||||
mDevicesList.add(mHapDevice);
|
||||
when(mHearingAidProfile.getActiveDevices()).thenReturn(mDevicesList);
|
||||
|
||||
assertThat(mMediaDeviceUpdateWorker.findActiveDeviceName())
|
||||
.isEqualTo(mHapDevice.getAliasName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findActiveDeviceName_noActiveDevice_verifyDefaultName() {
|
||||
when(mA2dpProfile.getActiveDevice()).thenReturn(null);
|
||||
mDevicesList.clear();
|
||||
when(mHearingAidProfile.getActiveDevices()).thenReturn(mDevicesList);
|
||||
|
||||
assertThat(mMediaDeviceUpdateWorker.findActiveDeviceName())
|
||||
.isEqualTo(mContext.getText(R.string.media_output_default_summary));
|
||||
public void onSliceUnpinned_unRegisterCallback() {
|
||||
mMediaDeviceUpdateWorker.onSlicePinned();
|
||||
mMediaDeviceUpdateWorker.onSliceUnpinned();
|
||||
verify(mBluetoothEventManager).unregisterCallback(mMediaDeviceUpdateWorker);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||
import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
@@ -223,6 +224,7 @@ public class BubblePreferenceControllerTest {
|
||||
@Test
|
||||
public void testUpdateState_app() {
|
||||
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||
appRow.label = "App!";
|
||||
appRow.allowBubbles = true;
|
||||
mController.onResume(appRow, null, null, null);
|
||||
|
||||
@@ -235,6 +237,9 @@ public class BubblePreferenceControllerTest {
|
||||
|
||||
mController.updateState(pref);
|
||||
assertFalse(pref.isChecked());
|
||||
|
||||
assertNotNull(pref.getSummary());
|
||||
assertTrue(pref.getSummary().toString().contains(appRow.label));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.notification;
|
||||
|
||||
import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
|
||||
|
||||
import static com.android.settings.notification.BadgingNotificationPreferenceController.OFF;
|
||||
import static com.android.settings.notification.BadgingNotificationPreferenceController.ON;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class BubbleSummaryNotificationPreferenceControllerTest {
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private BubbleSummaryNotificationPreferenceController mController;
|
||||
private Preference mPreference;
|
||||
|
||||
private static final String KEY_NOTIFICATION_BUBBLES = "notification_bubbles";
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mController = new BubbleSummaryNotificationPreferenceController(mContext,
|
||||
KEY_NOTIFICATION_BUBBLES);
|
||||
mPreference = new Preference(RuntimeEnvironment.application);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void display_shouldDisplay() {
|
||||
assertThat(mPreference.isVisible()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSummary() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, OFF);
|
||||
|
||||
assertThat(mController.getSummary()).isEqualTo("Off");
|
||||
|
||||
Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, ON);
|
||||
|
||||
assertThat(mController.getSummary()).isEqualTo("On");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.notification;
|
||||
|
||||
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
|
||||
import static android.app.NotificationManager.IMPORTANCE_HIGH;
|
||||
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||
import static android.provider.Settings.Secure.NOTIFICATION_BUBBLES;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
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.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
import com.android.settingslib.RestrictedSwitchPreference;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.shadows.ShadowApplication;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class BubbleSummaryPreferenceControllerTest {
|
||||
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private NotificationBackend mBackend;
|
||||
|
||||
private BubbleSummaryPreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mController = spy(new BubbleSummaryPreferenceController(mContext, mBackend));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoCrashIfNoOnResume() {
|
||||
mController.isAvailable();
|
||||
mController.updateState(mock(Preference.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAvailable_notIfAppBlocked() {
|
||||
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||
appRow.banned = true;
|
||||
mController.onResume(appRow, mock(NotificationChannel.class), null, null);
|
||||
assertFalse(mController.isAvailable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAvailable_notIfOffGlobally() {
|
||||
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||
NotificationChannel channel = mock(NotificationChannel.class);
|
||||
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
|
||||
mController.onResume(appRow, channel, null, null);
|
||||
Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, 0);
|
||||
|
||||
assertFalse(mController.isAvailable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAvailable_app() {
|
||||
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||
mController.onResume(appRow, null, null, null);
|
||||
Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, 1);
|
||||
|
||||
assertTrue(mController.isAvailable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAvailable_defaultChannel() {
|
||||
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||
appRow.allowBubbles = true;
|
||||
NotificationChannel channel = mock(NotificationChannel.class);
|
||||
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
|
||||
when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
|
||||
mController.onResume(appRow, channel, null, null);
|
||||
Settings.Secure.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, 1);
|
||||
|
||||
assertTrue(mController.isAvailable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateState() {
|
||||
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||
appRow.allowBubbles = true;
|
||||
mController.onResume(appRow, null, null, null);
|
||||
|
||||
Preference pref = new Preference(mContext);
|
||||
mController.updateState(pref);
|
||||
assertNotNull(pref.getIntent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSummary() {
|
||||
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||
appRow.allowBubbles = true;
|
||||
mController.onResume(appRow, null, null, null);
|
||||
|
||||
assertEquals("On", mController.getSummary());
|
||||
|
||||
appRow.allowBubbles = false;
|
||||
mController.onResume(appRow, null, null, null);
|
||||
|
||||
assertEquals("Off", mController.getSummary());
|
||||
}
|
||||
}
|
||||
@@ -317,6 +317,30 @@ public class NotificationPreferenceControllerTest {
|
||||
assertTrue(mController.isChannelGroupBlockable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsChannelBlockable_oemLocked() {
|
||||
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||
appRow.systemApp = false;
|
||||
NotificationChannel channel = mock(NotificationChannel.class);
|
||||
when(channel.isImportanceLockedByOEM()).thenReturn(true);
|
||||
when(channel.getImportance()).thenReturn(IMPORTANCE_DEFAULT);
|
||||
|
||||
mController.onResume(appRow, channel, null, null);
|
||||
assertFalse(mController.isChannelBlockable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsChannelBlockable_criticalDeviceFunction() {
|
||||
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||
appRow.systemApp = false;
|
||||
NotificationChannel channel = mock(NotificationChannel.class);
|
||||
when(channel.isImportanceLockedByCriticalDeviceFunction()).thenReturn(true);
|
||||
when(channel.getImportance()).thenReturn(IMPORTANCE_DEFAULT);
|
||||
|
||||
mController.onResume(appRow, channel, null, null);
|
||||
assertFalse(mController.isChannelBlockable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsChannelGroupBlockable_SystemNotBlockable() {
|
||||
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||
|
||||
@@ -39,6 +39,8 @@ import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
@@ -54,6 +56,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.Robolectric;
|
||||
@@ -230,6 +233,69 @@ public class SoundPreferenceControllerTest {
|
||||
verify(mFragment, times(1)).startActivityForResult(any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnPreferenceTreeClick_alarmSound() {
|
||||
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH);
|
||||
channel.setSound(null, new AudioAttributes.Builder().setUsage(
|
||||
AudioAttributes.USAGE_ALARM).build());
|
||||
mController.onResume(appRow, channel, null, null);
|
||||
|
||||
AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
|
||||
NotificationSoundPreference pref =
|
||||
spy(new NotificationSoundPreference(mContext, attributeSet));
|
||||
pref.setKey(mController.getPreferenceKey());
|
||||
mController.handlePreferenceTreeClick(pref);
|
||||
|
||||
ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(pref, times(1)).onPrepareRingtonePickerIntent(intentArgumentCaptor.capture());
|
||||
assertEquals(RingtoneManager.TYPE_ALARM,
|
||||
intentArgumentCaptor.getValue().getIntExtra(
|
||||
RingtoneManager.EXTRA_RINGTONE_TYPE, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnPreferenceTreeClick_ringtoneSound() {
|
||||
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH);
|
||||
channel.setSound(null, new AudioAttributes.Builder().setUsage(
|
||||
AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build());
|
||||
mController.onResume(appRow, channel, null, null);
|
||||
|
||||
AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
|
||||
NotificationSoundPreference pref =
|
||||
spy(new NotificationSoundPreference(mContext, attributeSet));
|
||||
pref.setKey(mController.getPreferenceKey());
|
||||
mController.handlePreferenceTreeClick(pref);
|
||||
|
||||
ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(pref, times(1)).onPrepareRingtonePickerIntent(intentArgumentCaptor.capture());
|
||||
assertEquals(RingtoneManager.TYPE_RINGTONE,
|
||||
intentArgumentCaptor.getValue().getIntExtra(
|
||||
RingtoneManager.EXTRA_RINGTONE_TYPE, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnPreferenceTreeClick_otherSound() {
|
||||
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
|
||||
NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH);
|
||||
channel.setSound(null, new AudioAttributes.Builder().setUsage(
|
||||
AudioAttributes.USAGE_UNKNOWN).build());
|
||||
mController.onResume(appRow, channel, null, null);
|
||||
|
||||
AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
|
||||
NotificationSoundPreference pref =
|
||||
spy(new NotificationSoundPreference(mContext, attributeSet));
|
||||
pref.setKey(mController.getPreferenceKey());
|
||||
mController.handlePreferenceTreeClick(pref);
|
||||
|
||||
ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(pref, times(1)).onPrepareRingtonePickerIntent(intentArgumentCaptor.capture());
|
||||
assertEquals(RingtoneManager.TYPE_NOTIFICATION,
|
||||
intentArgumentCaptor.getValue().getIntExtra(
|
||||
RingtoneManager.EXTRA_RINGTONE_TYPE, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnActivityResult() {
|
||||
NotificationSoundPreference pref = mock(NotificationSoundPreference.class);
|
||||
|
||||
@@ -16,6 +16,14 @@
|
||||
|
||||
package com.android.settings.privacy;
|
||||
|
||||
import static android.Manifest.permission_group.CALENDAR;
|
||||
import static android.Manifest.permission_group.CAMERA;
|
||||
import static android.Manifest.permission_group.CONTACTS;
|
||||
import static android.Manifest.permission_group.LOCATION;
|
||||
import static android.Manifest.permission_group.MICROPHONE;
|
||||
import static android.Manifest.permission_group.PHONE;
|
||||
import static android.Manifest.permission_group.SMS;
|
||||
|
||||
import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
|
||||
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
|
||||
|
||||
@@ -221,4 +229,27 @@ public class PermissionBarChartPreferenceControllerTest {
|
||||
verify(mFragment).setLoadingEnabled(false /* enabled */);
|
||||
verify(mPreference).updateLoadingState(false /* isLoading */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPermissionUsageResult_shouldBeSorted() {
|
||||
final List<RuntimePermissionUsageInfo> infos = new ArrayList<>();
|
||||
infos.add(new RuntimePermissionUsageInfo(PHONE, 10));
|
||||
infos.add(new RuntimePermissionUsageInfo(LOCATION, 10));
|
||||
infos.add(new RuntimePermissionUsageInfo(CAMERA, 10));
|
||||
infos.add(new RuntimePermissionUsageInfo(SMS, 1));
|
||||
infos.add(new RuntimePermissionUsageInfo(MICROPHONE, 10));
|
||||
infos.add(new RuntimePermissionUsageInfo(CONTACTS, 42));
|
||||
infos.add(new RuntimePermissionUsageInfo(CALENDAR, 10));
|
||||
mController.displayPreference(mScreen);
|
||||
|
||||
mController.onPermissionUsageResult(infos);
|
||||
|
||||
assertThat(infos.get(0).getName()).isEqualTo(CONTACTS);
|
||||
assertThat(infos.get(1).getName()).isEqualTo(LOCATION);
|
||||
assertThat(infos.get(2).getName()).isEqualTo(MICROPHONE);
|
||||
assertThat(infos.get(3).getName()).isEqualTo(CAMERA);
|
||||
assertThat(infos.get(4).getName()).isEqualTo(CALENDAR);
|
||||
assertThat(infos.get(5).getName()).isEqualTo(PHONE);
|
||||
assertThat(infos.get(6).getName()).isEqualTo(SMS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,17 @@ package com.android.settings.system;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.settings.aware.AwareFeatureProvider;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.XmlTestUtils;
|
||||
import com.android.settings.testutils.shadow.SettingsShadowResources;
|
||||
import com.android.settings.testutils.shadow.ShadowUserManager;
|
||||
@@ -38,11 +47,17 @@ import java.util.List;
|
||||
@Config(shadows = {SettingsShadowResources.class, ShadowUserManager.class})
|
||||
public class SystemDashboardFragmentTest {
|
||||
|
||||
private Context mContext;
|
||||
private SystemDashboardFragment mFragment;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
SettingsShadowResources.overrideResource(
|
||||
com.android.internal.R.bool.config_supportSystemNavigationKeys, true);
|
||||
ShadowUserManager.getShadow().setIsAdminUser(true);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mFragment = spy(new SystemDashboardFragment());
|
||||
when(mFragment.getContext()).thenReturn(mContext);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -52,13 +67,35 @@ public class SystemDashboardFragmentTest {
|
||||
|
||||
@Test
|
||||
public void testNonIndexableKeys_existInXmlLayout() {
|
||||
final Context context = RuntimeEnvironment.application;
|
||||
final List<String> niks = SystemDashboardFragment.SEARCH_INDEX_DATA_PROVIDER
|
||||
.getNonIndexableKeys(context);
|
||||
.getNonIndexableKeys(mContext);
|
||||
final int xmlId = (new SystemDashboardFragment()).getPreferenceScreenResId();
|
||||
|
||||
final List<String> keys = XmlTestUtils.getKeysFromPreferenceXml(context, xmlId);
|
||||
final List<String> keys = XmlTestUtils.getKeysFromPreferenceXml(mContext, xmlId);
|
||||
|
||||
assertThat(keys).containsAllIn(niks);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showRestrictionDialog_hasValidExtra_shouldShowDialog() {
|
||||
final AwareFeatureProvider mProvider =
|
||||
FakeFeatureFactory.setupForTest().mAwareFeatureProvider;
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putBoolean(SystemDashboardFragment.EXTRA_SHOW_AWARE_DISABLED, true);
|
||||
when(mFragment.getArguments()).thenReturn(bundle);
|
||||
|
||||
mFragment.showRestrictionDialog();
|
||||
|
||||
verify(mProvider).showRestrictionDialog(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void showRestrictionDialog_hasInvalidExtra_shouldNotShowDialog() {
|
||||
final AwareFeatureProvider mProvider =
|
||||
FakeFeatureFactory.setupForTest().mAwareFeatureProvider;
|
||||
|
||||
mFragment.showRestrictionDialog();
|
||||
|
||||
verify(mProvider, never()).showRestrictionDialog(any());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.os.UserManager.EnforcingUser;
|
||||
|
||||
import com.google.android.collect.Maps;
|
||||
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
@@ -48,6 +50,7 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager
|
||||
private boolean mIsQuietModeEnabled = false;
|
||||
private int[] profileIdsForUser = new int[0];
|
||||
private boolean mUserSwitchEnabled;
|
||||
private final Map<Integer, Integer> mSameProfileGroupIds = Maps.newHashMap();
|
||||
|
||||
public void addProfile(UserInfo userInfo) {
|
||||
mUserProfileInfos.add(userInfo);
|
||||
@@ -138,6 +141,18 @@ public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager
|
||||
return sIsSupportsMultipleUsers;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected boolean isSameProfileGroup(@UserIdInt int userId, int otherUserId) {
|
||||
return mSameProfileGroupIds.containsKey(userId)
|
||||
&& mSameProfileGroupIds.get(userId) == otherUserId
|
||||
|| mSameProfileGroupIds.containsKey(otherUserId)
|
||||
&& mSameProfileGroupIds.get(otherUserId) == userId;
|
||||
}
|
||||
|
||||
public Map<Integer, Integer> getSameProfileGroupIds() {
|
||||
return mSameProfileGroupIds;
|
||||
}
|
||||
|
||||
public void setSupportsMultipleUsers(boolean supports) {
|
||||
sIsSupportsMultipleUsers = supports;
|
||||
}
|
||||
|
||||
@@ -105,6 +105,7 @@ public class WifiDetailPreferenceControllerTest {
|
||||
private static final int RSSI = -55;
|
||||
private static final int TX_LINK_SPEED = 123;
|
||||
private static final int RX_LINK_SPEED = 54;
|
||||
private static final String SSID = "ssid";
|
||||
private static final String MAC_ADDRESS = WifiInfo.DEFAULT_MAC_ADDRESS;
|
||||
private static final String SECURITY = "None";
|
||||
|
||||
@@ -154,6 +155,8 @@ public class WifiDetailPreferenceControllerTest {
|
||||
@Mock
|
||||
private Preference mockSecurityPref;
|
||||
@Mock
|
||||
private Preference mockSsidPref;
|
||||
@Mock
|
||||
private Preference mockMacAddressPref;
|
||||
@Mock
|
||||
private Preference mockIpAddressPref;
|
||||
@@ -245,6 +248,7 @@ public class WifiDetailPreferenceControllerTest {
|
||||
when(mockAccessPoint.getConfig()).thenReturn(mockWifiConfig);
|
||||
when(mockAccessPoint.getLevel()).thenReturn(LEVEL);
|
||||
when(mockAccessPoint.getSecurityString(false)).thenReturn(SECURITY);
|
||||
when(mockAccessPoint.getSsidStr()).thenReturn(SSID);
|
||||
when(mockConnectivityManager.getNetworkInfo(any(Network.class)))
|
||||
.thenReturn(mockNetworkInfo);
|
||||
doNothing().when(mockConnectivityManager).registerNetworkCallback(
|
||||
@@ -314,6 +318,8 @@ public class WifiDetailPreferenceControllerTest {
|
||||
.thenReturn(mockFrequencyPref);
|
||||
when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_SECURITY_PREF))
|
||||
.thenReturn(mockSecurityPref);
|
||||
when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_SSID_PREF))
|
||||
.thenReturn(mockSsidPref);
|
||||
when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_MAC_ADDRESS_PREF))
|
||||
.thenReturn(mockMacAddressPref);
|
||||
when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IP_ADDRESS_PREF))
|
||||
@@ -462,6 +468,50 @@ public class WifiDetailPreferenceControllerTest {
|
||||
verify(mockRxLinkSpeedPref).setVisible(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ssidPref_shouldHaveDetailTextSet() {
|
||||
when(mockAccessPoint.isPasspoint()).thenReturn(true);
|
||||
when(mockAccessPoint.isOsuProvider()).thenReturn(false);
|
||||
|
||||
displayAndResume();
|
||||
|
||||
verify(mockSsidPref, times(1)).setSummary(SSID);
|
||||
|
||||
when(mockAccessPoint.isPasspoint()).thenReturn(false);
|
||||
when(mockAccessPoint.isOsuProvider()).thenReturn(true);
|
||||
|
||||
displayAndResume();
|
||||
|
||||
verify(mockSsidPref, times(2)).setSummary(SSID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ssidPref_shouldShowIfPasspointOrOsu() {
|
||||
when(mockAccessPoint.isPasspoint()).thenReturn(true);
|
||||
when(mockAccessPoint.isOsuProvider()).thenReturn(false);
|
||||
|
||||
displayAndResume();
|
||||
|
||||
verify(mockSsidPref, times(1)).setVisible(true);
|
||||
|
||||
when(mockAccessPoint.isPasspoint()).thenReturn(false);
|
||||
when(mockAccessPoint.isOsuProvider()).thenReturn(true);
|
||||
|
||||
displayAndResume();
|
||||
|
||||
verify(mockSsidPref, times(2)).setVisible(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ssidPref_shouldNotShowIfNotPasspoint() {
|
||||
when(mockAccessPoint.isPasspoint()).thenReturn(false);
|
||||
when(mockAccessPoint.isOsuProvider()).thenReturn(false);
|
||||
|
||||
displayAndResume();
|
||||
|
||||
verify(mockSsidPref).setVisible(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void macAddressPref_shouldHaveDetailTextSet() {
|
||||
displayAndResume();
|
||||
|
||||
@@ -109,4 +109,20 @@ public class WifiPrivacyPreferenceControllerTest {
|
||||
|
||||
assertThat(mDropDownPreference.isSelectable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateState_isNotPasspointNetwork_shouldBeSelectable() {
|
||||
mPreferenceController.setIsPasspoint(false);
|
||||
mPreferenceController.updateState(mDropDownPreference);
|
||||
|
||||
assertThat(mDropDownPreference.isSelectable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateState_isPasspointNetwork_shouldNotSelectable() {
|
||||
mPreferenceController.setIsPasspoint(true);
|
||||
mPreferenceController.updateState(mDropDownPreference);
|
||||
|
||||
assertThat(mDropDownPreference.isSelectable()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user