Snap for 5422062 from 299a04c59b to qt-release

Change-Id: Ia15c10f0820164fc5db00fcef087cbabe50dafcd
This commit is contained in:
android-build-team Robot
2019-03-30 23:24:53 +00:00
93 changed files with 1870 additions and 661 deletions

View File

@@ -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>

View File

@@ -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"

View File

@@ -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

View File

@@ -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"

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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">

View File

@@ -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

View File

@@ -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

View 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>

View File

@@ -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"

View 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>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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"

View File

@@ -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 */ }

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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)) {

View File

@@ -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);
}
}
}

View File

@@ -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);
}

View File

@@ -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) {
}
}

View File

@@ -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(),

View File

@@ -39,4 +39,9 @@ public class DeviceModelPreferenceController extends HardwareInfoPreferenceContr
public boolean isSliceable() {
return true;
}
@Override
public CharSequence getSummary() {
return HardwareInfoPreferenceController.getDeviceModel();
}
}

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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());
});
}

View File

@@ -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;

View File

@@ -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());
});
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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));
}
};
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}
};
}

View File

@@ -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));
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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);
});
}

View File

@@ -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 "

View File

@@ -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

View File

@@ -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

View File

@@ -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)) {

View File

@@ -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;
}
};
}

View File

@@ -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;
}
};
}

View File

@@ -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

View File

@@ -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

View File

@@ -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());

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -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>

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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());
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}
}

View File

@@ -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")

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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");
}
}

View File

@@ -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());
}
}

View File

@@ -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();

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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());
}
}

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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();
}
}