Merge "Create a config flag for the new Screen Timeout settings screen with Dashboard style settings" into main
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b62df60..8c9045d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -33,9 +33,9 @@
<string name="device_info_protected_single_press">Tap to show info</string>
<!-- [CHAR LIMIT=NONE] Device Info screen. Countdown for user taps to enable development settings -->
<string name="show_dev_countdown">{count, plural,
- =1 {You are now # step away from being a developer.}
- other {You are now # steps away from being a developer.}
- }</string>
+ =1 {You are now # step away from being a developer.}
+ other {You are now # steps away from being a developer.}
+ }</string>
<!-- [CHAR LIMIT=NONE] Device Info screen. Confirmation that developer settings are enabled -->
<string name="show_dev_on">You are now a developer!</string>
<!-- [CHAR LIMIT=NONE] Device Info screen. Okay we get it, stop pressing, you already have it on -->
@@ -502,9 +502,9 @@
<!-- The title of the confirmation dialog shown when the user selects one / several languages and tries to remove them [CHAR LIMIT=60] -->
<string name="dlg_remove_locales_title">{count, plural,
- =1 {Remove selected language?}
- other {Remove selected languages?}
- }</string>
+ =1 {Remove selected language?}
+ other {Remove selected languages?}
+ }</string>
<!-- The text of the confirmation dialog shown when the user selects several languages and tries to remove them [CHAR LIMIT=NONE] -->
<string name="dlg_remove_locales_message">Text will be displayed in another language.</string>
@@ -654,9 +654,9 @@
<string name="location_settings_summary_location_off">Off</string>
<!-- Summary for Location settings when location is on, explaining how many apps have location permission [CHAR LIMIT=NONE]-->
<string name="location_settings_summary_location_on">{count, plural,
- =1 {On / # app has access to location}
- other {On / # apps have access to location}
- }</string>
+ =1 {On / # app has access to location}
+ other {On / # apps have access to location}
+ }</string>
<!-- Location settings, loading the number of apps which have location permission [CHAR LIMIT=30] -->
<string name="location_settings_loading_app_permission_stats">Loading\u2026</string>
<!-- Location settings footer warning text when location is on [CHAR LIMIT=NONE] -->
@@ -845,9 +845,9 @@
<string name="fingerprint_add_title">Add fingerprint</string>
<!-- Message showing the current number of fingerprints set up. Shown for a menu item that launches fingerprint settings or enrollment. -->
<string name="security_settings_fingerprint_preference_summary">{count, plural,
- =1 {Fingerprint added}
- other {# fingerprints added}
- }</string>
+ =1 {Fingerprint added}
+ other {# fingerprints added}
+ }</string>
<!-- message shown in summary field when no fingerprints are registered -->
<string name="security_settings_fingerprint_preference_summary_none">Setup needed</string>
<!-- Introduction title shown in fingerprint enrollment to introduce the fingerprint feature [CHAR LIMIT=29] -->
@@ -1448,9 +1448,9 @@
<string name="private_space_category_hide">Hide</string>
<!-- Header on pattern confirm screen inside private space settings when separate lock set for private space [CHAR LIMIT=50] -->
<string name="private_space_confirm_your_pattern_header">Confirm your private space pattern</string>
- <!-- Header on PIN confirm screen inside private space settings when separate lock set for private space [CHAR LIMIT=50] -->
+ <!-- Header on PIN confirm screen inside private space settings when separate lock set for private space [CHAR LIMIT=50] -->
<string name="private_space_confirm_your_pin_header">Re-enter your private space PIN</string>
- <!-- Header on password confirm screen inside private space when separate lock set for private space[CHAR LIMIT=50] -->
+ <!-- Header on password confirm screen inside private space when separate lock set for private space[CHAR LIMIT=50] -->
<string name="private_space_confirm_your_password_header">Re-enter your private space password</string>
<!-- Text shown when "Add fingerprint" button is disabled -->
@@ -1686,21 +1686,21 @@
<!-- Hint shown in dialog screen when password is too short -->
<string name="lockpassword_password_too_short">{count, plural,
- =1 {Must contain at least # character}
- other {Must be at least # characters}
- }</string>
+ =1 {Must contain at least # character}
+ other {Must be at least # characters}
+ }</string>
<!-- Hint shown in dialog screen when password is too short and only using numbers. [CHAR LIMIT=NONE] -->
<string name="lockpassword_password_too_short_all_numeric">
{count, plural,
- =1 {If using only numbers, must be at least 1 digit}
- other {If using only numbers, must be at least # digits}
+ =1 {If using only numbers, must be at least 1 digit}
+ other {If using only numbers, must be at least # digits}
}
</string>
<!-- Hint shown in dialog screen when PIN is too short -->
<string name="lockpassword_pin_too_short">{count, plural,
- =1 {PIN must contain at least # digit}
- other {PIN must be at least # digits}
- }</string>
+ =1 {PIN must contain at least # digit}
+ other {PIN must be at least # digits}
+ }</string>
<!-- Hint shown in dialog screen when PIN is too short with Additional text indicating minAutoConfirmLen(eg: 6) digits PIN offer additional security -->
<string name="lockpassword_pin_too_short_autoConfirm_extra_message">{count, plural,
@@ -1710,14 +1710,14 @@
<!-- Error shown in popup when password is too long -->
<string name="lockpassword_password_too_long">{count, plural,
- =1 {Must be fewer than # character}
- other {Must be fewer than # characters}
- }</string>
+ =1 {Must be fewer than # character}
+ other {Must be fewer than # characters}
+ }</string>
<!-- Error shown in popup when PIN is too long -->
<string name="lockpassword_pin_too_long">{count, plural,
- =1 {Must be fewer than # digit}
- other {Must be fewer than # digits}
- }</string>
+ =1 {Must be fewer than # digit}
+ other {Must be fewer than # digits}
+ }</string>
<!-- Error shown when in PIN mode and PIN has been used recently. Please keep this string short! -->
<string name="lockpassword_pin_recently_used">Device admin doesn\'t allow using a recent PIN</string>
@@ -1727,45 +1727,45 @@
<!-- Error shown when in PASSWORD mode and password doesn't contain the required number of letters -->
<string name="lockpassword_password_requires_letters">{count, plural,
- =1 {Must contain at least 1 letter}
- other {Must contain at least # letters}
- }</string>
+ =1 {Must contain at least 1 letter}
+ other {Must contain at least # letters}
+ }</string>
<!-- Error shown when in PASSWORD mode and password doesn't contain the required number of lowercase letters -->
<string name="lockpassword_password_requires_lowercase">{count, plural,
- =1 {Must contain at least 1 lowercase letter}
- other {Must contain at least # lowercase letters}
- }</string>
+ =1 {Must contain at least 1 lowercase letter}
+ other {Must contain at least # lowercase letters}
+ }</string>
<!-- Error shown when in PASSWORD mode and password doesn't contain the required number of uppercase letters -->
<string name="lockpassword_password_requires_uppercase">{count, plural,
- =1 {Must contain at least 1 uppercase letter}
- other {Must contain at least # uppercase letters}
- }</string>
+ =1 {Must contain at least 1 uppercase letter}
+ other {Must contain at least # uppercase letters}
+ }</string>
<!-- Error shown when in PASSWORD mode and password doesn't contain the required number of numerical digits -->
<string name="lockpassword_password_requires_numeric">{count, plural,
- =1 {Must contain at least 1 numerical digit}
- other {Must contain at least # numerical digits}
- }</string>
+ =1 {Must contain at least 1 numerical digit}
+ other {Must contain at least # numerical digits}
+ }</string>
<!-- Error shown when in PASSWORD mode and password doesn't contain the required number of special symbols -->
<string name="lockpassword_password_requires_symbols">{count, plural,
- =1 {Must contain at least 1 special symbol}
- other {Must contain at least # special symbols}
- }</string>
+ =1 {Must contain at least 1 special symbol}
+ other {Must contain at least # special symbols}
+ }</string>
<!-- Error shown when in PASSWORD mode and password doesn't contain the required number of non-letter characters -->
<string name="lockpassword_password_requires_nonletter">{count, plural,
- =1 {Must contain at least 1 non-letter character}
- other {Must contain at least # non-letter characters}
- }</string>
+ =1 {Must contain at least 1 non-letter character}
+ other {Must contain at least # non-letter characters}
+ }</string>
<!-- Error shown when in PASSWORD mode and password doesn't contain the required number of non-numerical characters -->
<string name="lockpassword_password_requires_nonnumerical">{count, plural,
- =1 {Must contain at least 1 non-numerical character}
- other {Must contain at least # non-numerical characters}
- }</string>
+ =1 {Must contain at least 1 non-numerical character}
+ other {Must contain at least # non-numerical characters}
+ }</string>
<!-- Error shown when in PASSWORD mode and password has been used recently. Please keep this string short! -->
<string name="lockpassword_password_recently_used">Device admin doesn\'t allow using a recent
@@ -1801,9 +1801,9 @@
<!-- Summary of preference to manage device admin apps, informing the user how many device admin apps are installed and active -->
<string name="number_of_device_admins">{count, plural,
- =1 {# active app}
- other {# active apps}
- }</string>
+ =1 {# active app}
+ other {# active apps}
+ }</string>
<!-- Title of preference to manage trust agents -->
<string name="manage_trust_agents">Trust agents</string>
@@ -1816,9 +1816,9 @@
<!-- Summary of preference to manage device policies when there is trust agent-->
<string name="manage_trust_agents_summary_on">{count, plural,
- =1 {1 active trust agent}
- other {# active trust agents}
- }</string>
+ =1 {1 active trust agent}
+ other {# active trust agents}
+ }</string>
<!-- Bluetooth settings -->
<!--Used as title on second screen after selecting Bluetooth settings -->
@@ -2412,19 +2412,19 @@
<!-- Wi-Fi Advanced Settings --> <skip />
<!-- Wi-Fi settings screen, Saved networks summary. This shows below the "Saved networks" item and indicates the number of networks, not including passpoint network, a user has saved. [CHAR LIMIT=30] -->
<string name="wifi_saved_access_points_summary">{count, plural,
- =1 {1 network}
- other {# networks}
- }</string>
+ =1 {1 network}
+ other {# networks}
+ }</string>
<!-- Wi-Fi settings screen, Saved networks summary. This shows below the "Saved networks" item and indicates the number of passpoint networks a user has saved. [CHAR LIMIT=30] -->
<string name="wifi_saved_passpoint_access_points_summary">{count, plural,
- =1 {1 subscription}
- other {# subscriptions}
- }</string>
+ =1 {1 subscription}
+ other {# subscriptions}
+ }</string>
<!-- Wi-Fi settings screen, Saved networks summary. This shows below the "Saved networks" item and indicates number of whole kinds networks, if there are both normal saved networks and saved passpoint networks. The number will be at least 2, so the one case is only to prevent lint error. [CHAR LIMIT=60] -->
<string name="wifi_saved_all_access_points_summary">{count, plural,
- =1 {1 network & subscription}
- other {# networks & subscriptions}
- }</string>
+ =1 {1 network & subscription}
+ other {# networks & subscriptions}
+ }</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 device's Wi-Fi MAC address. [CHAR LIMIT=50] -->
@@ -2998,11 +2998,11 @@
<!-- Dark UI screen footer summary text shown to indicate Modes may turn on/off Dark theme automatically according to their triggers. [CHAR LIMIT=NONE] -->
<string name="dark_ui_modes_footer_summary">
{count, plural, offset:2
- =0 {Modes can also activate dark theme}
- =1 {{mode_1} also activates dark theme}
- =2 {{mode_1} and {mode_2} also activate dark theme}
- =3 {{mode_1}, {mode_2}, and {mode_3} also activate dark theme}
- other {{mode_1}, {mode_2}, and # more also activate dark theme}
+ =0 {Modes can also activate dark theme}
+ =1 {{mode_1} also activates dark theme}
+ =2 {{mode_1} and {mode_2} also activate dark theme}
+ =3 {{mode_1}, {mode_2}, and {mode_3} also activate dark theme}
+ other {{mode_1}, {mode_2}, and # more also activate dark theme}
}
</string>
<!-- Dark UI screen footer action text linking to Modes settings. [CHAR LIMIT=NONE] -->
@@ -3153,9 +3153,9 @@
<string name="wrong_pin_code_pukked">Incorrect SIM PIN code you must now contact your carrier to unlock your device.</string>
<!-- Instructions telling the user that they entered the wrong SIM PIN while trying to unlock the keyguard. Displayed in a dialog box. [CHAR LIMIT=100] -->
<string name="wrong_pin_code">{count, plural,
- =1 {Incorrect SIM PIN code, you have # remaining attempt before you must contact your carrier to unlock your device.}
- other {Incorrect SIM PIN code, you have # remaining attempts.}
- }</string>
+ =1 {Incorrect SIM PIN code, you have # remaining attempt before you must contact your carrier to unlock your device.}
+ other {Incorrect SIM PIN code, you have # remaining attempts.}
+ }</string>
<!-- This is instruction text to inform the user that they have entered the wrong SIM PIN while trying to unlock the keyguard.
The variable will be replaced with a number. [CHAR LIMIT=NONE] -->
@@ -3324,27 +3324,27 @@
<!-- Dialog body informing user about an unmountable storage device. [CHAR LIMIT=NONE]-->
<string name="storage_dialog_unmountable">This <xliff:g id="name" example="SD card">^1</xliff:g> is corrupted.
-\n\nTo use this <xliff:g id="name" example="SD card">^1</xliff:g>, you have to set it up first.</string>
+ \n\nTo use this <xliff:g id="name" example="SD card">^1</xliff:g>, you have to set it up first.</string>
<!-- Body of dialog informing user about consequences of formatting an internal storage device [CHAR LIMIT=NONE]-->
<string name="storage_internal_format_details">You can format this SD card to store photos, videos, music,
and more and access them on other devices.
\n\n<b>All data on this SD card will be erased.</b>
\n\n<b>Before formatting</b>
-\n\n<b>Back up photos & other media</b>
-\nMove your media files to alternative storage on this device, or transfer them to a computer using a USB cable.
-\n\n<b>Back up apps</b>
-\nAll apps stored on this <xliff:g id="name" example="SD card">^1</xliff:g> will be uninstalled and their data will be erased. To keep these apps, move them to alternative storage on this device.</string>
+ \n\n<b>Back up photos & other media</b>
+ \nMove your media files to alternative storage on this device, or transfer them to a computer using a USB cable.
+ \n\n<b>Back up apps</b>
+ \nAll apps stored on this <xliff:g id="name" example="SD card">^1</xliff:g> will be uninstalled and their data will be erased. To keep these apps, move them to alternative storage on this device.</string>
<!-- Body of dialog informing user about consequences of ejecting an internal storage device [CHAR LIMIT=NONE]-->
<string name="storage_internal_unmount_details"><b>When you eject this <xliff:g id="name" example="SD card">^1</xliff:g>, apps stored on it will stop working, and media files stored on it will not be available until it is reinserted.</b>
-\n\nThis <xliff:g id="name" example="SD card">^1</xliff:g> is formatted to work on this device only. It won\u2019t work on any others.</string>
+ \n\nThis <xliff:g id="name" example="SD card">^1</xliff:g> is formatted to work on this device only. It won\u2019t work on any others.</string>
<!-- Body of dialog informing user about consequences of forgetting an internal storage device [CHAR LIMIT=NONE]-->
<string name="storage_internal_forget_details">To use the apps, photos, or data this <xliff:g id="name" example="SD card">^1</xliff:g> contains, reinsert it.
-\n\nAlternatively, you can choose to forget this storage if the device isn\u2019t available.
-\n\nIf you choose to forget, all the data the device contains will be lost forever.
-\n\nYou can reinstall the apps later, but their data stored on this device will be lost.</string>
+ \n\nAlternatively, you can choose to forget this storage if the device isn\u2019t available.
+ \n\nIf you choose to forget, all the data the device contains will be lost forever.
+ \n\nYou can reinstall the apps later, but their data stored on this device will be lost.</string>
<!-- Title of dialog confirming that user wants to forget an internal storage device [CHAR LIMIT=32]-->
<string name="storage_internal_forget_confirm_title">Forget <xliff:g id="name" example="SD card">^1</xliff:g>?</string>
@@ -3378,7 +3378,7 @@
<string name="storage_wizard_move_confirm_title">Move <xliff:g id="app" example="Calculator">^1</xliff:g></string>
<!-- Body of wizard step prompting user to move an app [CHAR LIMIT=NONE] -->
<string name="storage_wizard_move_confirm_body">Moving <xliff:g id="app" example="Calculator">^1</xliff:g> and its data to <xliff:g id="name" example="SD card">^2</xliff:g> will take only a few moments. You won\u2019t be able to use the app until the move is complete.
-\n\nDon\u2019t remove the <xliff:g id="name" example="SD card">^2</xliff:g> during the move.
+ \n\nDon\u2019t remove the <xliff:g id="name" example="SD card">^2</xliff:g> during the move.
</string>
<!-- Body of lock screen challenge message explaining that the given user must be unlocked before data can be moved [CHAR LIMIT=64] -->
@@ -3388,7 +3388,7 @@
<string name="storage_wizard_move_progress_title">Moving <xliff:g id="app" example="Calculator">^1</xliff:g>\u2026</string>
<!-- Body of wizard step showing app move progress [CHAR LIMIT=NONE] -->
<string name="storage_wizard_move_progress_body">Don\u2019t remove the <xliff:g id="name" example="SD card">^1</xliff:g> during the move.
-\n\nThe <xliff:g id="app" example="Calculator">^2</xliff:g> app on this device won\u2019t be available until the move is complete.
+ \n\nThe <xliff:g id="app" example="Calculator">^2</xliff:g> app on this device won\u2019t be available until the move is complete.
</string>
<!-- This is the title of a full-screen message. After this question, the user will get to choose how they want to use the storage device that they have in their phone. The placeholder is for the specific device (e.g. SD card, USB drive, etc.). [CHAR LIMIT=32] -->
@@ -3408,7 +3408,7 @@
<string name="storage_wizard_format_confirm_v2_title">Format this <xliff:g id="name" example="SD card">^1</xliff:g>?</string>
<!-- Body of a dialog. This text is confirming that the user wants to use their SD card as extra phone storage, but the formatting process will erase existing content on the card. The first placeholder is for the name of the device (e.g. a brand name of the SD card or USB drive). The second and third placeholders are for the general references (e.g. SD card, USB drive). [CHAR LIMIT=NONE] -->
<string name="storage_wizard_format_confirm_v2_body">This <xliff:g id="name" example="SanDisk SD card">^1</xliff:g> needs to be formatted to store apps, files, and media.
-\n\nFormatting will erase existing content on the <xliff:g id="name" example="SD card">^2</xliff:g>. To avoid losing content, back it up to another <xliff:g id="name" example="SD card">^3</xliff:g> or device.</string>
+ \n\nFormatting will erase existing content on the <xliff:g id="name" example="SD card">^2</xliff:g>. To avoid losing content, back it up to another <xliff:g id="name" example="SD card">^3</xliff:g> or device.</string>
<!-- Body of a dialog. This text is confirming that the user wants to use their SD card as portable storage, but the formatting process will erase existing content on the card. The first placeholder is for the name of the device (e.g. a brand name of the SD card or USB drive). The second and third placeholders are for the general references (e.g. SD card, USB drive). [CHAR LIMIT=NONE] -->
<string name="storage_wizard_format_confirm_v2_body_external">This <xliff:g id="name" example="SanDisk SD card">^1</xliff:g> needs to be formatted to store photos, videos, music, and more.
\n\nFormatting will erase existing content on the <xliff:g id="name" example="SD card">^2</xliff:g>. To avoid losing content, back it up to another <xliff:g id="name" example="SD card">^3</xliff:g> or device.</string>
@@ -3437,8 +3437,8 @@
<string name="storage_wizard_slow_v2_title">Slow <xliff:g id="name" example="SD card">^1</xliff:g></string>
<!-- Strings that are part of a full-screen message. These strings let the user know that their storage device is slow, and include some options they can try. The first placeholder is for the name of the storage device (e.g. brand name of the SD card), and the second and third placeholders are for the general references (e.g. SD card, USB drive, etc.). [CHAR LIMIT=NONE] -->
<string name="storage_wizard_slow_v2_body">You can still use this <xliff:g id="name" example="SanDisk SD card">^1</xliff:g>, but it may be slow.
-\n\nApps stored on this <xliff:g id="name" example="SD card">^2</xliff:g> may not work properly, and content transfers could take a long time.
-\n\nTry using a faster <xliff:g id="name" example="SD card">^3</xliff:g>, or use this <xliff:g id="name" example="SD card">^4</xliff:g> for portable storage instead.</string>
+ \n\nApps stored on this <xliff:g id="name" example="SD card">^2</xliff:g> may not work properly, and content transfers could take a long time.
+ \n\nTry using a faster <xliff:g id="name" example="SD card">^3</xliff:g>, or use this <xliff:g id="name" example="SD card">^4</xliff:g> for portable storage instead.</string>
<!-- Action of a dialog. This action will start the wizard from the beginning, letting the user make an alternative choice. [CHAR LIMIT=32] -->
<string name="storage_wizard_slow_v2_start_over">Start over</string>
<!-- Action of a dialog. This action will continue the wizard, meaning the user acknowledges their card is slow. [CHAR LIMIT=32] -->
@@ -3753,9 +3753,9 @@
[CHAR LIMIT=NONE]-->
<string name="location_app_permission_summary_location_on">{count, plural,
- =1 {# of {total} apps has access to location}
- other {# of {total} apps have access to location}
- }</string>
+ =1 {# of {total} apps has access to location}
+ other {# of {total} apps have access to location}
+ }</string>
<!-- [CHAR LIMIT=50] Location settings screen, sub category for recent location access -->
<string name="location_category_recent_location_access">Recent access</string>
<!-- Location settings screen, displayed when there're more than three recent location access apps [CHAR LIMIT=30] -->
@@ -4141,9 +4141,9 @@
<string name="recent_app_category_title">Recently opened apps</string>
<!-- Preference title for showing all apps on device [CHAR_LIMIT=50]-->
<string name="see_all_apps_title">{count, plural,
- =1 {See all apps}
- other {See all # apps}
- }</string>
+ =1 {See all apps}
+ other {See all # apps}
+ }</string>
<!-- Title of the dialog that asks the user to contact the IT admin to reset password [CHAR LIMIT=40] -->
<string name="forgot_password_title">Contact your IT admin</string>
@@ -4174,9 +4174,9 @@
<string name="cache_size_label">Cache</string>
<!-- Manage applications, individual application info storage screen. Describes the number of URIs (directories or files) an app has been granted access (by another apps)-->
<string name="uri_permissions_text">{count, plural,
- =1 {1 item}
- other {# items}
- }</string>
+ =1 {1 item}
+ other {# items}
+ }</string>
<!-- Manage applications, individual application info storage screen. Button below list of URIs. -->
<string name="clear_uri_btn_text">Clear access</string>
<!-- Manage applications, Header name used for other controls -->
@@ -4229,7 +4229,7 @@
<string name="clear_activities">Clear default preferences</string>
<!-- Manage applications, individual application info screen, screen, message text under screen compatibility heading -->
<string name="screen_compatibility_text">This app may not be designed for your screen. You can control how it
- adjusts to your screen here.</string>
+ adjusts to your screen here.</string>
<!-- Manage applications, individual application screen, checkbox to control asking for compatibility mode. -->
<string name="ask_compatibility">Ask when launched</string>
<!-- Manage applications, individual application screen, checkbox to control compatibility mode. -->
@@ -4493,10 +4493,10 @@
<!-- Warning message about security implications of enabling a spell checker, displayed as a dialog
message when the user selects to enable a spell checker. -->
<string name="spellchecker_security_warning">This spell checker may be able to collect
- all the text you type, including personal data like passwords and credit
- card numbers. It comes from the app
- <xliff:g id="spellchecker_application_name">%1$s</xliff:g>.
- Use this spell checker?</string>
+ all the text you type, including personal data like passwords and credit
+ card numbers. It comes from the app
+ <xliff:g id="spellchecker_application_name">%1$s</xliff:g>.
+ Use this spell checker?</string>
<!-- Image button description for spell checker quick settings. -->
<string name="spellchecker_quick_settings">Settings</string>
<!-- Image button description for spell checker language. -->
@@ -5139,18 +5139,18 @@
<string name="accessibility_tutorial_dialog_twofinger_doubletap_instruction">To start and stop magnification, quickly tap the screen twice with %1$d fingers</string>
<!-- Instruction for the accessibility tutorial dialog in accessibility service with quick settings shortcut. [CHAR LIMIT=NONE]-->
<string name="accessibility_tutorial_dialog_message_quick_setting">{count, plural,
- =1 {To use this feature, swipe down from the top of your screen. Then, find the {featureName} tile.}
- other {To use this feature, swipe down from the top of your screen with # fingers. Then, find the {featureName} tile.}
- }</string>
+ =1 {To use this feature, swipe down from the top of your screen. Then, find the {featureName} tile.}
+ other {To use this feature, swipe down from the top of your screen with # fingers. Then, find the {featureName} tile.}
+ }</string>
<!-- Warning for the accessibility shortcut type that is not available immediately during device setup when chosen, but will be available after setup. [CHAR LIMIT=NONE]-->
<string name="accessibility_tutorial_dialog_shortcut_unavailable_in_suw">This shortcut will be available after you finish device setup.</string>
<!-- Message for the accessibility tutorial dialog when user enables an accessibility service while using gesture navigation and touch exploration is not enabled. [CHAR LIMIT=NONE] -->
<string name="accessibility_tutorial_dialog_message_gesture">To use this feature, swipe up from the bottom of the screen with 2 fingers.\n\nTo switch between features, swipe up with 2 fingers and hold.</string>
<!-- Instruction for the accessibility tutorial dialog when user enables an accessibility service while using gesture navigation. [CHAR LIMIT=NONE] -->
<string name="accessibility_tutorial_dialog_gesture_shortcut_instruction">{count, plural,
- =1 {To use this feature, swipe up from the bottom of your screen}
- other {To use this feature, swipe up with # fingers from the bottom of your screen}
- }</string>
+ =1 {To use this feature, swipe up from the bottom of your screen}
+ other {To use this feature, swipe up with # fingers from the bottom of your screen}
+ }</string>
<!-- Message for the accessibility tutorial dialog when user enables an accessibility service while using gesture navigation and touch exploration is enabled. [CHAR LIMIT=NONE] -->
<string name="accessibility_tutorial_dialog_message_gesture_talkback">To use this feature, swipe up from the bottom of the screen with 3 fingers.\n\nTo switch between features, swipe up with 3 fingers and hold.</string>
<!-- Message for the accessibility tutorial dialog when user chooses gesture navigation in navigation settings, an accessibility service is using the accessibility button, and touch exploration is disabled. [CHAR LIMIT=NONE] -->
@@ -5183,9 +5183,9 @@
<string name="accessibility_shortcut_edit_dialog_summary_software">Tap the accessibility button <xliff:g id="accessibility_icon" example="[Icon]">%s</xliff:g> at the bottom of your screen. To switch between features, touch & hold the accessibility button.</string>
<!-- Summary for gesture shortcut option -->
<string name="accessibility_shortcut_edit_dialog_summary_gesture">{count, plural,
- =1 {Swipe up from the bottom of your screen. To switch between features, swipe up and hold.}
- other {Swipe up with # fingers from the bottom of your screen. To switch between features, swipe up with # fingers and hold.}
- }</string>
+ =1 {Swipe up from the bottom of your screen. To switch between features, swipe up and hold.}
+ other {Swipe up with # fingers from the bottom of your screen. To switch between features, swipe up with # fingers and hold.}
+ }</string>
<!-- Summary for software shortcut in accessibility edit shortcut dialog when user had enabled the accessibility floating button mode (Floating over other apps). [CHAR LIMIT=NONE] -->
<string name="accessibility_shortcut_edit_dialog_summary_software_floating"><annotation id="link">More options</annotation></string>
<!-- Footer to show help link content description. [CHAR LIMIT=NONE] -->
@@ -5194,14 +5194,14 @@
<string name="accessibility_shortcut_edit_dialog_title_quick_settings">Quick Settings</string>
<!-- Summary for quick settings shortcut option in accessibility edit shortcut dialog. [CHAR LIMIT=NONE] -->
<string name="accessibility_shortcut_edit_dialog_summary_quick_settings">{count, plural,
- =1 {Swipe down from the top of your screen}
- other {Swipe down with # fingers from the top of your screen}
- }</string>
+ =1 {Swipe down from the top of your screen}
+ other {Swipe down with # fingers from the top of your screen}
+ }</string>
<!-- Summary for quick settings shortcut option in accessibility edit shortcut dialog in Setup Wizard. [CHAR LIMIT=NONE] -->
<string name="accessibility_shortcut_edit_dialog_summary_quick_settings_suw">{count, plural,
- =1 {Swipe down from the top of your screen. This shortcut will be available after you finish device setup.}
- other {Swipe down with # fingers from the top of your screen. This shortcut will be available after you finish device setup.}
- }</string>
+ =1 {Swipe down from the top of your screen. This shortcut will be available after you finish device setup.}
+ other {Swipe down with # fingers from the top of your screen. This shortcut will be available after you finish device setup.}
+ }</string>
<!-- Shown as one of the item in the chosen accessibility shortcut types list presented as a label next to the shortcut toggle. [CHAR LIMIT=NONE] -->
<string name="accessibility_feature_shortcut_setting_summary_quick_settings">Quick Settings</string>
<!-- Title for hardware shortcut in accessibility edit shortcut dialog. [CHAR LIMIT=NONE] -->
@@ -5621,25 +5621,25 @@
<!-- Subtitle for the accessibility preference to configure feature that performs click action soon after mouse/trackpad pointer stops moving, in case delay before click is extremely short. Placeholder will be set to the number of milliseconds to which the delay amounts. [CHAR LIMIT=NONE] -->
<string name="accessibilty_autoclick_preference_subtitle_short_delay">{count, plural,
- =1 {Short ({time} second)}
- other {Short ({time} seconds)}
- }</string>
+ =1 {Short ({time} second)}
+ other {Short ({time} seconds)}
+ }</string>
<!-- Subtitle for the accessibility preference to configure feature that performs click action soon after mouse/trackpad pointer stops moving, in case delay before click is extremely short. Placeholder will be set to the number of milliseconds to which the delay amounts. [CHAR LIMIT=NONE] -->
<string name="accessibilty_autoclick_preference_subtitle_medium_delay">{count, plural,
- =1 {Medium ({time} second)}
- other {Medium ({time} seconds)}
- }</string>
+ =1 {Medium ({time} second)}
+ other {Medium ({time} seconds)}
+ }</string>
<!-- Subtitle for the accessibility preference to configure feature that performs click action soon after mouse/trackpad pointer stops moving, in case delay before click is extremely short. Placeholder will be set to the number of milliseconds to which the delay amounts. [CHAR LIMIT=NONE] -->
<string name="accessibilty_autoclick_preference_subtitle_long_delay">{count, plural,
- =1 {Long ({time} second)}
- other {Long ({time} seconds)}
- }</string>
+ =1 {Long ({time} second)}
+ other {Long ({time} seconds)}
+ }</string>
<!-- Summary for autoclick seekbar settings preference when user selected custom item. [CHAR LIMIT=35] -->
<string name="accessibilty_autoclick_delay_unit_second">{count, plural,
- =1 {{time} second}
- other {{time} seconds}
- }</string>
+ =1 {{time} second}
+ other {{time} seconds}
+ }</string>
<!-- Title for accessibility menu item to launch a settings activity. [CHAR LIMIT=15] -->
<string name="accessibility_menu_item_settings">Settings</string>
@@ -5801,15 +5801,15 @@
<string name="print_settings_summary_no_service">Off</string>
<string name="print_settings_summary">{count, plural,
- =1 {1 print service on}
- other {# print services on}
- }</string>
+ =1 {1 print service on}
+ other {# print services on}
+ }</string>
<!-- Print setting summary in settings screenm indicating how many print jobs are active [CHAR LIMIT=None] -->
<string name="print_jobs_summary">{count, plural,
- =1 {1 print job}
- other {# print jobs}
- }</string>
+ =1 {1 print job}
+ other {# print jobs}
+ }</string>
<!-- Title for print service settings screen [CHAR LIMIT=25] -->
<string name="print_settings_title">Print services</string>
@@ -5894,7 +5894,7 @@
<string name="power_usage_summary">What has been using the battery</string>
<!-- Display the battery level and status [CHAR_LIMIT=60] -->
<string name="power_usage_level_and_status"><xliff:g id="level">%1$s</xliff:g>
- - <xliff:g id="status">%2$s</xliff:g></string>
+ - <xliff:g id="status">%2$s</xliff:g></string>
<!-- Display time remaining until battery is discharged [CHAR_LIMIT=60] -->
<string name="power_discharge_remaining"><xliff:g id="remain">%1$s</xliff:g> remaining</string>
<!-- Display time remaining until battery is charged [CHAR_LIMIT=60] -->
@@ -6012,30 +6012,30 @@
<string name="battery_tip_dialog_message_footer">Includes high-power background activity</string>
<!-- Title for restricted app preference, showing how many app need to be restricted [CHAR LIMIT=NONE] -->
<string name="battery_tip_restrict_title">{count, plural,
- =1 {Restrict # app}
- other {Restrict # apps}
- }</string>
+ =1 {Restrict # app}
+ other {Restrict # apps}
+ }</string>
<!-- Title for restricted app preference, showing how many app been restricted [CHAR LIMIT=NONE] -->
<string name="battery_tip_restrict_handled_title">{count, plural,
- =1 {{label} recently restricted}
- other {# apps recently restricted}
- }</string>
+ =1 {{label} recently restricted}
+ other {# apps recently restricted}
+ }</string>
<!-- Summary for restricted app preference, showing the impact of the apps [CHAR LIMIT=NONE] -->
<string name="battery_tip_restrict_summary">{count, plural,
- =1 {{label} has high background battery usage}
- other {# apps have high background battery usage}
- }</string>
+ =1 {{label} has high background battery usage}
+ other {# apps have high background battery usage}
+ }</string>
<!-- Summary for restricted app preference, showing the impact of the apps [CHAR LIMIT=NONE] -->
<string name="battery_tip_restrict_handled_summary">{count, plural,
- =1 {This app can\'t run in the background}
- other {These apps can\'t run in the background}
- }</string>
+ =1 {This app can\'t run in the background}
+ other {These apps can\'t run in the background}
+ }</string>
<!-- Title for dialog to restrict the app [CHAR LIMIT=NONE] -->
<string name="battery_tip_restrict_app_dialog_title">{count, plural,
- =1 {Restrict app?}
- other {Restrict # apps?}
- }</string>
+ =1 {Restrict app?}
+ other {Restrict # apps?}
+ }</string>
<!-- Message for battery tip dialog to show the info to restrict the app [CHAR LIMIT=NONE] -->
<string name="battery_tip_restrict_app_dialog_message">To save battery, stop <xliff:g id="app">%1$s</xliff:g> from using battery in the background. This app may not work properly and notifications may be delayed.</string>
<!-- Message for battery tip dialog to show the info to restrict the app, below it app list will be shown as a view [CHAR LIMIT=NONE] -->
@@ -6069,9 +6069,9 @@
<string name="restricted_app_title">Restricted apps</string>
<!-- Summary for restricted app preference, clicking it will goes to restricted app list [CHAR LIMIT=NONE] -->
<string name="restricted_app_summary">{count, plural,
- =1 {Limiting battery usage for # app}
- other {Limiting battery usage for # apps}
- }</string>
+ =1 {Limiting battery usage for # app}
+ other {Limiting battery usage for # apps}
+ }</string>
<!-- Summary for restricted app to show the restriction time [CHAR LIMIT=NONE] -->
<string name="restricted_app_time_summary">Restricted <xliff:g id="time" example="5 days ago">%1$s</xliff:g></string>
@@ -6091,9 +6091,9 @@
<!-- Summary for battery manager, showing app restricted -->
<string name="battery_manager_app_restricted">{count, plural,
- =1 {# app restricted}
- other {# apps restricted}
- }</string>
+ =1 {# app restricted}
+ other {# apps restricted}
+ }</string>
<!-- Summary for top level battery tile if battery is not present. [CHAR LIMIT=NONE] -->
<string name="battery_missing_message">Problem reading the battery meter.</string>
@@ -6581,9 +6581,9 @@
<string name="remove_credential_management_app_dialog_message">This app won\u2019t manage certificates, but it will stay on your device. Any certificates installed by the app will be uninstalled.</string>
<!-- List item found in the credential management app's authentication policy [CHAR LIMIT=NONE] -->
<string name="number_of_urls">{count, plural,
- =1 {# URL}
- other {# URLs}
- }</string>
+ =1 {# URL}
+ other {# URLs}
+ }</string>
<!-- Sound settings screen, setting check box label -->
<string name="emergency_tone_title">Emergency dialing signal</string>
@@ -6685,9 +6685,9 @@
<!-- app summary of notification app list screen [CHAR LIMIT=100] -->
<string name="notification_history_count">{count, plural,
- =1 {# notification}
- other {# notifications}
- }</string>
+ =1 {# notification}
+ other {# notifications}
+ }</string>
<!-- Category title for phone call's ringtone and vibration settings in the Sound Setting.
[CHAR LIMIT=40] -->
@@ -7108,9 +7108,9 @@
<string name="done_button">Done</string>
<!-- Title of Dialog warning users of SSL monitoring. [CHAR LIMIT=NONE] -->
<string name="ssl_ca_cert_dialog_title">{count, plural,
- =1 {Trust or remove certificate}
- other {Trust or remove certificates}
- }</string>
+ =1 {Trust or remove certificate}
+ other {Trust or remove certificates}
+ }</string>
<!-- Text of message to show to device owner user whose administrator has installed a SSL CA Cert. [CHAR LIMIT=NONE] -->
<string name="ssl_ca_cert_info_message_device_owner"> {numberOfCertificates, plural,
=1 {{orgName} has installed a certificate authority on your device, which may allow them to monitor your device network activity, including emails, apps, and secure websites.\n\nFor more information about this certificate, contact your admin.}
@@ -7125,9 +7125,9 @@
<string name="ssl_ca_cert_warning_message">A third party is capable of monitoring your network activity, including emails, apps, and secure websites.\n\nA trusted credential installed on your device is making this possible.</string>
<!-- Label on button that will take the user to the Trusted Credentials settings page. [CHAR LIMIT=NONE]-->
<string name="ssl_ca_cert_settings_button">{count, plural,
- =1 {Check certificate}
- other {Check certificates}
- }</string>
+ =1 {Check certificate}
+ other {Check certificates}
+ }</string>
<!-- User settings screen title [CHAR LIMIT=40] -->
<string name="user_settings_title">Users</string>
@@ -8085,9 +8085,9 @@
<!-- Zen Modes: Summary for the Do not Disturb option that describes how many automatic rules (schedules) are enabled [CHAR LIMIT=NONE]-->
<string name="zen_mode_settings_schedules_summary">
{count, plural,
- =0 {None}
- =1 {1 schedule set}
- other {# schedules set}
+ =0 {None}
+ =1 {1 schedule set}
+ other {# schedules set}
}
</string>
@@ -8123,20 +8123,20 @@
<!-- Modes: Summary for the modes segment, when at least one mode is active. [CHAR LIMIT=NONE]-->
<string name="zen_modes_summary_some_active">
{count, plural, offset:2
- =0 {}
- =1 {{mode_1} is active}
- =2 {{mode_1} and {mode_2} are active}
- =3 {{mode_1}, {mode_2}, and {mode_3} are active}
- other {{mode_1}, {mode_2}, and # more are active}
+ =0 {}
+ =1 {{mode_1} is active}
+ =2 {{mode_1} and {mode_2} are active}
+ =3 {{mode_1}, {mode_2}, and {mode_3} are active}
+ other {{mode_1}, {mode_2}, and # more are active}
}
</string>
<!-- Modes: Summary for the modes segment, when no modes are active. [CHAR LIMIT=NONE]-->
<string name="zen_modes_summary_none_active">
{count, plural,
- =0 {}
- =1 {1 mode can turn on automatically}
- other {# modes can turn on automatically}
+ =0 {}
+ =1 {1 mode can turn on automatically}
+ other {# modes can turn on automatically}
}
</string>
@@ -8437,25 +8437,25 @@
<!-- Do not disturb: Summary for zen mode duration setting indicating how long dnd will last when dnd is manually toggled on [CHAR LIMIT=NONE] -->
<string name="zen_mode_duration_summary_time_hours">
{count, plural,
- =1 {1 hour}
- other {# hours}
+ =1 {1 hour}
+ other {# hours}
}
</string>
<!-- Do not disturb: Summary for zen mode duration setting indicating how long dnd will last when toggled on -->
<string name="zen_mode_duration_summary_time_minutes">
{count, plural,
- =1 {1 minute}
- other {# minutes}
+ =1 {1 minute}
+ other {# minutes}
}
</string>
<!-- Summary for the Sound Do not Disturb option when DND isn't currently on. [CHAR LIMIT=NONE]-->
<string name="zen_mode_sound_summary_off">
{count, plural,
- =0 {Off}
- =1 {Off / 1 schedule can turn on automatically}
- other {Off / # schedules can turn on automatically}
+ =0 {Off}
+ =1 {Off / 1 schedule can turn on automatically}
+ other {Off / # schedules can turn on automatically}
}
</string>
@@ -8798,9 +8798,9 @@
<!-- [CHAR LIMIT=100] summary text on link to 'all conversations' page, some conversations are priority -->
<string name="priority_conversation_count">{count, plural,
- =1 {# priority conversation}
- other {# priority conversations}
- }</string>
+ =1 {# priority conversation}
+ other {# priority conversations}
+ }</string>
<!-- [CHAR LIMIT=100] preference category title -->
<string name="important_conversations">Priority conversations</string>
@@ -8897,13 +8897,13 @@
<!-- app summary of notification app list screen [CHAR LIMIT=100] -->
<string name="notifications_sent_daily">{count, plural,
- =1 {About # notification per day}
- other {About # notifications per day}
- }</string>
+ =1 {About # notification per day}
+ other {About # notifications per day}
+ }</string>
<string name="notifications_sent_weekly">{count, plural,
- =1 {About # notification per week}
- other {About # notifications per week}
- }</string>
+ =1 {About # notification per week}
+ other {About # notifications per week}
+ }</string>
<!-- app summary of notification app list screen [CHAR LIMIT=100] -->
<string name="notifications_sent_never">Never</string>
@@ -8943,7 +8943,7 @@
<!-- Title for a warning message about security implications of enabling a notification
listener, displayed as a dialog message. [CHAR LIMIT=NONE] -->
<string name="notification_listener_security_warning_title">Allow notification access for
- <xliff:g id="service" example="NotificationReader">%1$s</xliff:g>?</string>
+ <xliff:g id="service" example="NotificationReader">%1$s</xliff:g>?</string>
<!-- Summary for a warning message about security implications of enabling a notification
listener, displayed as a dialog message. [CHAR LIMIT=NONE] -->
<string name="notification_listener_security_warning_summary">
@@ -9007,7 +9007,7 @@
<!-- Title for a warning message about security implications of enabling a VR
listener, displayed as a dialog message. [CHAR LIMIT=NONE] -->
<string name="vr_listener_security_warning_title">Allow VR service access for
- <xliff:g id="service" example="VrCore">%1$s</xliff:g>?</string>
+ <xliff:g id="service" example="VrCore">%1$s</xliff:g>?</string>
<!-- Summary for a warning message about security implications of enabling a VR
listener, displayed as a dialog message. [CHAR LIMIT=NONE] -->
<string name="vr_listener_security_warning_summary">
@@ -9114,9 +9114,9 @@
<!-- Summary of preference to manage connected work and personal apps, informing the user how many apps are connected -->
<string name="interact_across_profiles_number_of_connected_apps">{count, plural,
- =1 {# app connected}
- other {# apps connected}
- }</string>
+ =1 {# app connected}
+ other {# apps connected}
+ }</string>
<!-- Banner title. This banner lets a user know that they need to install an app in their
work profile in order to connect it to the corresponding personal app.
@@ -9188,9 +9188,9 @@
<!-- [CHAR LIMIT=NONE] Footer listing a count of deleted channels. -->
<string name="deleted_channels">{count, plural,
- =1 {# category deleted}
- other {# categories deleted}
- }</string>
+ =1 {# category deleted}
+ other {# categories deleted}
+ }</string>
<!-- [CHAR LIMIT=NONE] App notification settings: Block option title -->
<string name="app_notification_block_title">Block all</string>
@@ -9351,9 +9351,9 @@
<!-- [CHAR LIMIT=NONE] Zen mode settings: Number of conversations allowed to bypass DND -->
<string name="zen_mode_conversations_count">
{count, plural,
- =0 {None}
- =1 {1 conversation}
- other {# conversations}
+ =0 {None}
+ =1 {1 conversation}
+ other {# conversations}
}
</string>
@@ -9385,11 +9385,11 @@
<!-- Zen mode settings: Starred contacts summary [CHAR LIMIT=NONE] -->
<string name="zen_mode_starred_contacts_summary_contacts">
{count, plural, offset:2
- =0 {None}
- =1 {{contact_1}}
- =2 {{contact_1} and {contact_2}}
- =3 {{contact_1}, {contact_2}, and {contact_3}}
- other {{contact_1}, {contact_2}, and # others}
+ =0 {None}
+ =1 {{contact_1}}
+ =2 {{contact_1} and {contact_2}}
+ =3 {{contact_1}, {contact_2}, and {contact_3}}
+ other {{contact_1}, {contact_2}, and # others}
}
</string>
@@ -9416,9 +9416,9 @@
<!-- Zen mode settings: Senders in contacts can bypass DND summary summary [CHAR LIMIT=NONE] -->
<string name="zen_mode_contacts_count">
{count, plural,
- =0 {None}
- =1 {1 contact}
- other {# contacts}
+ =0 {None}
+ =1 {1 contact}
+ other {# contacts}
}
</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Calls or messages option value: From anyone -->
@@ -9494,11 +9494,11 @@
<!-- [CHAR LIMIT=NONE] Zen mode settings: Lists apps that can bypass DND. For example, "Nest, Messages, and 2 more can interrupt". -->
<string name="zen_mode_apps_subtext">
{count, plural, offset:2
- =0 {No apps can interrupt}
- =1 {{app_1} can interrupt}
- =2 {{app_1} and {app_2} can interrupt}
- =3 {{app_1}, {app_2}, and {app_3} can interrupt}
- other {{app_1}, {app_2}, and # more can interrupt}
+ =0 {No apps can interrupt}
+ =1 {{app_1} can interrupt}
+ =2 {{app_1} and {app_2} can interrupt}
+ =3 {{app_1}, {app_2}, and {app_3} can interrupt}
+ other {{app_1}, {app_2}, and # more can interrupt}
}
</string>
<!-- Modes: Entry in the "apps that can bypass DND" list that corresponds to a work profile app (e.g. "Chrome (Work)" [CHAR LIMIT=15]. -->
@@ -9533,11 +9533,11 @@
<!-- [CHAR LIMIT=NONE] Zen mode settings: Lists apps that can bypass DND. For example, "Nest, Messages, and 2 more can interrupt". -->
<string name="zen_mode_bypassing_apps_subtext">
{count, plural, offset:2
- =0 {No apps can interrupt}
- =1 {{app_1} can interrupt}
- =2 {{app_1} and {app_2} can interrupt}
- =3 {{app_1}, {app_2}, and {app_3} can interrupt}
- other {{app_1}, {app_2}, and # more can interrupt}
+ =0 {No apps can interrupt}
+ =1 {{app_1} can interrupt}
+ =2 {{app_1} and {app_2} can interrupt}
+ =3 {{app_1}, {app_2}, and {app_3} can interrupt}
+ other {{app_1}, {app_2}, and # more can interrupt}
}
</string>
<!-- [CHAR LIMIT=100] Zen mode settings: Allow apps to bypass DND title-->
@@ -9551,11 +9551,11 @@
<!-- [CHAR LIMIT=NONE] Zen mode settings: Summary for sound interruption settings -->
<string name="zen_mode_other_sounds_summary">
{count, plural, offset:2
- =0 {Nothing can interrupt}
- =1 {{sound_category_1} can interrupt}
- =2 {{sound_category_1} and {sound_category_2} can interrupt}
- =3 {{sound_category_1}, {sound_category_2}, and {sound_category_3} can interrupt}
- other {{sound_category_1}, {sound_category_2}, and # more can interrupt}
+ =0 {Nothing can interrupt}
+ =1 {{sound_category_1} can interrupt}
+ =2 {{sound_category_1} and {sound_category_2} can interrupt}
+ =3 {{sound_category_1}, {sound_category_2}, and {sound_category_3} can interrupt}
+ other {{sound_category_1}, {sound_category_2}, and # more can interrupt}
}
</string>
<!-- [CHAR LIMIT=120] Zen mode settings: No sounds are allowed to bypass DND -->
@@ -9599,14 +9599,14 @@
<string name="zen_mode_summary_alarms_only_indefinite">Change to alarms only indefinitely</string>
<!-- [CHAR LIMIT=NONE] Zen mode summary spoken when changing mode by voice: switch to alarms only for < 60 minutes. -->
<string name="zen_mode_summary_alarms_only_by_minute">{count, plural,
- =1 {Change to alarms only for one minute until {time}}
- other {Change to alarms only for # minutes (until {time})}
- }</string>
+ =1 {Change to alarms only for one minute until {time}}
+ other {Change to alarms only for # minutes (until {time})}
+ }</string>
<!-- [CHAR LIMIT=NONE] Zen mode summary spoken when changing mode by voice: switch to alarms only for N hours. -->
<string name="zen_mode_summary_alarms_only_by_hour">{count, plural,
- =1 {Change to alarms only for one hour until {time}}
- other {Change to alarms only for # hours until {time}}
- }</string>
+ =1 {Change to alarms only for one hour until {time}}
+ other {Change to alarms only for # hours until {time}}
+ }</string>
<!-- [CHAR LIMIT=NONE] Zen mode summary spoken when changing mode by voice: switch to alarms only until a specific time. -->
<string name="zen_mode_summary_alarms_only_by_time">Change to alarms only until <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g></string>
<!-- [CHAR LIMIT=NONE] Zen mode summary spoken when changing mode by voice: Turn on all notifications. -->
@@ -9828,13 +9828,13 @@
<!-- Title, message and button for verified links dialog. -->
<string name="app_launch_verified_links_title">{count, plural,
- =1 {# verified link}
- other {# verified links}
- }</string>
+ =1 {# verified link}
+ other {# verified links}
+ }</string>
<string name="app_launch_verified_links_message">{count, plural,
- =1 {This link is verified and automatically opens in this app.}
- other {These links are verified and automatically open in this app.}
- }</string>
+ =1 {This link is verified and automatically opens in this app.}
+ other {These links are verified and automatically open in this app.}
+ }</string>
<!-- OK button for verified links dialog. [CHAR LIMIT=20] -->
<string name="app_launch_dialog_ok">OK</string>
<!-- Info icon description of the verified links. [CHAR LIMIT=NONE] -->
@@ -9847,9 +9847,9 @@
<!-- Title and button for supported links dialog. -->
<string name="app_launch_supported_links_title">{count, plural,
- =1 {# supported link}
- other {# supported links}
- }</string>
+ =1 {# supported link}
+ other {# supported links}
+ }</string>
<!-- Add button for supported links dialog. [CHAR LIMIT=20] -->
<string name="app_launch_supported_links_add">Add</string>
<!-- The subtext of the link title in supported links dialog. [CHAR LIMIT=30] -->
@@ -9885,15 +9885,15 @@
<!-- Permissions preference summary [CHAR LIMIT=40] -->
<string name="notifications_categories_off">{count, plural,
- =1 {# category turned off}
- other {# categories turned off}
- }</string>
+ =1 {# category turned off}
+ other {# categories turned off}
+ }</string>
<!-- Runtime permissions preference summary. Number of additional permissions granted. [CHAR LIMIT=40] -->
<string name="runtime_permissions_additional_count">{count, plural,
- =1 {# additional permission}
- other {# additional permissions}
- }</string>
+ =1 {# additional permission}
+ other {# additional permissions}
+ }</string>
<!-- Runtime permissions preference summary, shown when the app has no permissions granted. [CHAR LIMIT=40] -->
<string name="runtime_permissions_summary_no_permissions_granted">No permissions granted</string>
@@ -9915,9 +9915,9 @@
<!-- Summary of number of apps that have not been used for months. [CHAR LIMIT=40]-->
<string name="unused_apps_summary">{count, plural,
- =1 {# unused app}
- other {# unused apps}
- }</string>
+ =1 {# unused app}
+ other {# unused apps}
+ }</string>
<!-- Label for category for unused app settings for an app. [CHAR LIMIT=40]-->
<string name="unused_apps_category">Unused app settings</string>
@@ -9985,9 +9985,9 @@
<!-- Summary for allow app to open supported links [CHAR LIMIT=42] -->
<string name="app_link_open_always_summary">{count, plural,
- =1 {App claims to handle # link}
- other {App claims to handle # links}
- }</string>
+ =1 {App claims to handle # link}
+ other {App claims to handle # links}
+ }</string>
<!-- Footer of open supported links settings [CHAR LIMIT=NONE] -->
<string name="open_supported_links_footer">App claims to handle following links:</string>
@@ -10257,9 +10257,9 @@
<!-- Description of number of apps using memory [CHAR LIMIT=NONE] -->
<string name="memory_usage_apps_summary">{count, plural,
- =1 {1 app used memory in the last {time}}
- other {# apps used memory in the last {time}}
- }</string>
+ =1 {1 app used memory in the last {time}}
+ other {# apps used memory in the last {time}}
+ }</string>
<!-- Label for toggle that enables the profiling/aggregating of memory usage [CHAR LIMIT=80]-->
<string name="force_enable_pss_profiling_title">Enable memory usage profiling</string>
@@ -10685,9 +10685,9 @@
<!-- Description of number of apps allowed to ignore Data Saver [CHAR LIMIT=NONE] -->
<string name="data_saver_unrestricted_summary">{count, plural,
- =1 {1 app allowed to use unrestricted mobile data when Data Saver is on}
- other {# apps allowed to use unrestricted mobile data when Data Saver is on}
- }</string>
+ =1 {1 app allowed to use unrestricted mobile data when Data Saver is on}
+ other {# apps allowed to use unrestricted mobile data when Data Saver is on}
+ }</string>
<!-- Data usage title text [CHAR LIMIT=30] -->
<string name="data_usage_title">Primary data</string>
@@ -10712,9 +10712,9 @@
<!-- Informational text about time left in billing cycle [CHAR LIMIT=60] -->
<string name="billing_cycle_days_left">{count, plural,
- =1 {# day left}
- other {# days left}
- }</string>
+ =1 {# day left}
+ other {# days left}
+ }</string>
<!-- Informational text about time left in billing cycle [CHAR LIMIT=60] -->
<string name="billing_cycle_none_left">No time remaining</string>
@@ -11291,9 +11291,9 @@
<string name="enterprise_privacy_apps_count_estimation_info">Number of apps is estimated. It may not include apps installed outside of the Play Store.</string>
<!-- Summary indicating the number of apps that a label (e.g. installed apps or apps granted a particular permission) refers to. The number shown is a minimum as there may be additional apps we do not know about. [CHAR LIMIT=NONE] -->
<string name="enterprise_privacy_number_packages_lower_bound">{count, plural,
- =1 {Minimum # app}
- other {Minimum # apps}
- }</string>
+ =1 {Minimum # app}
+ other {Minimum # apps}
+ }</string>
<!-- Label indicating that the admin granted one or more apps access to the device's location. [CHAR LIMIT=NONE] -->
<string name="enterprise_privacy_location_access">Location permissions</string>
<!-- Label indicating that the admin granted one or more apps access to the microphone. [CHAR LIMIT=NONE] -->
@@ -11304,9 +11304,9 @@
<string name="enterprise_privacy_enterprise_set_default_apps">Default apps</string>
<!-- Summary indicating the number of apps that a label (e.g. installed apps or apps granted a particular permission) refers to. [CHAR LIMIT=NONE] -->
<string name="enterprise_privacy_number_packages">{count, plural,
- =1 {# app}
- other {# apps}
- }</string>
+ =1 {# app}
+ other {# apps}
+ }</string>
<!-- Label explaining that the current input method was set by the admin. [CHAR LIMIT=NONE] -->
<string name="enterprise_privacy_input_method">Default keyboard</string>
<!-- Summary indicating the input method set by the admin. [CHAR LIMIT=NONE] -->
@@ -11327,9 +11327,9 @@
<string name="enterprise_privacy_ca_certs_work">Trusted credentials in your work profile</string>
<!-- Summary indicating the number of trusted CA certificates installed by the admin. The number shown is a minimum as there may be additional CA certificates we do not know about. [CHAR LIMIT=NONE] -->
<string name="enterprise_privacy_number_ca_certs">{count, plural,
- =1 {Minimum # CA certificate}
- other {Minimum # CA certificates}
- }</string>
+ =1 {Minimum # CA certificate}
+ other {Minimum # CA certificates}
+ }</string>
<!-- Label explaining that the admin can lock the device and change the user's password. [CHAR LIMIT=NONE] -->
<string name="enterprise_privacy_lock_device">Admin can lock the device and reset password</string>
<!-- Label explaining that the admin can wipe the device remotely. [CHAR LIMIT=NONE] -->
@@ -11340,9 +11340,9 @@
<string name="enterprise_privacy_failed_password_wipe_work">Failed password attempts before deleting work profile data</string>
<!-- Summary indicating the number of mistyped passwords after which the device or work profile wipes itself. [CHAR LIMIT=NONE] -->
<string name="enterprise_privacy_number_failed_password_wipe">{count, plural,
- =1 {# attempt}
- other {# attempts}
- }</string>
+ =1 {# attempt}
+ other {# attempts}
+ }</string>
<!-- Message indicating that the device is enterprise-managed by a Device Owner [CHAR LIMIT=NONE] -->
<string name="do_disclosure_generic">This device is managed by your organization.</string>
<!-- Message indicating that the device is enterprise-managed by a Device Owner [CHAR LIMIT=NONE] -->
@@ -11405,25 +11405,25 @@
<!-- Strings for displaying which applications were set as default for specific actions. -->
<!-- Title for the apps that have been set as default handlers of camera-related intents. [CHAR LIMIT=30] -->
<string name="default_camera_app_title">{count, plural,
- =1 {Camera app}
- other {Camera apps}
- }</string>
+ =1 {Camera app}
+ other {Camera apps}
+ }</string>
<!-- Title for the app that has been set as default handler of calendar-related intents. [CHAR LIMIT=30] -->
<string name="default_calendar_app_title">Calendar app</string>
<!-- Title for the app that has been set as default handler of contacts-related intents. [CHAR LIMIT=30] -->
<string name="default_contacts_app_title">Contacts app</string>
<!-- Title for the apps that have been set as default handlers of new email intents. [CHAR LIMIT=30] -->
<string name="default_email_app_title">{count, plural,
- =1 {Email client app}
- other {Email client apps}
- }</string>
+ =1 {Email client app}
+ other {Email client apps}
+ }</string>
<!-- Title for the app that has been set as default handler of geo-related intents. [CHAR LIMIT=30] -->
<string name="default_map_app_title">Map app</string>
<!-- Title for the apps that have been set as default handlers of call-related intents. [CHAR LIMIT=30] -->
<string name="default_phone_app_title">{count, plural,
- =1 {Phone app}
- other {Phone apps}
- }</string>
+ =1 {Phone app}
+ other {Phone apps}
+ }</string>
<!-- Template for concatenating two app names -->
<string name="app_names_concatenation_template_2"><xliff:g id="first_app_name">%1$s</xliff:g>, <xliff:g id="second_app_name">%2$s</xliff:g></string>
<!-- Template for concatenating three app names -->
@@ -11518,9 +11518,9 @@
<!-- Summary for passwords settings that shows how many passwords are saved for each autofill
service. [CHAR LIMIT=NONE] -->
<string name="autofill_passwords_count">{count, plural,
- =1 {# password}
- other {# passwords}
- }</string>
+ =1 {# password}
+ other {# passwords}
+ }</string>
<!-- DO NOT TRANSLATE Summary placeholder for when the passwords count is still loading or is
unavailable. -->
<string name="autofill_passwords_count_placeholder" translatable="false">\u2014</string>
@@ -12379,10 +12379,10 @@
<string name="choose_sim_title">Choose a SIM to use</string>
<!-- The body text of choose SIM activity. [CHAR LIMIT=NONE] -->
<string name="choose_sim_text">{count, plural,
- =1 {1 SIM is available on this device, but only one can be used at a time}
- =2 {2 SIMs are available on this device, but only one can be used at a time}
- other {# SIMs are available on this device, but only one can be used at a time}
- }</string>
+ =1 {1 SIM is available on this device, but only one can be used at a time}
+ =2 {2 SIMs are available on this device, but only one can be used at a time}
+ other {# SIMs are available on this device, but only one can be used at a time}
+ }</string>
<!-- String indicating that we are activating the profile [CHAR LIMIT=NONE] -->
<string name="choose_sim_activating">Turning on<xliff:g id="ellipsis" example="...">…</xliff:g></string>
<!-- String indicating that we failed to activate the selected profile [CHAR LIMIT=NONE] -->
@@ -12513,9 +12513,9 @@
<!-- Summary for the accessibility usage preference in the Privacy page. [CHAR LIMIT=NONE] -->
<string name="accessibility_usage_summary">{count, plural,
- =1 {1 app has full access to your device}
- other {# apps have full access to your device}
- }</string>
+ =1 {1 app has full access to your device}
+ other {# apps have full access to your device}
+ }</string>
<!-- Label for the title on wfc disclaimer fragment. [CHAR LIMIT=40] -->
<string name="wfc_disclaimer_title_text">Important information</string>
@@ -13268,9 +13268,9 @@
<!-- Background Install Control UI -->
<!-- [CHAR LIMIT=NONE] Preference Feature Summary -->
<string name="background_install_preference_summary">{count, plural,
- =1 {# app}
- other {# apps}
- }</string>
+ =1 {# app}
+ other {# apps}
+ }</string>
<!-- [CHAR LIMIT=NONE] Feature Title -->
<string name="background_install_title">Apps installed in the background</string>
@@ -13282,14 +13282,14 @@
<string name="background_install_uninstall_button_description">Uninstall app</string>
<!-- [CHAR LIMIT=NONE] Before time period group list title -->
<string name="background_install_before">{count, plural,
- =1 {Apps installed in the last # month}
- other {Apps installed in the last # months}
- }</string>
+ =1 {Apps installed in the last # month}
+ other {Apps installed in the last # months}
+ }</string>
<!-- [CHAR LIMIT=NONE] After time period group list title -->
<string name="background_install_after">{count, plural,
- =1 {Apps installed more than # month ago}
- other {Apps installed more than # months ago}
- }</string>
+ =1 {Apps installed more than # month ago}
+ other {Apps installed more than # months ago}
+ }</string>
<!-- App Aspect Ratio (User Aspect Ratio Override) -->
<!-- [CHAR LIMIT=60] Aspect ratio title setting to choose app aspect ratio -->
@@ -13482,11 +13482,11 @@
<!--Text for Stylus Pointer Icon preference -->
<string name="show_stylus_pointer_icon">Show pointer while hovering</string>
- <!-- Developer settings title: Media DRM settings screen. [CHAR LIMIT=50] -->
+ <!-- Developer settings title: Media DRM settings screen. [CHAR LIMIT=50] -->
<string name="media_drm_settings_title">Media DRM settings</string>
- <!-- Developer settings title: select whether to enable force Software Secure Crypto fallback. [CHAR LIMIT=50] -->
+ <!-- Developer settings title: select whether to enable force Software Secure Crypto fallback. [CHAR LIMIT=50] -->
<string name="force_swcrypto_fallback_title">Force Software Secure Crypto</string>
- <!-- Developer settings summary: select to force Software Secure Crypto.[CHAR LIMIT=NONE] -->
+ <!-- Developer settings summary: select to force Software Secure Crypto.[CHAR LIMIT=NONE] -->
<string name="force_swcrypto_fallback_summary">Force DRM key management to use software-based whitebox crypto</string>
<!--Text for acquire msg on UDFPS devices -->
@@ -13729,8 +13729,12 @@
<string name="contacts_storage_device_only_preference_summary">New contacts won\'t be synced with an account</string>
<!-- Text for explaining the selection in Contacts Storage Settings [CHAR LIMIT=NONE] -->
<string name="contacts_storage_selection_message">Contacts will be saved to your device and synced to your account by default</string>
+ <!-- Text for error toast when there's error setting the default account in Contacts Storage Settings [CHAR LIMIT=NONE] -->
+ <string name="contacts_storage_set_default_account_error_message">Error setting the default account</string>
<!-- Text for displaying when no account is set as default account [CHAR LIMIT=50] -->
- <string name="contacts_storage_no_account_set">No default set</string>
+ <string name="contacts_storage_no_account_set_summary">No default set</string>
+ <!-- Text for displaying when default account is set as local only [CHAR LIMIT=50] -->
+ <string name="contacts_storage_local_account_summary">Device only</string>
<!-- Text for add account selection message when no account has been added [CHAR LIMIT=100] -->
<string name="contacts_storage_first_time_add_account_message">Add an account to get started</string>
diff --git a/res/xml/power_background_usage_detail.xml b/res/xml/power_background_usage_detail.xml
index 5c7b6a5..32d80b5 100644
--- a/res/xml/power_background_usage_detail.xml
+++ b/res/xml/power_background_usage_detail.xml
@@ -25,22 +25,25 @@
android:layout="@layout/settings_entity_header"
android:selectable="false"/>
- <com.android.settingslib.widget.MainSwitchPreference
- android:key="allow_background_usage"
- android:title="@string/manager_battery_usage_allow_background_usage_title"
- settings:controller="com.android.settings.fuelgauge.AllowBackgroundPreferenceController"/>
+ <PreferenceCategory
+ android:key="battery_optimization_mode_category"
+ android:layout="@layout/settingslib_preference_category_no_title"
+ settings:controller="com.android.settings.fuelgauge.BatteryOptimizationModePreferenceController">
- <com.android.settingslib.widget.SelectorWithWidgetPreference
- android:key="optimized_preference"
- android:title="@string/manager_battery_usage_optimized_title"
- android:summary="@string/manager_battery_usage_optimized_summary"
- settings:controller="com.android.settings.fuelgauge.OptimizedPreferenceController"/>
+ <com.android.settingslib.widget.MainSwitchPreference
+ android:key="background_usage_allowability_switch"
+ android:title="@string/manager_battery_usage_allow_background_usage_title"/>
- <com.android.settingslib.widget.SelectorWithWidgetPreference
- android:key="unrestricted_preference"
- android:title="@string/manager_battery_usage_unrestricted_title"
- android:summary="@string/manager_battery_usage_unrestricted_summary"
- settings:controller="com.android.settings.fuelgauge.UnrestrictedPreferenceController"/>
+ <com.android.settingslib.widget.SelectorWithWidgetPreference
+ android:key="optimized_preference"
+ android:title="@string/manager_battery_usage_optimized_title"
+ android:summary="@string/manager_battery_usage_optimized_summary"/>
+
+ <com.android.settingslib.widget.SelectorWithWidgetPreference
+ android:key="unrestricted_preference"
+ android:title="@string/manager_battery_usage_unrestricted_title"
+ android:summary="@string/manager_battery_usage_unrestricted_summary"/>
+ </PreferenceCategory>
<com.android.settingslib.widget.FooterPreference
android:key="app_usage_footer_preference"
diff --git a/res/xml/power_usage_detail.xml b/res/xml/power_usage_detail.xml
index f3b30b6..655dbc5 100644
--- a/res/xml/power_usage_detail.xml
+++ b/res/xml/power_usage_detail.xml
@@ -48,12 +48,12 @@
<PreferenceCategory
android:title="@string/manager_battery_usage_category_title"
- android:key="manage_battery_usage_category">
+ android:key="background_usage_allowability_category"
+ settings:controller="com.android.settings.fuelgauge.BackgroundUsageAllowabilityPreferenceController">
<com.android.settingslib.PrimarySwitchPreference
- android:key="allow_background_usage"
- android:title="@string/manager_battery_usage_allow_background_usage_title"
- settings:controller="com.android.settings.fuelgauge.AllowBackgroundPreferenceController"/>
+ android:key="background_usage_allowability_switch"
+ android:title="@string/manager_battery_usage_allow_background_usage_title"/>
</PreferenceCategory>
diff --git a/src/com/android/settings/accessibility/ColorAndMotionScreen.kt b/src/com/android/settings/accessibility/ColorAndMotionScreen.kt
index 20a71e3..909b08b 100644
--- a/src/com/android/settings/accessibility/ColorAndMotionScreen.kt
+++ b/src/com/android/settings/accessibility/ColorAndMotionScreen.kt
@@ -17,16 +17,19 @@
package com.android.settings.accessibility
import android.content.Context
-import com.android.settings.flags.Flags
import com.android.settings.R
+import com.android.settings.flags.Flags
import com.android.settingslib.metadata.ProvidePreferenceScreen
import com.android.settingslib.metadata.preferenceHierarchy
import com.android.settingslib.preference.PreferenceScreenCreator
@ProvidePreferenceScreen
class ColorAndMotionScreen : PreferenceScreenCreator {
- override val key: String = KEY
- override val title: Int = R.string.accessibility_color_and_motion_title
+ override val key: String
+ get() = KEY
+
+ override val title: Int
+ get() = R.string.accessibility_color_and_motion_title
override fun isFlagEnabled(context: Context) = Flags.catalystAccessibilityColorAndMotion()
@@ -36,8 +39,7 @@
override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {}
-
companion object {
const val KEY = "accessibility_color_and_motion"
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/applications/contacts/ContactsStoragePreferenceController.java b/src/com/android/settings/applications/contacts/ContactsStoragePreferenceController.java
index bc6931d..6c179da 100644
--- a/src/com/android/settings/applications/contacts/ContactsStoragePreferenceController.java
+++ b/src/com/android/settings/applications/contacts/ContactsStoragePreferenceController.java
@@ -1,4 +1,3 @@
-
/*
* Copyright (C) 2024 The Android Open Source Project
*
@@ -16,12 +15,13 @@
*/
package com.android.settings.applications.contacts;
+import static android.provider.ContactsContract.RawContacts.DefaultAccount;
+
import android.accounts.Account;
import android.content.Context;
import android.os.UserHandle;
-import android.provider.ContactsContract;
-
-import androidx.preference.PreferenceScreen;
+import android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState;
+import android.util.Log;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
@@ -36,33 +36,53 @@
private final AuthenticatorHelper mAuthenticatorHelper;
+ private DefaultAccountAndState mCurrentDefaultAccountAndState;
+
public ContactsStoragePreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mAuthenticatorHelper = new AuthenticatorHelper(mContext,
new UserHandle(UserHandle.myUserId()), null);
+ try {
+ mCurrentDefaultAccountAndState =
+ DefaultAccount.getDefaultAccountForNewContacts(mContext.getContentResolver());
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "The default account is in an invalid state: " + e);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Failed to look up the default account: " + e);
+ }
}
@Override
public int getAvailabilityStatus() {
- return Flags.enableContactsDefaultAccountInSettings()
- ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ return (Flags.enableContactsDefaultAccountInSettings()
+ && mCurrentDefaultAccountAndState != null) ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
}
@Override
public CharSequence getSummary() {
- Account currentDefaultAccount =
- ContactsContract.Settings.getDefaultAccount(mContext.getContentResolver());
- if (currentDefaultAccount == null) {
- return mContext.getResources().getString(
- R.string.contacts_storage_no_account_set);
+ if (mCurrentDefaultAccountAndState != null) {
+ int currentDefaultAccountState = mCurrentDefaultAccountAndState.getState();
+ Account currentDefaultAccount = mCurrentDefaultAccountAndState.getAccount();
+ if (currentDefaultAccountState
+ == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_NOT_SET) {
+ return mContext.getResources().getString(
+ R.string.contacts_storage_no_account_set_summary);
+ } else if (currentDefaultAccountState
+ == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_LOCAL) {
+ return mContext.getResources().getString(
+ R.string.contacts_storage_local_account_summary);
+ } else if (currentDefaultAccount != null) {
+ String accountTypeLabel = (String) mAuthenticatorHelper.getLabelForType(mContext,
+ currentDefaultAccount.type);
+ // If there's no account type, or the account type is the same as the
+ // current default account name, just return the account name.
+ if (accountTypeLabel == null || accountTypeLabel.equals(
+ currentDefaultAccount.name)) {
+ return currentDefaultAccount.name;
+ }
+ return accountTypeLabel + " | " + currentDefaultAccount.name;
+ }
}
- String accountTypeLabel = (String) mAuthenticatorHelper.getLabelForType(mContext,
- currentDefaultAccount.type);
- // If there's no account type, or the account type is the same as the
- // current default account name, just return the account name.
- if (accountTypeLabel == null || accountTypeLabel.equals(currentDefaultAccount.name)) {
- return currentDefaultAccount.name;
- }
- return accountTypeLabel + " | " + currentDefaultAccount.name;
+ return "";
}
}
diff --git a/src/com/android/settings/applications/contacts/ContactsStorageSettings.java b/src/com/android/settings/applications/contacts/ContactsStorageSettings.java
index 90d593a..3d449cf 100644
--- a/src/com/android/settings/applications/contacts/ContactsStorageSettings.java
+++ b/src/com/android/settings/applications/contacts/ContactsStorageSettings.java
@@ -1,4 +1,3 @@
-
/*
* Copyright (C) 2020 The Android Open Source Project
*
@@ -17,25 +16,27 @@
package com.android.settings.applications.contacts;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.provider.ContactsContract.RawContacts.DefaultAccount;
import static android.provider.Settings.ACTION_ADD_ACCOUNT;
import static android.provider.Settings.EXTRA_ACCOUNT_TYPES;
import android.accounts.Account;
-import android.accounts.AccountManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.UserHandle;
-import android.provider.ContactsContract.Settings;
-
+import android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState;
+import android.widget.Toast;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceClickListener;
import androidx.preference.PreferenceScreen;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.accounts.AddAccountSettings;
import com.android.settings.dashboard.DashboardFragment;
@@ -46,6 +47,7 @@
import com.android.settingslib.widget.SelectorWithWidgetPreference;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -59,7 +61,7 @@
private static final String TAG = "ContactsStorageSettings";
private static final String PREF_KEY_ADD_ACCOUNT = "add_account";
private static final String PREF_KEY_DEVICE_ONLY = "device_only_account_preference";
- private final Map<String, Account> mAccountMap = new HashMap<>();
+ private final Map<String, DefaultAccountAndState> mAccountMap = new HashMap<>();
private AuthenticatorHelper mAuthenticatorHelper;
@Override
@@ -73,13 +75,18 @@
@Override
public void onRadioButtonClicked(@NonNull SelectorWithWidgetPreference selectedPref) {
final String selectedPreferenceKey = selectedPref.getKey();
- // Check if current provider is different from the selected provider.
+ // Check if current account is different from the selected account.
for (String preferenceKey : mAccountMap.keySet()) {
if (selectedPreferenceKey.equals(preferenceKey)) {
- selectedPref.setChecked(true);
- //TODO: Call DefaultAccount.setDefaultAccountForNewContacts once
- // the implementation is ready.
- Settings.setDefaultAccount(getContentResolver(), mAccountMap.get(preferenceKey));
+ try {
+ DefaultAccount.setDefaultAccountForNewContacts(getContentResolver(),
+ mAccountMap.get(preferenceKey));
+ selectedPref.setChecked(true);
+ } catch (RuntimeException e) {
+ Toast.makeText(getContext(),
+ R.string.contacts_storage_set_default_account_error_message,
+ Toast.LENGTH_SHORT).show();
+ }
} else {
SelectorWithWidgetPreference unSelectedPreference =
getPreferenceScreen().findPreference(preferenceKey);
@@ -92,10 +99,7 @@
public boolean onPreferenceClick(@NonNull Preference preference) {
if (PREF_KEY_ADD_ACCOUNT.equals(preference.getKey())) {
- Resources resources = Resources.getSystem();
- String[] accountTypesArray =
- resources.getStringArray(
- com.android.internal.R.array.config_rawContactsEligibleDefaultAccountTypes);
+ String[] accountTypesArray = getEligibleAccountTypes();
Intent intent = new Intent(ACTION_ADD_ACCOUNT);
intent.setClass(getContext(), AddAccountSettings.class);
intent.putExtra(EXTRA_ACCOUNT_TYPES, accountTypesArray);
@@ -108,7 +112,7 @@
@Override
public void onCreatePreferences(@NonNull Bundle savedInstanceState,
- @NonNull String rootKey) {
+ @NonNull String rootKey) {
super.onCreatePreferences(savedInstanceState, rootKey);
refreshUI();
}
@@ -119,48 +123,60 @@
// when creating eligible account preferences.
mAccountMap.clear();
final PreferenceScreen screen = getPreferenceScreen();
- AccountManager accountManager = AccountManager.get(getPrefContext());
- //TODO: Call DefaultAccount.getDefaultAccountForNewContacts once
- // implementation is ready.
- Account[] accounts = accountManager.getAccounts();
-
- for (int i = 0; i < accounts.length; i++) {
- screen.addPreference(buildAccountPreference(accounts[i], i));
+ List<Account> accounts = DefaultAccount.getEligibleCloudAccounts(getContentResolver());
+ for (int i = 0; i < accounts.size(); i++) {
+ screen.addPreference(buildAccountPreference(accounts.get(i), /*order=*/i));
}
- screen.addPreference(buildAddAccountPreference(accounts.length == 0));
+ // If there's no eligible account types, the "Add Account" preference should
+ // not be shown to the users.
+ if (getEligibleAccountTypes().length > 0) {
+ screen.addPreference(buildAddAccountPreference(accounts.isEmpty()));
+ }
setupDeviceOnlyPreference();
-
- //TODO: Call DefaultAccount.ListEligibleCloudAccounts once the
- // implementation is ready. And differentiate device only account vs account not set case.
- Account currentDefaultAccount = Settings.getDefaultAccount(getContentResolver());
- String preferenceKey = currentDefaultAccount != null ?
- String.valueOf(currentDefaultAccount.hashCode()) : PREF_KEY_DEVICE_ONLY;
- SelectorWithWidgetPreference preference = getPreferenceScreen().findPreference(
- preferenceKey);
- if (preference != null) {
- preference.setChecked(true);
- }
+ setDefaultAccountPreference();
}
private void setupDeviceOnlyPreference() {
SelectorWithWidgetPreference preference = findPreference(PREF_KEY_DEVICE_ONLY);
if (preference != null) {
preference.setOnClickListener(this);
- mAccountMap.put(PREF_KEY_DEVICE_ONLY, null);
+ mAccountMap.put(PREF_KEY_DEVICE_ONLY, DefaultAccountAndState.ofLocal());
+ }
+ }
+
+ private void setDefaultAccountPreference() {
+ DefaultAccountAndState currentDefaultAccountAndState =
+ DefaultAccount.getDefaultAccountForNewContacts(getContentResolver());
+ String preferenceKey = getAccountHashCode(currentDefaultAccountAndState);
+ Account currentDefaultAccount = currentDefaultAccountAndState.getAccount();
+
+ // Set the current default account preference to be checked if found among existing
+ // preferences. If not, then create a new preference for default account.
+ SelectorWithWidgetPreference preference = null;
+ if (mAccountMap.containsKey(preferenceKey)) {
+ preference = getPreferenceScreen().findPreference(preferenceKey);
+ } else if (preferenceKey != null && currentDefaultAccount != null) {
+ preference = buildAccountPreference(currentDefaultAccount, mAccountMap.size());
+ getPreferenceScreen().addPreference(preference);
+ }
+ if (preference != null) {
+ preference.setChecked(true);
}
}
//TODO: Add preference category on account preferences.
- private Preference buildAccountPreference(Account account, int order) {
+ private SelectorWithWidgetPreference buildAccountPreference(Account account, int order) {
SelectorWithWidgetPreference preference = new SelectorWithWidgetPreference(
getPrefContext());
+ DefaultAccountAndState accountAndState = DefaultAccountAndState.ofCloud(account);
+ String preferenceKey = getAccountHashCode(accountAndState);
preference.setTitle(mAuthenticatorHelper.getLabelForType(getPrefContext(), account.type));
preference.setIcon(mAuthenticatorHelper.getDrawableForType(getPrefContext(), account.type));
preference.setSummary(account.name);
- preference.setKey(String.valueOf(account.hashCode()));
+ preference.setKey(preferenceKey);
preference.setOnClickListener(this);
preference.setOrder(order);
- mAccountMap.put(String.valueOf(account.hashCode()), account);
+ mAccountMap.put(preferenceKey, accountAndState);
return preference;
}
@@ -178,6 +194,29 @@
return preference;
}
+ private @Nullable String getAccountHashCode(DefaultAccountAndState currentDefaultAccountAndState) {
+ Account currentDefaultAccount = currentDefaultAccountAndState.getAccount();
+ if (currentDefaultAccount != null && (currentDefaultAccountAndState.getState()
+ == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD
+ || currentDefaultAccountAndState.getState()
+ == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_SIM)) {
+ return String.valueOf(currentDefaultAccount.hashCode());
+ } else if (currentDefaultAccountAndState.getState()
+ == DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_LOCAL) {
+ return PREF_KEY_DEVICE_ONLY;
+ } else {
+ // If the account is not set or in error state, it should just return null and won't
+ // set the checked status in radio button.
+ return null;
+ }
+ }
+
+ @VisibleForTesting
+ String[] getEligibleAccountTypes() {
+ return Resources.getSystem().getStringArray(
+ com.android.internal.R.array.config_rawContactsEligibleDefaultAccountTypes);
+ }
+
@Override
protected int getPreferenceScreenResId() {
return R.xml.contacts_storage_settings;
diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
index e922f70..28d7d58 100644
--- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
@@ -26,13 +26,10 @@
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.UserHandle;
-import android.text.TextUtils;
import android.util.Log;
import android.view.View;
-import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
@@ -48,7 +45,6 @@
import com.android.settings.fuelgauge.batteryusage.BatteryEntry;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.EntityHeaderController;
-import com.android.settingslib.PrimarySwitchPreference;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -67,9 +63,7 @@
* 2. Battery related controls for app(i.e uninstall, force stop)
*/
public class AdvancedPowerUsageDetail extends DashboardFragment
- implements ButtonActionDialogFragment.AppButtonsDialogListener,
- Preference.OnPreferenceClickListener,
- Preference.OnPreferenceChangeListener {
+ implements ButtonActionDialogFragment.AppButtonsDialogListener {
public static final String TAG = "AdvancedPowerDetail";
public static final String EXTRA_UID = "extra_uid";
public static final String EXTRA_PACKAGE_NAME = "extra_package_name";
@@ -86,7 +80,8 @@
public static final String EXTRA_POWER_USAGE_AMOUNT = "extra_power_usage_amount";
private static final String KEY_PREF_HEADER = "header_view";
- private static final String KEY_ALLOW_BACKGROUND_USAGE = "allow_background_usage";
+ private static final String KEY_BACKGROUND_USAGE_ALLOWABILITY_CATEGORY =
+ "background_usage_allowability_category";
private static final int REQUEST_UNINSTALL = 0;
private static final int REQUEST_REMOVE_DEVICE_ADMIN = 1;
@@ -96,11 +91,9 @@
private AppButtonsPreferenceController mAppButtonsPreferenceController;
private PowerUsageTimeController mPowerUsageTimeController;
- @VisibleForTesting LayoutPreference mHeaderPreference;
@VisibleForTesting ApplicationsState mState;
@VisibleForTesting ApplicationsState.AppEntry mAppEntry;
@VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
- @VisibleForTesting PrimarySwitchPreference mAllowBackgroundUsagePreference;
@VisibleForTesting @BatteryOptimizeUtils.OptimizationMode
int mOptimizationMode = BatteryOptimizeUtils.MODE_UNKNOWN;
@@ -242,17 +235,11 @@
public void onAttach(Activity activity) {
super.onAttach(activity);
+ final Bundle bundle = getArguments();
+ final int uid = bundle.getInt(EXTRA_UID, 0);
+ final String packageName = bundle.getString(EXTRA_PACKAGE_NAME);
+ mBatteryOptimizeUtils = new BatteryOptimizeUtils(getContext(), uid, packageName);
mState = ApplicationsState.getInstance(getActivity().getApplication());
- }
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- final String packageName = getArguments().getString(EXTRA_PACKAGE_NAME);
- onCreateBackgroundUsageState(packageName);
- mHeaderPreference = findPreference(KEY_PREF_HEADER);
-
if (packageName != null) {
mAppEntry = mState.getEntry(packageName, UserHandle.myUserId());
}
@@ -264,7 +251,6 @@
initHeader();
mOptimizationMode = mBatteryOptimizeUtils.getAppOptimizationMode();
- initFooter();
mLogStringBuilder = new StringBuilder("onResume mode = ").append(mOptimizationMode);
}
@@ -299,7 +285,8 @@
@VisibleForTesting
void initHeader() {
- final View appSnippet = mHeaderPreference.findViewById(R.id.entity_header);
+ final LayoutPreference headerPreference = findPreference(KEY_PREF_HEADER);
+ final View appSnippet = headerPreference.findViewById(R.id.entity_header);
final Activity context = getActivity();
final Bundle bundle = getArguments();
EntityHeaderController controller =
@@ -340,31 +327,6 @@
controller.done(true /* rebindActions */);
}
- @VisibleForTesting
- void initFooter() {
- final String stateString;
- final String detailInfoString;
- final Context context = getContext();
-
- if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
- // Present optimized only string when the package name is invalid.
- stateString = context.getString(R.string.manager_battery_usage_optimized_only);
- detailInfoString =
- context.getString(R.string.manager_battery_usage_footer_limited, stateString);
- } else if (mBatteryOptimizeUtils.isSystemOrDefaultApp()) {
- // Present unrestricted only string when the package is system or default active app.
- stateString = context.getString(R.string.manager_battery_usage_unrestricted_only);
- detailInfoString =
- context.getString(R.string.manager_battery_usage_footer_limited, stateString);
- } else {
- // Present default string to normal app.
- detailInfoString =
- context.getString(
- R.string.manager_battery_usage_allow_background_usage_summary);
- }
- mAllowBackgroundUsagePreference.setSummary(detailInfoString);
- }
-
@Override
public int getMetricsCategory() {
return SettingsEnums.FUELGAUGE_POWER_USAGE_DETAIL;
@@ -384,7 +346,6 @@
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
final Bundle bundle = getArguments();
- final int uid = bundle.getInt(EXTRA_UID, 0);
final String packageName = bundle.getString(EXTRA_PACKAGE_NAME);
mAppButtonsPreferenceController =
@@ -401,7 +362,12 @@
controllers.add(mPowerUsageTimeController);
}
controllers.add(mAppButtonsPreferenceController);
- controllers.add(new AllowBackgroundPreferenceController(context, uid, packageName));
+ controllers.add(
+ new BackgroundUsageAllowabilityPreferenceController(
+ context,
+ /* dashboardFragment= */ this,
+ KEY_BACKGROUND_USAGE_ALLOWABILITY_CATEGORY,
+ mBatteryOptimizeUtils));
return controllers;
}
@@ -421,34 +387,6 @@
}
}
- @Override
- public boolean onPreferenceClick(Preference preference) {
- if (!(preference instanceof PrimarySwitchPreference)
- || !TextUtils.equals(preference.getKey(), KEY_ALLOW_BACKGROUND_USAGE)) {
- return false;
- }
- PowerBackgroundUsageDetail.startPowerBackgroundUsageDetailPage(
- getContext(), getArguments());
- return true;
- }
-
- @Override
- public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) {
- if (!(preference instanceof PrimarySwitchPreference)
- || !TextUtils.equals(preference.getKey(), KEY_ALLOW_BACKGROUND_USAGE)) {
- return false;
- }
- if (newValue instanceof Boolean) {
- final boolean isAllowBackgroundUsage = (boolean) newValue;
- mBatteryOptimizeUtils.setAppUsageState(
- isAllowBackgroundUsage
- ? BatteryOptimizeUtils.MODE_OPTIMIZED
- : BatteryOptimizeUtils.MODE_RESTRICTED,
- Action.APPLY);
- }
- return true;
- }
-
private void logMetricCategory(int currentOptimizeMode) {
if (currentOptimizeMode == mOptimizationMode) {
return;
@@ -482,16 +420,4 @@
getArguments().getInt(EXTRA_POWER_USAGE_AMOUNT));
});
}
-
- private void onCreateBackgroundUsageState(String packageName) {
- mAllowBackgroundUsagePreference = findPreference(KEY_ALLOW_BACKGROUND_USAGE);
- if (mAllowBackgroundUsagePreference != null) {
- mAllowBackgroundUsagePreference.setOnPreferenceClickListener(this);
- mAllowBackgroundUsagePreference.setOnPreferenceChangeListener(this);
- }
-
- mBatteryOptimizeUtils =
- new BatteryOptimizeUtils(
- getContext(), getArguments().getInt(EXTRA_UID), packageName);
- }
}
diff --git a/src/com/android/settings/fuelgauge/AllowBackgroundPreferenceController.java b/src/com/android/settings/fuelgauge/AllowBackgroundPreferenceController.java
deleted file mode 100644
index 52cec795..0000000
--- a/src/com/android/settings/fuelgauge/AllowBackgroundPreferenceController.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.fuelgauge;
-
-import android.content.Context;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.PrimarySwitchPreference;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.widget.MainSwitchPreference;
-
-/** Controller to update the app background usage state */
-public class AllowBackgroundPreferenceController extends AbstractPreferenceController
- implements PreferenceControllerMixin {
-
- private static final String TAG = "AllowBackgroundPreferenceController";
-
- @VisibleForTesting static final String KEY_ALLOW_BACKGROUND_USAGE = "allow_background_usage";
-
- @VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
-
- public AllowBackgroundPreferenceController(Context context, int uid, String packageName) {
- super(context);
- mBatteryOptimizeUtils = new BatteryOptimizeUtils(context, uid, packageName);
- }
-
- private void setChecked(Preference preference, boolean checked) {
- if (preference instanceof PrimarySwitchPreference) {
- ((PrimarySwitchPreference) preference).setChecked(checked);
- } else if (preference instanceof MainSwitchPreference) {
- ((MainSwitchPreference) preference).setChecked(checked);
- }
- }
-
- private void setEnabled(Preference preference, boolean enabled) {
- if (preference instanceof PrimarySwitchPreference) {
- ((PrimarySwitchPreference) preference).setEnabled(enabled);
- ((PrimarySwitchPreference) preference).setSwitchEnabled(enabled);
- } else if (preference instanceof MainSwitchPreference) {
- ((MainSwitchPreference) preference).setEnabled(enabled);
- }
- }
-
- @Override
- public void updateState(Preference preference) {
- setEnabled(preference, mBatteryOptimizeUtils.isOptimizeModeMutable());
-
- final boolean isAllowBackground =
- mBatteryOptimizeUtils.getAppOptimizationMode()
- != BatteryOptimizeUtils.MODE_RESTRICTED;
- setChecked(preference, isAllowBackground);
- }
-
- @Override
- public boolean isAvailable() {
- return true;
- }
-
- @Override
- public String getPreferenceKey() {
- return KEY_ALLOW_BACKGROUND_USAGE;
- }
-
- @Override
- public boolean handlePreferenceTreeClick(Preference preference) {
- return getPreferenceKey().equals(preference.getKey());
- }
-}
diff --git a/src/com/android/settings/fuelgauge/BackgroundUsageAllowabilityPreferenceController.java b/src/com/android/settings/fuelgauge/BackgroundUsageAllowabilityPreferenceController.java
new file mode 100644
index 0000000..bce439b
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/BackgroundUsageAllowabilityPreferenceController.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.PrimarySwitchPreference;
+
+/** Controller to update the manage battery usage preference in App Battery Usage page */
+public class BackgroundUsageAllowabilityPreferenceController extends BasePreferenceController
+ implements PreferenceControllerMixin {
+
+ @VisibleForTesting
+ static final String KEY_BACKGROUND_USAGE_ALLOWABILITY_SWITCH =
+ "background_usage_allowability_switch";
+
+ private final BatteryOptimizeUtils mBatteryOptimizeUtils;
+ private final DashboardFragment mDashboardFragment;
+ @Nullable @VisibleForTesting PrimarySwitchPreference mBackgroundUsageAllowabilityPreference;
+
+ public BackgroundUsageAllowabilityPreferenceController(
+ @NonNull Context context,
+ @NonNull DashboardFragment dashboardFragment,
+ @NonNull String preferenceKey,
+ @NonNull BatteryOptimizeUtils batteryOptimizeUtils) {
+ super(context, preferenceKey);
+ mDashboardFragment = dashboardFragment;
+ mBatteryOptimizeUtils = batteryOptimizeUtils;
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public void updateState(@NonNull Preference preference) {
+ updatePreferences(mBatteryOptimizeUtils.getAppOptimizationMode());
+ }
+
+ @Override
+ public void displayPreference(@NonNull PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mBackgroundUsageAllowabilityPreference =
+ screen.findPreference(KEY_BACKGROUND_USAGE_ALLOWABILITY_SWITCH);
+ initPreferences();
+ }
+
+ @VisibleForTesting
+ void initPreferences() {
+ if (mBackgroundUsageAllowabilityPreference == null) {
+ return;
+ }
+ final String stateString;
+ final String detailInfoString;
+ boolean isPreferenceEnabled = true;
+ if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
+ // Present "Optimized" only string if the package name is invalid.
+ stateString = mContext.getString(R.string.manager_battery_usage_optimized_only);
+ detailInfoString =
+ mContext.getString(R.string.manager_battery_usage_footer_limited, stateString);
+ isPreferenceEnabled = false;
+ } else if (mBatteryOptimizeUtils.isSystemOrDefaultApp()) {
+ // Present "Unrestricted" only string if the package is system important apps.
+ stateString = mContext.getString(R.string.manager_battery_usage_unrestricted_only);
+ detailInfoString =
+ mContext.getString(R.string.manager_battery_usage_footer_limited, stateString);
+ isPreferenceEnabled = false;
+ } else {
+ // Present default string to normal app.
+ detailInfoString =
+ mContext.getString(
+ R.string.manager_battery_usage_allow_background_usage_summary);
+ }
+ mBackgroundUsageAllowabilityPreference.setEnabled(isPreferenceEnabled);
+ mBackgroundUsageAllowabilityPreference.setSwitchEnabled(isPreferenceEnabled);
+ mBackgroundUsageAllowabilityPreference.setSummary(detailInfoString);
+ if (isPreferenceEnabled) {
+ mBackgroundUsageAllowabilityPreference.setOnPreferenceClickListener(
+ preference -> {
+ PowerBackgroundUsageDetail.startPowerBackgroundUsageDetailPage(
+ mContext, mDashboardFragment.getArguments());
+ return true;
+ });
+ mBackgroundUsageAllowabilityPreference.setOnPreferenceChangeListener(
+ (preference, isAllowBackground) -> {
+ handleBatteryOptimizeModeUpdated(
+ (boolean) isAllowBackground
+ ? BatteryOptimizeUtils.MODE_OPTIMIZED
+ : BatteryOptimizeUtils.MODE_RESTRICTED);
+ return true;
+ });
+ }
+ }
+
+ @VisibleForTesting
+ void handleBatteryOptimizeModeUpdated(int newBatteryOptimizeMode) {
+ if (mBatteryOptimizeUtils.getAppOptimizationMode() == newBatteryOptimizeMode) {
+ Log.w(TAG, "ignore same mode for: " + mBatteryOptimizeUtils.getPackageName());
+ return;
+ }
+ mBatteryOptimizeUtils.setAppUsageState(
+ newBatteryOptimizeMode, BatteryOptimizeHistoricalLogEntry.Action.APPLY);
+ updatePreferences(newBatteryOptimizeMode);
+ }
+
+ @VisibleForTesting
+ void updatePreferences(int optimizationMode) {
+ if (mBackgroundUsageAllowabilityPreference == null) {
+ return;
+ }
+ mBackgroundUsageAllowabilityPreference.setChecked(
+ optimizationMode != BatteryOptimizeUtils.MODE_RESTRICTED);
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/BatteryOptimizationModePreferenceController.java b/src/com/android/settings/fuelgauge/BatteryOptimizationModePreferenceController.java
new file mode 100644
index 0000000..0a4cbac
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/BatteryOptimizationModePreferenceController.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.widget.MainSwitchPreference;
+import com.android.settingslib.widget.SelectorWithWidgetPreference;
+
+/** Controller to update the app background usage mode state in Allow background usage page */
+public class BatteryOptimizationModePreferenceController extends BasePreferenceController
+ implements PreferenceControllerMixin {
+
+ @VisibleForTesting
+ static final String KEY_BACKGROUND_USAGE_ALLOWABILITY_SWITCH =
+ "background_usage_allowability_switch";
+
+ @VisibleForTesting static final String KEY_OPTIMIZED_PREF = "optimized_preference";
+ @VisibleForTesting static final String KEY_UNRESTRICTED_PREF = "unrestricted_preference";
+
+ private final BatteryOptimizeUtils mBatteryOptimizeUtils;
+ @Nullable @VisibleForTesting MainSwitchPreference mBackgroundUsageAllowabilityPreference;
+ @Nullable @VisibleForTesting SelectorWithWidgetPreference mOptimizedPreference;
+ @Nullable @VisibleForTesting SelectorWithWidgetPreference mUnrestrictedPreference;
+
+ public BatteryOptimizationModePreferenceController(
+ @NonNull Context context,
+ @NonNull String preferenceKey,
+ @NonNull BatteryOptimizeUtils batteryOptimizeUtils) {
+ super(context, preferenceKey);
+ mBatteryOptimizeUtils = batteryOptimizeUtils;
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public void updateState(@NonNull Preference preference) {
+ updatePreferences(mBatteryOptimizeUtils.getAppOptimizationMode());
+ }
+
+ @Override
+ public void displayPreference(@NonNull PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mBackgroundUsageAllowabilityPreference =
+ screen.findPreference(KEY_BACKGROUND_USAGE_ALLOWABILITY_SWITCH);
+ mOptimizedPreference = screen.findPreference(KEY_OPTIMIZED_PREF);
+ mUnrestrictedPreference = screen.findPreference(KEY_UNRESTRICTED_PREF);
+ initPreferences();
+ }
+
+ @VisibleForTesting
+ void initPreferences() {
+ if (mBackgroundUsageAllowabilityPreference == null
+ || mOptimizedPreference == null
+ || mUnrestrictedPreference == null) {
+ return;
+ }
+ final boolean isEnabled = mBatteryOptimizeUtils.isOptimizeModeMutable();
+ mBackgroundUsageAllowabilityPreference.setEnabled(isEnabled);
+ mOptimizedPreference.setEnabled(isEnabled);
+ mUnrestrictedPreference.setEnabled(isEnabled);
+ if (isEnabled) {
+ mBackgroundUsageAllowabilityPreference.setOnPreferenceChangeListener(
+ (preference, isAllowBackground) -> {
+ handleBatteryOptimizeModeUpdated(
+ (boolean) isAllowBackground
+ ? BatteryOptimizeUtils.MODE_OPTIMIZED
+ : BatteryOptimizeUtils.MODE_RESTRICTED);
+ return true;
+ });
+ mOptimizedPreference.setOnPreferenceClickListener(
+ preference -> {
+ handleBatteryOptimizeModeUpdated(BatteryOptimizeUtils.MODE_OPTIMIZED);
+ return true;
+ });
+ mUnrestrictedPreference.setOnPreferenceClickListener(
+ preference -> {
+ handleBatteryOptimizeModeUpdated(BatteryOptimizeUtils.MODE_UNRESTRICTED);
+ return true;
+ });
+ }
+ }
+
+ @VisibleForTesting
+ void updatePreferences(int optimizationMode) {
+ if (mBackgroundUsageAllowabilityPreference == null
+ || mOptimizedPreference == null
+ || mUnrestrictedPreference == null) {
+ return;
+ }
+ final boolean isAllowBackground = optimizationMode != BatteryOptimizeUtils.MODE_RESTRICTED;
+ mBackgroundUsageAllowabilityPreference.setChecked(isAllowBackground);
+ mOptimizedPreference.setEnabled(isAllowBackground);
+ mUnrestrictedPreference.setEnabled(isAllowBackground);
+ mOptimizedPreference.setChecked(optimizationMode == BatteryOptimizeUtils.MODE_OPTIMIZED);
+ mUnrestrictedPreference.setChecked(
+ optimizationMode == BatteryOptimizeUtils.MODE_UNRESTRICTED);
+ }
+
+ @VisibleForTesting
+ void handleBatteryOptimizeModeUpdated(int newBatteryOptimizeMode) {
+ if (mBatteryOptimizeUtils.getAppOptimizationMode() == newBatteryOptimizeMode) {
+ Log.w(TAG, "ignore same mode for: " + mBatteryOptimizeUtils.getPackageName());
+ return;
+ }
+ mBatteryOptimizeUtils.setAppUsageState(
+ newBatteryOptimizeMode, BatteryOptimizeHistoricalLogEntry.Action.APPLY);
+ updatePreferences(newBatteryOptimizeMode);
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/OptimizedPreferenceController.java b/src/com/android/settings/fuelgauge/OptimizedPreferenceController.java
deleted file mode 100644
index a26ab7a..0000000
--- a/src/com/android/settings/fuelgauge/OptimizedPreferenceController.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.fuelgauge;
-
-import android.content.Context;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.widget.SelectorWithWidgetPreference;
-
-public class OptimizedPreferenceController extends AbstractPreferenceController
- implements PreferenceControllerMixin {
-
- private static final String TAG = "OPTIMIZED_PREF";
-
- @VisibleForTesting static final String KEY_OPTIMIZED_PREF = "optimized_preference";
- @VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
-
- public OptimizedPreferenceController(Context context, int uid, String packageName) {
- super(context);
- mBatteryOptimizeUtils = new BatteryOptimizeUtils(context, uid, packageName);
- }
-
- @Override
- public boolean isAvailable() {
- return true;
- }
-
- @Override
- public void updateState(Preference preference) {
- preference.setEnabled(mBatteryOptimizeUtils.isSelectorPreferenceEnabled());
-
- final boolean isOptimized =
- mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()
- || mBatteryOptimizeUtils.getAppOptimizationMode()
- == BatteryOptimizeUtils.MODE_OPTIMIZED;
- ((SelectorWithWidgetPreference) preference).setChecked(isOptimized);
- }
-
- @Override
- public String getPreferenceKey() {
- return KEY_OPTIMIZED_PREF;
- }
-
- @Override
- public boolean handlePreferenceTreeClick(Preference preference) {
- return getPreferenceKey().equals(preference.getKey());
- }
-}
diff --git a/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetail.java b/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetail.java
index e59cc4ad..dadf2e8 100644
--- a/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetail.java
@@ -24,11 +24,8 @@
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
-import android.text.TextUtils;
import android.util.Log;
import android.view.View;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
import androidx.annotation.VisibleForTesting;
@@ -44,8 +41,6 @@
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.widget.FooterPreference;
import com.android.settingslib.widget.LayoutPreference;
-import com.android.settingslib.widget.MainSwitchPreference;
-import com.android.settingslib.widget.SelectorWithWidgetPreference;
import java.util.ArrayList;
import java.util.List;
@@ -53,8 +48,7 @@
import java.util.concurrent.Executors;
/** Allow background usage fragment for each app */
-public class PowerBackgroundUsageDetail extends DashboardFragment
- implements SelectorWithWidgetPreference.OnClickListener, OnCheckedChangeListener {
+public class PowerBackgroundUsageDetail extends DashboardFragment {
private static final String TAG = "PowerBackgroundUsageDetail";
public static final String EXTRA_UID = "extra_uid";
@@ -63,21 +57,15 @@
public static final String EXTRA_POWER_USAGE_AMOUNT = "extra_power_usage_amount";
public static final String EXTRA_ICON_ID = "extra_icon_id";
private static final String KEY_PREF_HEADER = "header_view";
- private static final String KEY_PREF_UNRESTRICTED = "unrestricted_preference";
- private static final String KEY_PREF_OPTIMIZED = "optimized_preference";
- private static final String KEY_ALLOW_BACKGROUND_USAGE = "allow_background_usage";
private static final String KEY_FOOTER_PREFERENCE = "app_usage_footer_preference";
+ private static final String KEY_BATTERY_OPTIMIZATION_MODE_CATEGORY =
+ "battery_optimization_mode_category";
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
- @VisibleForTesting LayoutPreference mHeaderPreference;
@VisibleForTesting ApplicationsState mState;
@VisibleForTesting ApplicationsState.AppEntry mAppEntry;
@VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
- @VisibleForTesting SelectorWithWidgetPreference mOptimizePreference;
- @VisibleForTesting SelectorWithWidgetPreference mUnrestrictedPreference;
- @VisibleForTesting MainSwitchPreference mMainSwitchPreference;
- @VisibleForTesting FooterPreference mFooterPreference;
@VisibleForTesting StringBuilder mLogStringBuilder;
@VisibleForTesting @BatteryOptimizeUtils.OptimizationMode
@@ -87,17 +75,11 @@
public void onAttach(Activity activity) {
super.onAttach(activity);
+ final Bundle bundle = getArguments();
+ final int uid = bundle.getInt(EXTRA_UID, 0);
+ final String packageName = bundle.getString(EXTRA_PACKAGE_NAME);
+ mBatteryOptimizeUtils = new BatteryOptimizeUtils(getContext(), uid, packageName);
mState = ApplicationsState.getInstance(getActivity().getApplication());
- }
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- final String packageName = getArguments().getString(EXTRA_PACKAGE_NAME);
- onCreateBackgroundUsageState(packageName);
- mHeaderPreference = findPreference(KEY_PREF_HEADER);
-
if (packageName != null) {
mAppEntry = mState.getEntry(packageName, UserHandle.myUserId());
}
@@ -107,8 +89,8 @@
public void onResume() {
super.onResume();
initHeader();
- mOptimizationMode = mBatteryOptimizeUtils.getAppOptimizationMode();
initFooter();
+ mOptimizationMode = mBatteryOptimizeUtils.getAppOptimizationMode();
mLogStringBuilder = new StringBuilder("onResume mode = ").append(mOptimizationMode);
}
@@ -137,34 +119,16 @@
}
@Override
- public void onRadioButtonClicked(SelectorWithWidgetPreference selected) {
- final String selectedKey = selected == null ? null : selected.getKey();
- updateSelectorPreferenceState(mUnrestrictedPreference, selectedKey);
- updateSelectorPreferenceState(mOptimizePreference, selectedKey);
- mBatteryOptimizeUtils.setAppUsageState(getSelectedPreference(), Action.APPLY);
- }
-
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- mMainSwitchPreference.setChecked(isChecked);
- updateSelectorPreference(isChecked);
- }
-
- @Override
public int getMetricsCategory() {
return SettingsEnums.FUELGAUGE_POWER_USAGE_MANAGE_BACKGROUND;
}
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
- final List<AbstractPreferenceController> controllers = new ArrayList<>();
- final Bundle bundle = getArguments();
- final int uid = bundle.getInt(EXTRA_UID, 0);
- final String packageName = bundle.getString(EXTRA_PACKAGE_NAME);
-
- controllers.add(new AllowBackgroundPreferenceController(context, uid, packageName));
- controllers.add(new OptimizedPreferenceController(context, uid, packageName));
- controllers.add(new UnrestrictedPreferenceController(context, uid, packageName));
+ final List<AbstractPreferenceController> controllers = new ArrayList<>(1);
+ controllers.add(
+ new BatteryOptimizationModePreferenceController(
+ context, KEY_BATTERY_OPTIMIZATION_MODE_CATEGORY, mBatteryOptimizeUtils));
return controllers;
}
@@ -179,26 +143,6 @@
return TAG;
}
- @VisibleForTesting
- void updateSelectorPreference(boolean isEnabled) {
- mOptimizePreference.setEnabled(isEnabled);
- mUnrestrictedPreference.setEnabled(isEnabled);
- onRadioButtonClicked(isEnabled ? mOptimizePreference : null);
- }
-
- @VisibleForTesting
- int getSelectedPreference() {
- if (!mMainSwitchPreference.isChecked()) {
- return BatteryOptimizeUtils.MODE_RESTRICTED;
- } else if (mUnrestrictedPreference.isChecked()) {
- return BatteryOptimizeUtils.MODE_UNRESTRICTED;
- } else if (mOptimizePreference.isChecked()) {
- return BatteryOptimizeUtils.MODE_OPTIMIZED;
- } else {
- return BatteryOptimizeUtils.MODE_UNKNOWN;
- }
- }
-
static void startPowerBackgroundUsageDetailPage(Context context, Bundle args) {
new SubSettingLauncher(context)
.setDestination(PowerBackgroundUsageDetail.class.getName())
@@ -209,7 +153,11 @@
@VisibleForTesting
void initHeader() {
- final View appSnippet = mHeaderPreference.findViewById(R.id.entity_header);
+ final LayoutPreference headerPreference = findPreference(KEY_PREF_HEADER);
+ if (headerPreference == null) {
+ return;
+ }
+ final View appSnippet = headerPreference.findViewById(R.id.entity_header);
final Activity context = getActivity();
final Bundle bundle = getArguments();
EntityHeaderController controller =
@@ -239,58 +187,25 @@
@VisibleForTesting
void initFooter() {
- final String stateString;
- final String footerString;
- final Context context = getContext();
-
- if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
- // Present optimized only string when the package name is invalid.
- stateString = context.getString(R.string.manager_battery_usage_optimized_only);
- footerString =
- context.getString(R.string.manager_battery_usage_footer_limited, stateString);
- } else if (mBatteryOptimizeUtils.isSystemOrDefaultApp()) {
- // Present unrestricted only string when the package is system or default active app.
- stateString = context.getString(R.string.manager_battery_usage_unrestricted_only);
- footerString =
- context.getString(R.string.manager_battery_usage_footer_limited, stateString);
- } else {
- // Present default string to normal app.
- footerString = context.getString(R.string.manager_battery_usage_footer);
+ final FooterPreference footerPreference = findPreference(KEY_FOOTER_PREFERENCE);
+ if (footerPreference == null) {
+ return;
}
- mFooterPreference.setTitle(footerString);
+ final Context context = getContext();
+ footerPreference.setTitle(context.getString(R.string.manager_battery_usage_footer));
final Intent helpIntent =
HelpUtils.getHelpIntent(
context,
context.getString(R.string.help_url_app_usage_settings),
/* backupContext= */ "");
if (helpIntent != null) {
- mFooterPreference.setLearnMoreAction(
+ footerPreference.setLearnMoreAction(
v -> startActivityForResult(helpIntent, /* requestCode= */ 0));
- mFooterPreference.setLearnMoreText(
+ footerPreference.setLearnMoreText(
context.getString(R.string.manager_battery_usage_link_a11y));
}
}
- private void onCreateBackgroundUsageState(String packageName) {
- mOptimizePreference = findPreference(KEY_PREF_OPTIMIZED);
- mUnrestrictedPreference = findPreference(KEY_PREF_UNRESTRICTED);
- mMainSwitchPreference = findPreference(KEY_ALLOW_BACKGROUND_USAGE);
- mFooterPreference = findPreference(KEY_FOOTER_PREFERENCE);
-
- mOptimizePreference.setOnClickListener(this);
- mUnrestrictedPreference.setOnClickListener(this);
- mMainSwitchPreference.addOnSwitchChangeListener(this);
-
- mBatteryOptimizeUtils =
- new BatteryOptimizeUtils(
- getContext(), getArguments().getInt(EXTRA_UID), packageName);
- }
-
- private void updateSelectorPreferenceState(
- SelectorWithWidgetPreference preference, String selectedKey) {
- preference.setChecked(TextUtils.equals(selectedKey, preference.getKey()));
- }
-
private void logMetricCategory(int currentOptimizeMode) {
if (currentOptimizeMode == mOptimizationMode) {
return;
diff --git a/src/com/android/settings/fuelgauge/UnrestrictedPreferenceController.java b/src/com/android/settings/fuelgauge/UnrestrictedPreferenceController.java
deleted file mode 100644
index 652941b..0000000
--- a/src/com/android/settings/fuelgauge/UnrestrictedPreferenceController.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.fuelgauge;
-
-import android.content.Context;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.widget.SelectorWithWidgetPreference;
-
-public class UnrestrictedPreferenceController extends AbstractPreferenceController
- implements PreferenceControllerMixin {
-
- private static final String TAG = "UNRESTRICTED_PREF";
-
- @VisibleForTesting static final String KEY_UNRESTRICTED_PREF = "unrestricted_preference";
-
- @VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
-
- public UnrestrictedPreferenceController(Context context, int uid, String packageName) {
- super(context);
- mBatteryOptimizeUtils = new BatteryOptimizeUtils(context, uid, packageName);
- }
-
- @Override
- public void updateState(Preference preference) {
- preference.setEnabled(mBatteryOptimizeUtils.isSelectorPreferenceEnabled());
-
- final boolean isUnrestricted =
- mBatteryOptimizeUtils.getAppOptimizationMode()
- == BatteryOptimizeUtils.MODE_UNRESTRICTED;
- ((SelectorWithWidgetPreference) preference).setChecked(isUnrestricted);
- }
-
- @Override
- public boolean isAvailable() {
- return true;
- }
-
- @Override
- public String getPreferenceKey() {
- return KEY_UNRESTRICTED_PREF;
- }
-
- @Override
- public boolean handlePreferenceTreeClick(Preference preference) {
- return getPreferenceKey().equals(preference.getKey());
- }
-}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
index ad487ef..0998e2d 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
@@ -31,8 +31,6 @@
import android.os.AsyncTask;
import android.os.BatteryManager;
import android.os.BatteryUsageStats;
-import android.os.Handler;
-import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserManager;
@@ -66,12 +64,6 @@
public final class DatabaseUtils {
private static final String TAG = "DatabaseUtils";
private static final String SHARED_PREFS_FILE = "battery_usage_shared_prefs";
- private static final boolean EXPLICIT_CLEAR_MEMORY_ENABLED = false;
-
- /** Clear memory threshold for device booting phase. */
- private static final long CLEAR_MEMORY_THRESHOLD_MS = Duration.ofMinutes(5).toMillis();
-
- private static final long CLEAR_MEMORY_DELAYED_MS = Duration.ofSeconds(2).toMillis();
private static final long INVALID_TIMESTAMP = 0L;
static final int DATA_RETENTION_INTERVAL_DAY = 9;
@@ -593,7 +585,6 @@
String.format(
"sendAppUsageEventData() size=%d in %d/ms",
size, (System.currentTimeMillis() - startTime)));
- clearMemory();
return valuesList;
}
@@ -613,7 +604,6 @@
String.format(
"sendBatteryEventData() in %d/ms",
(System.currentTimeMillis() - startTime)));
- clearMemory();
return contentValues;
}
@@ -647,7 +637,6 @@
String.format(
"sendBatteryEventData() size=%d in %d/ms",
size, (System.currentTimeMillis() - startTime)));
- clearMemory();
return valuesList;
}
@@ -681,7 +670,6 @@
String.format(
"sendBatteryUsageSlotData() size=%d in %d/ms",
size, (System.currentTimeMillis() - startTime)));
- clearMemory();
return valuesList;
}
@@ -695,7 +683,6 @@
final Intent intent = BatteryUtils.getBatteryIntent(context);
if (intent == null) {
Log.e(TAG, "sendBatteryEntryData(): cannot fetch battery intent");
- clearMemory();
return null;
}
final int batteryLevel = BatteryStatus.getBatteryLevel(intent);
@@ -796,7 +783,6 @@
if (isFullChargeStart) {
recordDateTime(context, KEY_LAST_UPLOAD_FULL_CHARGE_TIME);
}
- clearMemory();
return valuesList;
}
@@ -992,20 +978,4 @@
writer.println(String.format("\t\t%s: %s", prefix, results.toString()));
}
}
-
- private static void clearMemory() {
- if (!EXPLICIT_CLEAR_MEMORY_ENABLED
- || SystemClock.uptimeMillis() > CLEAR_MEMORY_THRESHOLD_MS) {
- return;
- }
- final Handler mainHandler = new Handler(Looper.getMainLooper());
- mainHandler.postDelayed(
- () -> {
- System.gc();
- System.runFinalization();
- System.gc();
- Log.w(TAG, "invoke clearMemory()");
- },
- CLEAR_MEMORY_DELAYED_MS);
- }
}
diff --git a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
index cfaee00..9b4da46 100644
--- a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
+++ b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
@@ -243,7 +243,9 @@
protected boolean setDefaultKey(String key) {
setCurrentSystemNavigationMode(mOverlayManager, key);
setIllustrationVideo(mVideoPreference, key);
- setGestureNavigationTutorialDialog(key);
+ if (!android.provider.Flags.a11yStandaloneGestureEnabled()) {
+ setGestureNavigationTutorialDialog(key);
+ }
setIllustrationClickListener(mVideoPreference, key);
return true;
}
diff --git a/src/com/android/settings/network/NetworkProviderSettings.java b/src/com/android/settings/network/NetworkProviderSettings.java
index 69183ff..b268461 100644
--- a/src/com/android/settings/network/NetworkProviderSettings.java
+++ b/src/com/android/settings/network/NetworkProviderSettings.java
@@ -64,8 +64,8 @@
import com.android.settings.AirplaneModeEnabler;
import com.android.settings.R;
-import com.android.settings.RestrictedSettingsFragment;
import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.dashboard.RestrictedDashboardFragment;
import com.android.settings.datausage.DataUsagePreference;
import com.android.settings.datausage.DataUsageUtils;
import com.android.settings.location.WifiScanningFragment;
@@ -104,7 +104,7 @@
* UI for Mobile network and Wi-Fi network settings.
*/
@SearchIndexable
-public class NetworkProviderSettings extends RestrictedSettingsFragment
+public class NetworkProviderSettings extends RestrictedDashboardFragment
implements Indexable, WifiPickerTracker.WifiPickerTrackerCallback,
WifiDialog2.WifiDialog2Listener, DialogInterface.OnDismissListener,
AirplaneModeEnabler.OnAirplaneModeChangedListener, InternetUpdater.InternetChangeListener {
@@ -356,9 +356,17 @@
mIsGuest = userManager.isGuestUser();
}
- private void addPreferences() {
- addPreferencesFromResource(R.xml.network_provider_settings);
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.network_provider_settings;
+ }
+
+ private void addPreferences() {
mAirplaneModeMsgPreference = findPreference(PREF_KEY_AIRPLANE_MODE_MSG);
updateAirplaneModeMsgPreference(mAirplaneModeEnabler.isAirplaneModeOn() /* visible */);
mConnectedWifiEntryPreferenceCategory = findPreference(PREF_KEY_CONNECTED_ACCESS_POINTS);
diff --git a/src/com/android/settings/network/apn/ApnEditor.java b/src/com/android/settings/network/apn/ApnEditor.java
index dc9741d..533fd29 100644
--- a/src/com/android/settings/network/apn/ApnEditor.java
+++ b/src/com/android/settings/network/apn/ApnEditor.java
@@ -16,153 +16,33 @@
package com.android.settings.network.apn;
-import android.app.Dialog;
+import static com.android.settings.network.apn.ApnEditPageProviderKt.EDIT_URL;
+import static com.android.settings.network.apn.ApnEditPageProviderKt.INSERT_URL;
+
import android.app.settings.SettingsEnums;
-import android.content.ContentValues;
-import android.content.Context;
import android.content.Intent;
-import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.os.UserManager;
import android.provider.Telephony;
import android.telephony.CarrierConfigManager;
-import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
import android.util.Log;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnKeyListener;
-import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import androidx.appcompat.app.AlertDialog;
-import androidx.preference.EditTextPreference;
-import androidx.preference.ListPreference;
-import androidx.preference.MultiSelectListPreference;
-import androidx.preference.Preference;
-import androidx.preference.Preference.OnPreferenceChangeListener;
-import androidx.preference.TwoStatePreference;
import com.android.internal.util.ArrayUtils;
-import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
-import com.android.settings.network.ProxySubscriptionManager;
-import com.android.settingslib.utils.ThreadUtils;
+import com.android.settings.spa.SpaActivity;
import java.util.Arrays;
-import java.util.HashSet;
import java.util.List;
-import java.util.Objects;
-import java.util.Set;
/** Use to edit apn settings. */
-public class ApnEditor extends SettingsPreferenceFragment
- implements OnPreferenceChangeListener, OnKeyListener {
+public class ApnEditor extends SettingsPreferenceFragment {
private static final String TAG = ApnEditor.class.getSimpleName();
- private static final boolean VDBG = false; // STOPSHIP if true
-
- private static final String KEY_AUTH_TYPE = "auth_type";
- private static final String KEY_APN_TYPE = "apn_type";
- private static final String KEY_PROTOCOL = "apn_protocol";
- private static final String KEY_ROAMING_PROTOCOL = "apn_roaming_protocol";
- private static final String KEY_CARRIER_ENABLED = "carrier_enabled";
- private static final String KEY_BEARER_MULTI = "bearer_multi";
- private static final String KEY_MVNO_TYPE = "mvno_type";
- private static final String KEY_PASSWORD = "apn_password";
-
- @VisibleForTesting
- static final int MENU_DELETE = Menu.FIRST;
- private static final int MENU_SAVE = Menu.FIRST + 1;
- private static final int MENU_CANCEL = Menu.FIRST + 2;
-
- @VisibleForTesting
- static String sNotSet;
- @VisibleForTesting
- EditTextPreference mName;
- @VisibleForTesting
- EditTextPreference mApn;
- @VisibleForTesting
- EditTextPreference mProxy;
- @VisibleForTesting
- EditTextPreference mPort;
- @VisibleForTesting
- EditTextPreference mUser;
- @VisibleForTesting
- EditTextPreference mServer;
- @VisibleForTesting
- EditTextPreference mPassword;
- @VisibleForTesting
- EditTextPreference mMmsc;
- @VisibleForTesting
- EditTextPreference mMcc;
- @VisibleForTesting
- EditTextPreference mMnc;
- @VisibleForTesting
- EditTextPreference mMmsProxy;
- @VisibleForTesting
- EditTextPreference mMmsPort;
- @VisibleForTesting
- ListPreference mAuthType;
- @VisibleForTesting
- EditTextPreference mApnType;
- @VisibleForTesting
- ListPreference mProtocol;
- @VisibleForTesting
- ListPreference mRoamingProtocol;
- @VisibleForTesting
- TwoStatePreference mCarrierEnabled;
- @VisibleForTesting
- MultiSelectListPreference mBearerMulti;
- @VisibleForTesting
- ListPreference mMvnoType;
- @VisibleForTesting
- EditTextPreference mMvnoMatchData;
-
- @VisibleForTesting
- ApnData mApnData;
-
- private String mCurMnc;
- private String mCurMcc;
-
- private boolean mNewApn;
- private int mSubId;
- @VisibleForTesting
- ProxySubscriptionManager mProxySubscriptionMgr;
- private int mBearerInitialVal = 0;
- private String mMvnoTypeStr;
- private String mMvnoMatchDataStr;
- @VisibleForTesting
- String[] mReadOnlyApnTypes;
- @VisibleForTesting
- String[] mDefaultApnTypes;
- @VisibleForTesting
- String mDefaultApnProtocol;
- @VisibleForTesting
- String mDefaultApnRoamingProtocol;
- private String[] mReadOnlyApnFields;
- private boolean mReadOnlyApn;
- /**
- * The APN deletion feature within menu is aligned with the APN adding feature.
- * Having only one of them could lead to a UX which not that make sense from user's
- * perspective.
- *
- * mIsAddApnAllowed stores the configuration value reading from
- * CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL to support the presentation
- * control of the menu options. When false, delete option would be invisible to
- * the end user.
- */
- private boolean mIsAddApnAllowed;
- private Uri mCarrierUri;
- private boolean mIsCarrierIdApn;
/**
* APN types for data connections. These are usage categories for an APN
@@ -225,150 +105,41 @@
APN_TYPE_OEM_PRIVATE,
};
- /**
- * Standard projection for the interesting columns of a normal note.
- */
- private static final String[] sProjection = new String[] {
- Telephony.Carriers._ID, // 0
- Telephony.Carriers.NAME, // 1
- Telephony.Carriers.APN, // 2
- Telephony.Carriers.PROXY, // 3
- Telephony.Carriers.PORT, // 4
- Telephony.Carriers.USER, // 5
- Telephony.Carriers.SERVER, // 6
- Telephony.Carriers.PASSWORD, // 7
- Telephony.Carriers.MMSC, // 8
- Telephony.Carriers.MCC, // 9
- Telephony.Carriers.MNC, // 10
- Telephony.Carriers.NUMERIC, // 11
- Telephony.Carriers.MMSPROXY, // 12
- Telephony.Carriers.MMSPORT, // 13
- Telephony.Carriers.AUTH_TYPE, // 14
- Telephony.Carriers.TYPE, // 15
- Telephony.Carriers.PROTOCOL, // 16
- Telephony.Carriers.CARRIER_ENABLED, // 17
- Telephony.Carriers.BEARER, // 18
- Telephony.Carriers.BEARER_BITMASK, // 19
- Telephony.Carriers.ROAMING_PROTOCOL, // 20
- Telephony.Carriers.MVNO_TYPE, // 21
- Telephony.Carriers.MVNO_MATCH_DATA, // 22
- Telephony.Carriers.EDITED_STATUS, // 23
- Telephony.Carriers.USER_EDITABLE, // 24
- Telephony.Carriers.CARRIER_ID // 25
- };
-
- private static final int ID_INDEX = 0;
- @VisibleForTesting
- static final int NAME_INDEX = 1;
- @VisibleForTesting
- static final int APN_INDEX = 2;
- private static final int PROXY_INDEX = 3;
- private static final int PORT_INDEX = 4;
- private static final int USER_INDEX = 5;
- private static final int SERVER_INDEX = 6;
- private static final int PASSWORD_INDEX = 7;
- private static final int MMSC_INDEX = 8;
- @VisibleForTesting
- static final int MCC_INDEX = 9;
- @VisibleForTesting
- static final int MNC_INDEX = 10;
- private static final int MMSPROXY_INDEX = 12;
- private static final int MMSPORT_INDEX = 13;
- private static final int AUTH_TYPE_INDEX = 14;
- @VisibleForTesting
- static final int TYPE_INDEX = 15;
- @VisibleForTesting
- static final int PROTOCOL_INDEX = 16;
- @VisibleForTesting
- static final int CARRIER_ENABLED_INDEX = 17;
- private static final int BEARER_INDEX = 18;
- private static final int BEARER_BITMASK_INDEX = 19;
- @VisibleForTesting
- static final int ROAMING_PROTOCOL_INDEX = 20;
- private static final int MVNO_TYPE_INDEX = 21;
- private static final int MVNO_MATCH_DATA_INDEX = 22;
- private static final int EDITED_INDEX = 23;
- private static final int USER_EDITABLE_INDEX = 24;
- private static final int CARRIER_ID_INDEX = 25;
-
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ maybeRedirectToNewPage();
+ finish();
+ }
+
+ private void maybeRedirectToNewPage() {
if (isUserRestricted()) {
Log.e(TAG, "This setting isn't available due to user restriction.");
- finish();
return;
}
- setLifecycleForAllControllers();
-
final Intent intent = getIntent();
final String action = intent.getAction();
- if (TextUtils.isEmpty(action)) {
- finish();
- return;
- }
- mSubId = intent.getIntExtra(ApnSettings.SUB_ID,
- SubscriptionManager.INVALID_SUBSCRIPTION_ID);
- initApnEditorUi();
- getCarrierCustomizedConfig(getContext());
+ int subId =
+ intent.getIntExtra(ApnSettings.SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
- Uri uri = null;
- if (action.equals(Intent.ACTION_EDIT)) {
- uri = intent.getData();
+ Uri uri = intent.getData();
+ if (Intent.ACTION_EDIT.equals(action)) {
if (!uri.isPathPrefixMatch(Telephony.Carriers.CONTENT_URI)) {
Log.e(TAG, "Edit request not for carrier table. Uri: " + uri);
- finish();
- return;
+ } else {
+ String route = ApnEditPageProvider.INSTANCE.getRoute(EDIT_URL, uri, subId);
+ SpaActivity.startSpaActivity(requireContext(), route);
}
- } else if (action.equals(Intent.ACTION_INSERT)) {
- mCarrierUri = intent.getData();
- if (!mCarrierUri.isPathPrefixMatch(Telephony.Carriers.CONTENT_URI)) {
- Log.e(TAG, "Insert request not for carrier table. Uri: " + mCarrierUri);
- finish();
- return;
+ } else if (Intent.ACTION_INSERT.equals(action)) {
+ if (!uri.isPathPrefixMatch(Telephony.Carriers.CONTENT_URI)) {
+ Log.e(TAG, "Insert request not for carrier table. Uri: " + uri);
+ } else {
+ String route = ApnEditPageProvider.INSTANCE.getRoute(
+ INSERT_URL, Telephony.Carriers.CONTENT_URI, subId);
+ SpaActivity.startSpaActivity(getContext(), route);
}
- mNewApn = true;
- mMvnoTypeStr = intent.getStringExtra(ApnSettings.MVNO_TYPE);
- mMvnoMatchDataStr = intent.getStringExtra(ApnSettings.MVNO_MATCH_DATA);
- } else {
- finish();
- return;
- }
-
- // Creates an ApnData to store the apn data temporary, so that we don't need the cursor to
- // get the apn data. The uri is null if the action is ACTION_INSERT, that mean there is no
- // record in the database, so create a empty ApnData to represent a empty row of database.
- if (uri != null) {
- mApnData = getApnDataFromUri(uri);
- } else {
- mApnData = new ApnData(sProjection.length);
- }
- final int carrierId = mApnData.getInteger(CARRIER_ID_INDEX,
- TelephonyManager.UNKNOWN_CARRIER_ID);
- mIsCarrierIdApn = (carrierId > TelephonyManager.UNKNOWN_CARRIER_ID);
-
- final boolean isUserEdited = mApnData.getInteger(EDITED_INDEX,
- Telephony.Carriers.USER_EDITED) == Telephony.Carriers.USER_EDITED;
-
- Log.d(TAG, "onCreate: EDITED " + isUserEdited);
- // if it's not a USER_EDITED apn, check if it's read-only
- if (!isUserEdited && (mApnData.getInteger(USER_EDITABLE_INDEX, 1) == 0
- || apnTypesMatch(mReadOnlyApnTypes, mApnData.getString(TYPE_INDEX)))) {
- Log.d(TAG, "onCreate: apnTypesMatch; read-only APN");
- mReadOnlyApn = true;
- disableAllFields();
- } else if (!ArrayUtils.isEmpty(mReadOnlyApnFields)) {
- disableFields(mReadOnlyApnFields);
- }
- // Make sure that a user cannot break carrier id APN matching
- if (mIsCarrierIdApn) {
- disableFieldsForCarrieridApn();
- }
-
- for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); i++) {
- getPreferenceScreen().getPreference(i).setOnPreferenceChangeListener(this);
}
}
@@ -385,44 +156,6 @@
}
/**
- * Enable ProxySubscriptionMgr with Lifecycle support for all controllers
- * live within this fragment
- */
- private void setLifecycleForAllControllers() {
- if (mProxySubscriptionMgr == null) {
- mProxySubscriptionMgr = ProxySubscriptionManager.getInstance(getContext());
- }
- mProxySubscriptionMgr.setLifecycle(getLifecycle());
- }
-
- @Override
- public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
- super.onViewStateRestored(savedInstanceState);
- fillUI(savedInstanceState == null);
- setCarrierCustomizedConfigToUi();
- }
-
- @VisibleForTesting
- static String formatInteger(String value) {
- try {
- final int intValue = Integer.parseInt(value);
- return String.format(getCorrectDigitsFormat(value), intValue);
- } catch (NumberFormatException e) {
- return value;
- }
- }
-
- /**
- * Get the digits format so we preserve leading 0's.
- * MCCs are 3 digits and MNCs are either 2 or 3.
- */
- static String getCorrectDigitsFormat(String value) {
- if (value.length() == 2) return "%02d";
- else return "%03d";
- }
-
-
- /**
* Check if passed in array of APN types indicates all APN types
* @param apnTypes array of APN types. "*" indicates all types.
* @return true if all apn types are included in the array, false otherwise
@@ -447,1046 +180,12 @@
return true;
}
- /**
- * Check if APN types overlap.
- * @param apnTypesArray1 array of APNs. Empty array indicates no APN type; "*" indicates all
- * types
- * @param apnTypes2 comma separated string of APN types. Empty string represents all types.
- * @return if any apn type matches return true, otherwise return false
- */
- private boolean apnTypesMatch(String[] apnTypesArray1, String apnTypes2) {
- if (ArrayUtils.isEmpty(apnTypesArray1)) {
- return false;
- }
-
- final String[] apnTypesArray1LowerCase = new String[apnTypesArray1.length];
- for (int i = 0; i < apnTypesArray1.length; i++) {
- apnTypesArray1LowerCase[i] = apnTypesArray1[i].toLowerCase();
- }
-
- if (hasAllApns(apnTypesArray1LowerCase) || TextUtils.isEmpty(apnTypes2)) {
- return true;
- }
-
- final List apnTypesList1 = Arrays.asList(apnTypesArray1LowerCase);
- final String[] apnTypesArray2 = apnTypes2.split(",");
-
- for (String apn : apnTypesArray2) {
- if (apnTypesList1.contains(apn.trim().toLowerCase())) {
- Log.d(TAG, "apnTypesMatch: true because match found for " + apn.trim());
- return true;
- }
- }
-
- Log.d(TAG, "apnTypesMatch: false");
- return false;
- }
-
- /**
- * Function to get Preference obj corresponding to an apnField
- * @param apnField apn field name for which pref is needed
- * @return Preference obj corresponding to passed in apnField
- */
- private Preference getPreferenceFromFieldName(String apnField) {
- switch (apnField) {
- case Telephony.Carriers.NAME:
- return mName;
- case Telephony.Carriers.APN:
- return mApn;
- case Telephony.Carriers.PROXY:
- return mProxy;
- case Telephony.Carriers.PORT:
- return mPort;
- case Telephony.Carriers.USER:
- return mUser;
- case Telephony.Carriers.SERVER:
- return mServer;
- case Telephony.Carriers.PASSWORD:
- return mPassword;
- case Telephony.Carriers.MMSPROXY:
- return mMmsProxy;
- case Telephony.Carriers.MMSPORT:
- return mMmsPort;
- case Telephony.Carriers.MMSC:
- return mMmsc;
- case Telephony.Carriers.MCC:
- return mMcc;
- case Telephony.Carriers.MNC:
- return mMnc;
- case Telephony.Carriers.TYPE:
- return mApnType;
- case Telephony.Carriers.AUTH_TYPE:
- return mAuthType;
- case Telephony.Carriers.PROTOCOL:
- return mProtocol;
- case Telephony.Carriers.ROAMING_PROTOCOL:
- return mRoamingProtocol;
- case Telephony.Carriers.CARRIER_ENABLED:
- return mCarrierEnabled;
- case Telephony.Carriers.BEARER:
- case Telephony.Carriers.BEARER_BITMASK:
- return mBearerMulti;
- case Telephony.Carriers.MVNO_TYPE:
- return mMvnoType;
- case Telephony.Carriers.MVNO_MATCH_DATA:
- return mMvnoMatchData;
- }
- return null;
- }
-
- /**
- * Disables given fields so that user cannot modify them
- *
- * @param apnFields fields to be disabled
- */
- private void disableFields(String[] apnFields) {
- for (String apnField : apnFields) {
- final Preference preference = getPreferenceFromFieldName(apnField);
- if (preference != null) {
- preference.setEnabled(false);
- }
- }
- }
-
- /**
- * Disables all fields so that user cannot modify the APN
- */
- private void disableAllFields() {
- mName.setEnabled(false);
- mApn.setEnabled(false);
- mProxy.setEnabled(false);
- mPort.setEnabled(false);
- mUser.setEnabled(false);
- mServer.setEnabled(false);
- mPassword.setEnabled(false);
- mMmsProxy.setEnabled(false);
- mMmsPort.setEnabled(false);
- mMmsc.setEnabled(false);
- mMcc.setEnabled(false);
- mMnc.setEnabled(false);
- mApnType.setEnabled(false);
- mAuthType.setEnabled(false);
- mProtocol.setEnabled(false);
- mRoamingProtocol.setEnabled(false);
- mCarrierEnabled.setEnabled(false);
- mBearerMulti.setEnabled(false);
- mMvnoType.setEnabled(false);
- mMvnoMatchData.setEnabled(false);
- }
-
- /**
- * Disables fields for a carrier id APN to avoid breaking the match criteria
- */
- private void disableFieldsForCarrieridApn() {
- mMcc.setEnabled(false);
- mMnc.setEnabled(false);
- mMvnoType.setEnabled(false);
- mMvnoMatchData.setEnabled(false);
- }
-
@Override
public int getMetricsCategory() {
return SettingsEnums.APN_EDITOR;
}
@VisibleForTesting
- void fillUI(boolean firstTime) {
- if (firstTime) {
- // Fill in all the values from the db in both text editor and summary
- mName.setText(mApnData.getString(NAME_INDEX));
- mApn.setText(mApnData.getString(APN_INDEX));
- mProxy.setText(mApnData.getString(PROXY_INDEX));
- mPort.setText(mApnData.getString(PORT_INDEX));
- mUser.setText(mApnData.getString(USER_INDEX));
- mServer.setText(mApnData.getString(SERVER_INDEX));
- mPassword.setText(mApnData.getString(PASSWORD_INDEX));
- mMmsProxy.setText(mApnData.getString(MMSPROXY_INDEX));
- mMmsPort.setText(mApnData.getString(MMSPORT_INDEX));
- mMmsc.setText(mApnData.getString(MMSC_INDEX));
- mMcc.setText(mApnData.getString(MCC_INDEX));
- mMnc.setText(mApnData.getString(MNC_INDEX));
- mApnType.setText(mApnData.getString(TYPE_INDEX));
- if (mNewApn) {
- final SubscriptionInfo subInfo =
- mProxySubscriptionMgr.getAccessibleSubscriptionInfo(mSubId);
-
- // Country code
- final String mcc = (subInfo == null) ? null : subInfo.getMccString();
- // Network code
- final String mnc = (subInfo == null) ? null : subInfo.getMncString();
-
- if (!TextUtils.isEmpty(mcc)) {
- // Auto populate MNC and MCC for new entries, based on what SIM reports
- mMcc.setText(mcc);
- mMnc.setText(mnc);
- mCurMnc = mnc;
- mCurMcc = mcc;
- }
- }
- final int authVal = mApnData.getInteger(AUTH_TYPE_INDEX, -1);
- if (authVal != -1) {
- mAuthType.setValueIndex(authVal);
- } else {
- mAuthType.setValue(null);
- }
-
- mProtocol.setValue(mApnData.getString(PROTOCOL_INDEX));
- mRoamingProtocol.setValue(mApnData.getString(ROAMING_PROTOCOL_INDEX));
- mCarrierEnabled.setChecked(mApnData.getInteger(CARRIER_ENABLED_INDEX, 1) == 1);
- mBearerInitialVal = mApnData.getInteger(BEARER_INDEX, 0);
-
- final HashSet<String> bearers = new HashSet<String>();
- int bearerBitmask = mApnData.getInteger(BEARER_BITMASK_INDEX, 0);
- if (bearerBitmask == 0) {
- if (mBearerInitialVal == 0) {
- bearers.add("" + 0);
- }
- } else {
- int i = 1;
- while (bearerBitmask != 0) {
- if ((bearerBitmask & 1) == 1) {
- bearers.add("" + i);
- }
- bearerBitmask >>= 1;
- i++;
- }
- }
-
- if (mBearerInitialVal != 0 && !bearers.contains("" + mBearerInitialVal)) {
- // add mBearerInitialVal to bearers
- bearers.add("" + mBearerInitialVal);
- }
- mBearerMulti.setValues(bearers);
-
- mMvnoType.setValue(mApnData.getString(MVNO_TYPE_INDEX));
- mMvnoMatchData.setEnabled(false);
- mMvnoMatchData.setText(mApnData.getString(MVNO_MATCH_DATA_INDEX));
- if (mNewApn && mMvnoTypeStr != null && mMvnoMatchDataStr != null) {
- mMvnoType.setValue(mMvnoTypeStr);
- mMvnoMatchData.setText(mMvnoMatchDataStr);
- }
- }
-
- mName.setSummary(checkNull(mName.getText()));
- mApn.setSummary(checkNull(mApn.getText()));
- mProxy.setSummary(checkNull(mProxy.getText()));
- mPort.setSummary(checkNull(mPort.getText()));
- mUser.setSummary(checkNull(mUser.getText()));
- mServer.setSummary(checkNull(mServer.getText()));
- mPassword.setSummary(starify(mPassword.getText()));
- mMmsProxy.setSummary(checkNull(mMmsProxy.getText()));
- mMmsPort.setSummary(checkNull(mMmsPort.getText()));
- mMmsc.setSummary(checkNull(mMmsc.getText()));
- mMcc.setSummary(formatInteger(checkNull(mMcc.getText())));
- mMnc.setSummary(formatInteger(checkNull(mMnc.getText())));
- mApnType.setSummary(checkNull(mApnType.getText()));
-
- final String authVal = mAuthType.getValue();
- if (authVal != null) {
- final int authValIndex = Integer.parseInt(authVal);
- mAuthType.setValueIndex(authValIndex);
-
- final String[] values = getResources().getStringArray(R.array.apn_auth_entries);
- mAuthType.setSummary(values[authValIndex]);
- } else {
- mAuthType.setSummary(sNotSet);
- }
-
- mProtocol.setSummary(checkNull(protocolDescription(mProtocol.getValue(), mProtocol)));
- mRoamingProtocol.setSummary(
- checkNull(protocolDescription(mRoamingProtocol.getValue(), mRoamingProtocol)));
- mBearerMulti.setSummary(
- checkNull(bearerMultiDescription(mBearerMulti.getValues())));
- mMvnoType.setSummary(
- checkNull(mvnoDescription(mMvnoType.getValue())));
- mMvnoMatchData.setSummary(checkNullforMvnoValue(mMvnoMatchData.getText()));
- // allow user to edit carrier_enabled for some APN
- final boolean ceEditable = getResources().getBoolean(
- R.bool.config_allow_edit_carrier_enabled);
- if (ceEditable) {
- mCarrierEnabled.setEnabled(true);
- } else {
- mCarrierEnabled.setEnabled(false);
- }
- }
-
- /**
- * Returns the UI choice (e.g., "IPv4/IPv6") corresponding to the given
- * raw value of the protocol preference (e.g., "IPV4V6"). If unknown,
- * return null.
- */
- private String protocolDescription(String raw, ListPreference protocol) {
- String uRaw = checkNull(raw).toUpperCase();
- uRaw = uRaw.equals("IPV4") ? "IP" : uRaw;
- final int protocolIndex = protocol.findIndexOfValue(uRaw);
- if (protocolIndex == -1) {
- return null;
- } else {
- final String[] values = getResources().getStringArray(R.array.apn_protocol_entries);
- try {
- return values[protocolIndex];
- } catch (ArrayIndexOutOfBoundsException e) {
- return null;
- }
- }
- }
-
- private String bearerMultiDescription(Set<String> raw) {
- final String[] values = getResources().getStringArray(R.array.bearer_entries);
- final StringBuilder retVal = new StringBuilder();
- boolean first = true;
- for (String bearer : raw) {
- int bearerIndex = mBearerMulti.findIndexOfValue(bearer);
- try {
- if (first) {
- retVal.append(values[bearerIndex]);
- first = false;
- } else {
- retVal.append(", " + values[bearerIndex]);
- }
- } catch (ArrayIndexOutOfBoundsException e) {
- // ignore
- }
- }
- final String val = retVal.toString();
- if (!TextUtils.isEmpty(val)) {
- return val;
- }
- return null;
- }
-
- private String mvnoDescription(String newValue) {
- final int mvnoIndex = mMvnoType.findIndexOfValue(newValue);
- final String oldValue = mMvnoType.getValue();
-
- if (mvnoIndex == -1) {
- return null;
- } else {
- final String[] values = getResources().getStringArray(R.array.mvno_type_entries);
- final boolean mvnoMatchDataUneditable =
- mReadOnlyApn || (mReadOnlyApnFields != null
- && Arrays.asList(mReadOnlyApnFields)
- .contains(Telephony.Carriers.MVNO_MATCH_DATA));
- mMvnoMatchData.setEnabled(!mvnoMatchDataUneditable && mvnoIndex != 0);
- if (newValue != null && !newValue.equals(oldValue)) {
- if (values[mvnoIndex].equals("SPN")) {
- TelephonyManager telephonyManager = (TelephonyManager)
- getContext().getSystemService(TelephonyManager.class);
- final TelephonyManager telephonyManagerForSubId =
- telephonyManager.createForSubscriptionId(mSubId);
- if (telephonyManagerForSubId != null) {
- telephonyManager = telephonyManagerForSubId;
- }
- mMvnoMatchData.setText(telephonyManager.getSimOperatorName());
- } else if (values[mvnoIndex].equals("IMSI")) {
- final SubscriptionInfo subInfo =
- mProxySubscriptionMgr.getAccessibleSubscriptionInfo(mSubId);
- final String mcc = (subInfo == null) ? "" :
- Objects.toString(subInfo.getMccString(), "");
- final String mnc = (subInfo == null) ? "" :
- Objects.toString(subInfo.getMncString(), "");
- mMvnoMatchData.setText(mcc + mnc + "x");
- } else if (values[mvnoIndex].equals("GID")) {
- TelephonyManager telephonyManager = (TelephonyManager)
- getContext().getSystemService(TelephonyManager.class);
- final TelephonyManager telephonyManagerForSubId =
- telephonyManager.createForSubscriptionId(mSubId);
- if (telephonyManagerForSubId != null) {
- telephonyManager = telephonyManagerForSubId;
- }
- mMvnoMatchData.setText(telephonyManager.getGroupIdLevel1());
- } else {
- // mvno type 'none' case. At this time, mvnoIndex should be 0.
- mMvnoMatchData.setText("");
- }
- }
-
- try {
- return values[mvnoIndex];
- } catch (ArrayIndexOutOfBoundsException e) {
- return null;
- }
- }
- }
- /**
- * Callback when preference status changed.
- */
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- String key = preference.getKey();
- if (KEY_AUTH_TYPE.equals(key)) {
- try {
- final int index = Integer.parseInt((String) newValue);
- mAuthType.setValueIndex(index);
-
- final String[] values = getResources().getStringArray(R.array.apn_auth_entries);
- mAuthType.setSummary(values[index]);
- } catch (NumberFormatException e) {
- return false;
- }
- } else if (KEY_APN_TYPE.equals(key)) {
- String data = (TextUtils.isEmpty((String) newValue)
- && !ArrayUtils.isEmpty(mDefaultApnTypes))
- ? getEditableApnType(mDefaultApnTypes) : (String) newValue;
- if (!TextUtils.isEmpty(data)) {
- mApnType.setSummary(data);
- }
- } else if (KEY_PROTOCOL.equals(key)) {
- final String protocol = protocolDescription((String) newValue, mProtocol);
- if (protocol == null) {
- return false;
- }
- mProtocol.setSummary(protocol);
- mProtocol.setValue((String) newValue);
- } else if (KEY_ROAMING_PROTOCOL.equals(key)) {
- final String protocol = protocolDescription((String) newValue, mRoamingProtocol);
- if (protocol == null) {
- return false;
- }
- mRoamingProtocol.setSummary(protocol);
- mRoamingProtocol.setValue((String) newValue);
- } else if (KEY_BEARER_MULTI.equals(key)) {
- final String bearer = bearerMultiDescription((Set<String>) newValue);
- if (bearer == null) {
- return false;
- }
- mBearerMulti.setValues((Set<String>) newValue);
- mBearerMulti.setSummary(bearer);
- } else if (KEY_MVNO_TYPE.equals(key)) {
- final String mvno = mvnoDescription((String) newValue);
- if (mvno == null) {
- return false;
- }
- mMvnoType.setValue((String) newValue);
- mMvnoType.setSummary(mvno);
- mMvnoMatchData.setSummary(checkNullforMvnoValue(mMvnoMatchData.getText()));
- } else if (KEY_PASSWORD.equals(key)) {
- mPassword.setSummary(starify(newValue != null ? String.valueOf(newValue) : ""));
- } else if (KEY_CARRIER_ENABLED.equals(key)) {
- // do nothing
- } else {
- preference.setSummary(checkNull(newValue != null ? String.valueOf(newValue) : null));
- }
- return true;
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- super.onCreateOptionsMenu(menu, inflater);
- // If it's a new APN, then cancel will delete the new entry in onPause
- // If APN add is not allowed, delete might lead to issue regarding recovery
- if (!mNewApn && !mReadOnlyApn && mIsAddApnAllowed) {
- menu.add(0, MENU_DELETE, 0, R.string.menu_delete)
- .setIcon(R.drawable.ic_delete);
- }
- if (!mReadOnlyApn) {
- menu.add(0, MENU_SAVE, 0, R.string.menu_save)
- .setIcon(android.R.drawable.ic_menu_save);
- }
- menu.add(0, MENU_CANCEL, 0, R.string.menu_cancel)
- .setIcon(android.R.drawable.ic_menu_close_clear_cancel);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case MENU_DELETE:
- deleteApn();
- finish();
- return true;
- case MENU_SAVE:
- if (validateAndSaveApnData()) {
- finish();
- }
- return true;
- case MENU_CANCEL:
- finish();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- view.setOnKeyListener(this);
- view.setFocusableInTouchMode(true);
- view.requestFocus();
- }
-
- /**
- * Try to save the apn data when pressed the back button. An error message will be displayed if
- * the apn data is invalid.
- *
- * TODO(b/77339593): Try to keep the same behavior between back button and up navigate button.
- * We will save the valid apn data to the database when pressed the back button, but discard all
- * user changed when pressed the up navigate button.
- */
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- if (event.getAction() != KeyEvent.ACTION_DOWN) return false;
- switch (keyCode) {
- case KeyEvent.KEYCODE_BACK: {
- if (validateAndSaveApnData()) {
- finish();
- }
- return true;
- }
- }
- return false;
- }
-
- /**
- * Add key, value to {@code cv} and compare the value against the value at index in
- * {@link #mApnData}.
- *
- * <p>
- * The key, value will not add to {@code cv} if value is null.
- *
- * @return true if values are different. {@code assumeDiff} indicates if values can be assumed
- * different in which case no comparison is needed.
- */
- boolean setStringValueAndCheckIfDiff(
- ContentValues cv, String key, String value, boolean assumeDiff, int index) {
- final String valueFromLocalCache = mApnData.getString(index);
- if (VDBG) {
- Log.d(TAG, "setStringValueAndCheckIfDiff: assumeDiff: " + assumeDiff
- + " key: " + key
- + " value: '" + value
- + "' valueFromDb: '" + valueFromLocalCache + "'");
- }
- final boolean isDiff = assumeDiff
- || !((TextUtils.isEmpty(value) && TextUtils.isEmpty(valueFromLocalCache))
- || (value != null && value.equals(valueFromLocalCache)));
-
- if (isDiff && value != null) {
- cv.put(key, value);
- }
- return isDiff;
- }
-
- /**
- * Add key, value to {@code cv} and compare the value against the value at index in
- * {@link #mApnData}.
- *
- * @return true if values are different. {@code assumeDiff} indicates if values can be assumed
- * different in which case no comparison is needed.
- */
- boolean setIntValueAndCheckIfDiff(
- ContentValues cv, String key, int value, boolean assumeDiff, int index) {
- final Integer valueFromLocalCache = mApnData.getInteger(index);
- if (VDBG) {
- Log.d(TAG, "setIntValueAndCheckIfDiff: assumeDiff: " + assumeDiff
- + " key: " + key
- + " value: '" + value
- + "' valueFromDb: '" + valueFromLocalCache + "'");
- }
-
- final boolean isDiff = assumeDiff || value != valueFromLocalCache;
- if (isDiff) {
- cv.put(key, value);
- }
- return isDiff;
- }
-
- /**
- * Validates the apn data and save it to the database if it's valid.
- *
- * <p>
- * A dialog with error message will be displayed if the APN data is invalid.
- *
- * @return true if there is no error
- */
- @VisibleForTesting
- boolean validateAndSaveApnData() {
- // Nothing to do if it's a read only APN
- if (mReadOnlyApn) {
- return true;
- }
-
- final String name = checkNotSet(mName.getText());
- final String apn = checkNotSet(mApn.getText());
- final String mcc = checkNotSet(mMcc.getText());
- final String mnc = checkNotSet(mMnc.getText());
-
- final String errorMsg = validateApnData();
- if (errorMsg != null) {
- showError();
- return false;
- }
-
- final ContentValues values = new ContentValues();
- // call update() if it's a new APN. If not, check if any field differs from the db value;
- // if any diff is found update() should be called
- boolean callUpdate = mNewApn;
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.NAME,
- name,
- callUpdate,
- NAME_INDEX);
-
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.APN,
- apn,
- callUpdate,
- APN_INDEX);
-
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.PROXY,
- checkNotSet(mProxy.getText()),
- callUpdate,
- PROXY_INDEX);
-
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.PORT,
- checkNotSet(mPort.getText()),
- callUpdate,
- PORT_INDEX);
-
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.MMSPROXY,
- checkNotSet(mMmsProxy.getText()),
- callUpdate,
- MMSPROXY_INDEX);
-
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.MMSPORT,
- checkNotSet(mMmsPort.getText()),
- callUpdate,
- MMSPORT_INDEX);
-
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.USER,
- checkNotSet(mUser.getText()),
- callUpdate,
- USER_INDEX);
-
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.SERVER,
- checkNotSet(mServer.getText()),
- callUpdate,
- SERVER_INDEX);
-
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.PASSWORD,
- checkNotSet(mPassword.getText()),
- callUpdate,
- PASSWORD_INDEX);
-
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.MMSC,
- checkNotSet(mMmsc.getText()),
- callUpdate,
- MMSC_INDEX);
-
- final String authVal = mAuthType.getValue();
- if (authVal != null) {
- callUpdate = setIntValueAndCheckIfDiff(values,
- Telephony.Carriers.AUTH_TYPE,
- Integer.parseInt(authVal),
- callUpdate,
- AUTH_TYPE_INDEX);
- }
-
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.PROTOCOL,
- checkNotSet(mProtocol.getValue()),
- callUpdate,
- PROTOCOL_INDEX);
-
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.ROAMING_PROTOCOL,
- checkNotSet(mRoamingProtocol.getValue()),
- callUpdate,
- ROAMING_PROTOCOL_INDEX);
-
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.TYPE,
- checkNotSet(getUserEnteredApnType()),
- callUpdate,
- TYPE_INDEX);
-
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.MCC,
- mcc,
- callUpdate,
- MCC_INDEX);
-
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.MNC,
- mnc,
- callUpdate,
- MNC_INDEX);
-
- values.put(Telephony.Carriers.NUMERIC, mcc + mnc);
-
- if (mCurMnc != null && mCurMcc != null) {
- if (mCurMnc.equals(mnc) && mCurMcc.equals(mcc)) {
- values.put(Telephony.Carriers.CURRENT, 1);
- }
- }
-
- final Set<String> bearerSet = mBearerMulti.getValues();
- int bearerBitmask = 0;
- for (String bearer : bearerSet) {
- if (Integer.parseInt(bearer) == 0) {
- bearerBitmask = 0;
- break;
- } else {
- bearerBitmask |= getBitmaskForTech(Integer.parseInt(bearer));
- }
- }
- callUpdate = setIntValueAndCheckIfDiff(values,
- Telephony.Carriers.BEARER_BITMASK,
- bearerBitmask,
- callUpdate,
- BEARER_BITMASK_INDEX);
-
- int bearerVal;
- if (bearerBitmask == 0 || mBearerInitialVal == 0) {
- bearerVal = 0;
- } else if (bitmaskHasTech(bearerBitmask, mBearerInitialVal)) {
- bearerVal = mBearerInitialVal;
- } else {
- // bearer field was being used but bitmask has changed now and does not include the
- // initial bearer value -- setting bearer to 0 but maybe better behavior is to choose a
- // random tech from the new bitmask??
- bearerVal = 0;
- }
- callUpdate = setIntValueAndCheckIfDiff(values,
- Telephony.Carriers.BEARER,
- bearerVal,
- callUpdate,
- BEARER_INDEX);
-
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.MVNO_TYPE,
- checkNotSet(mMvnoType.getValue()),
- callUpdate,
- MVNO_TYPE_INDEX);
-
- callUpdate = setStringValueAndCheckIfDiff(values,
- Telephony.Carriers.MVNO_MATCH_DATA,
- checkNotSet(mMvnoMatchData.getText()),
- callUpdate,
- MVNO_MATCH_DATA_INDEX);
-
- callUpdate = setIntValueAndCheckIfDiff(values,
- Telephony.Carriers.CARRIER_ENABLED,
- mCarrierEnabled.isChecked() ? 1 : 0,
- callUpdate,
- CARRIER_ENABLED_INDEX);
-
- values.put(Telephony.Carriers.EDITED_STATUS, Telephony.Carriers.USER_EDITED);
-
- if (callUpdate) {
- final Uri uri = mApnData.getUri() == null ? mCarrierUri : mApnData.getUri();
- updateApnDataToDatabase(uri, values);
- } else {
- if (VDBG) Log.d(TAG, "validateAndSaveApnData: not calling update()");
- }
-
- return true;
- }
-
- private void updateApnDataToDatabase(Uri uri, ContentValues values) {
- ThreadUtils.postOnBackgroundThread(() -> {
- if (uri.equals(mCarrierUri)) {
- // Add a new apn to the database
- final Uri newUri = getContentResolver().insert(mCarrierUri, values);
- if (newUri == null) {
- Log.e(TAG, "Can't add a new apn to database " + mCarrierUri);
- }
- } else {
- // Update the existing apn
- getContentResolver().update(
- uri, values, null /* where */, null /* selection Args */);
- }
- });
- }
-
- /**
- * Validates whether the apn data is valid.
- *
- * @return An error message if the apn data is invalid, otherwise return null.
- */
- @VisibleForTesting
- String validateApnData() {
- String errorMsg = null;
-
- final String name = checkNotSet(mName.getText());
- final String apn = checkNotSet(mApn.getText());
- final String mcc = checkNotSet(mMcc.getText());
- final String mnc = checkNotSet(mMnc.getText());
- boolean doNotCheckMccMnc = mIsCarrierIdApn && TextUtils.isEmpty(mcc)
- && TextUtils.isEmpty(mnc);
- if (TextUtils.isEmpty(name)) {
- errorMsg = getResources().getString(R.string.error_name_empty);
- } else if (TextUtils.isEmpty(apn)) {
- errorMsg = getResources().getString(R.string.error_apn_empty);
- } else if (doNotCheckMccMnc) {
- Log.d(TAG, "validateApnData: carrier id APN does not have mcc/mnc defined");
- // no op, skip mcc mnc null check
- } else if (mcc == null || mcc.length() != 3) {
- errorMsg = getResources().getString(R.string.error_mcc_not3);
- } else if ((mnc == null || (mnc.length() & 0xFFFE) != 2)) {
- errorMsg = getResources().getString(R.string.error_mnc_not23);
- }
-
- if (errorMsg == null) {
- // if carrier does not allow editing certain apn types, make sure type does not include
- // those
- if (!ArrayUtils.isEmpty(mReadOnlyApnTypes)
- && apnTypesMatch(mReadOnlyApnTypes, getUserEnteredApnType())) {
- final StringBuilder stringBuilder = new StringBuilder();
- for (String type : mReadOnlyApnTypes) {
- stringBuilder.append(type).append(", ");
- Log.d(TAG, "validateApnData: appending type: " + type);
- }
- // remove last ", "
- if (stringBuilder.length() >= 2) {
- stringBuilder.delete(stringBuilder.length() - 2, stringBuilder.length());
- }
- errorMsg = String.format(getResources().getString(R.string.error_adding_apn_type),
- stringBuilder);
- }
- }
-
- return errorMsg;
- }
-
- @VisibleForTesting
- void showError() {
- ErrorDialog.showError(this);
- }
-
- private void deleteApn() {
- if (mApnData.getUri() != null) {
- getContentResolver().delete(mApnData.getUri(), null, null);
- mApnData = new ApnData(sProjection.length);
- }
- }
-
- private String starify(String value) {
- if (value == null || value.length() == 0) {
- return sNotSet;
- } else {
- final char[] password = new char[value.length()];
- for (int i = 0; i < password.length; i++) {
- password[i] = '*';
- }
- return new String(password);
- }
- }
-
- /**
- * Returns {@link #sNotSet} if the given string {@code value} is null or empty. The string
- * {@link #sNotSet} typically used as the default display when an entry in the preference is
- * null or empty.
- */
- private String checkNull(String value) {
- return TextUtils.isEmpty(value) ? sNotSet : value;
- }
-
- /**
- * To make traslation be diversity, use another string id for MVNO value.
- */
- private String checkNullforMvnoValue(String value) {
- String notSetForMvnoValue = getResources().getString(R.string.apn_not_set_for_mvno);
- return TextUtils.isEmpty(value) ? notSetForMvnoValue : value;
- }
-
- /**
- * Returns null if the given string {@code value} equals to {@link #sNotSet}. This method
- * should be used when convert a string value from preference to database.
- */
- private String checkNotSet(String value) {
- return sNotSet.equals(value) ? null : value;
- }
-
- @VisibleForTesting
- String getUserEnteredApnType() {
- // if user has not specified a type, map it to "ALL APN TYPES THAT ARE NOT READ-ONLY"
- // but if user enter empty type, map it just for default
- String userEnteredApnType = mApnType.getText();
- if (userEnteredApnType != null) userEnteredApnType = userEnteredApnType.trim();
- if ((TextUtils.isEmpty(userEnteredApnType)
- || APN_TYPE_ALL.equals(userEnteredApnType))) {
- userEnteredApnType = getEditableApnType(APN_TYPES);
- }
- Log.d(TAG, "getUserEnteredApnType: changed apn type to editable apn types: "
- + userEnteredApnType);
- return userEnteredApnType;
- }
-
- private String getEditableApnType(String[] apnTypeList) {
- final StringBuilder editableApnTypes = new StringBuilder();
- final List<String> readOnlyApnTypes = Arrays.asList(mReadOnlyApnTypes);
- boolean first = true;
- for (String apnType : apnTypeList) {
- // add APN type if it is not read-only and is not wild-cardable
- if (!readOnlyApnTypes.contains(apnType)
- && !apnType.equals(APN_TYPE_IA)
- && !apnType.equals(APN_TYPE_EMERGENCY)
- && !apnType.equals(APN_TYPE_MCX)
- && !apnType.equals(APN_TYPE_IMS)) {
- if (first) {
- first = false;
- } else {
- editableApnTypes.append(",");
- }
- editableApnTypes.append(apnType);
- }
- }
- return editableApnTypes.toString();
- }
-
- private void initApnEditorUi() {
- addPreferencesFromResource(R.xml.apn_editor);
-
- sNotSet = getResources().getString(R.string.apn_not_set);
- mName = (EditTextPreference) findPreference("apn_name");
- mApn = (EditTextPreference) findPreference("apn_apn");
- mProxy = (EditTextPreference) findPreference("apn_http_proxy");
- mPort = (EditTextPreference) findPreference("apn_http_port");
- mUser = (EditTextPreference) findPreference("apn_user");
- mServer = (EditTextPreference) findPreference("apn_server");
- mPassword = (EditTextPreference) findPreference(KEY_PASSWORD);
- mMmsProxy = (EditTextPreference) findPreference("apn_mms_proxy");
- mMmsPort = (EditTextPreference) findPreference("apn_mms_port");
- mMmsc = (EditTextPreference) findPreference("apn_mmsc");
- mMcc = (EditTextPreference) findPreference("apn_mcc");
- mMnc = (EditTextPreference) findPreference("apn_mnc");
- mApnType = (EditTextPreference) findPreference("apn_type");
- mAuthType = (ListPreference) findPreference(KEY_AUTH_TYPE);
- mProtocol = (ListPreference) findPreference(KEY_PROTOCOL);
- mRoamingProtocol = (ListPreference) findPreference(KEY_ROAMING_PROTOCOL);
- mCarrierEnabled = (TwoStatePreference) findPreference(KEY_CARRIER_ENABLED);
- mBearerMulti = (MultiSelectListPreference) findPreference(KEY_BEARER_MULTI);
- mMvnoType = (ListPreference) findPreference(KEY_MVNO_TYPE);
- mMvnoMatchData = (EditTextPreference) findPreference("mvno_match_data");
- }
-
- @VisibleForTesting
- protected void getCarrierCustomizedConfig(Context context) {
- mReadOnlyApn = false;
- mReadOnlyApnTypes = null;
- mReadOnlyApnFields = null;
- mIsAddApnAllowed = true;
-
- final CarrierConfigManager configManager = (CarrierConfigManager)
- context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- if (configManager != null) {
- final PersistableBundle b = configManager.getConfigForSubId(mSubId);
- if (b != null) {
- mReadOnlyApnTypes = getReadOnlyApnTypes(b);
- if (!ArrayUtils.isEmpty(mReadOnlyApnTypes)) {
- Log.d(TAG,
- "onCreate: read only APN type: " + Arrays.toString(mReadOnlyApnTypes));
- }
- mReadOnlyApnFields = b.getStringArray(
- CarrierConfigManager.KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY);
-
- mDefaultApnTypes = b.getStringArray(
- CarrierConfigManager.KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY);
-
- if (!ArrayUtils.isEmpty(mDefaultApnTypes)) {
- Log.d(TAG, "onCreate: default apn types: " + Arrays.toString(mDefaultApnTypes));
- }
-
- mDefaultApnProtocol = b.getString(
- CarrierConfigManager.Apn.KEY_SETTINGS_DEFAULT_PROTOCOL_STRING);
- if (!TextUtils.isEmpty(mDefaultApnProtocol)) {
- Log.d(TAG, "onCreate: default apn protocol: " + mDefaultApnProtocol);
- }
-
- mDefaultApnRoamingProtocol = b.getString(
- CarrierConfigManager.Apn.KEY_SETTINGS_DEFAULT_ROAMING_PROTOCOL_STRING);
- if (!TextUtils.isEmpty(mDefaultApnRoamingProtocol)) {
- Log.d(TAG, "onCreate: default apn roaming protocol: "
- + mDefaultApnRoamingProtocol);
- }
-
- mIsAddApnAllowed = b.getBoolean(CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL);
- if (!mIsAddApnAllowed) {
- Log.d(TAG, "onCreate: not allow to add new APN");
- }
- }
- }
- }
-
- private void setCarrierCustomizedConfigToUi() {
- if (TextUtils.isEmpty(mApnType.getText()) && !ArrayUtils.isEmpty(mDefaultApnTypes)) {
- String value = getEditableApnType(mDefaultApnTypes);
- mApnType.setText(value);
- mApnType.setSummary(value);
- }
-
- String protocol = protocolDescription(mDefaultApnProtocol, mProtocol);
- if (TextUtils.isEmpty(mProtocol.getValue()) && !TextUtils.isEmpty(protocol)) {
- mProtocol.setValue(mDefaultApnProtocol);
- mProtocol.setSummary(protocol);
- }
-
- String roamingProtocol = protocolDescription(mDefaultApnRoamingProtocol, mRoamingProtocol);
- if (TextUtils.isEmpty(mRoamingProtocol.getValue()) && !TextUtils.isEmpty(roamingProtocol)) {
- mRoamingProtocol.setValue(mDefaultApnRoamingProtocol);
- mRoamingProtocol.setSummary(roamingProtocol);
- }
- }
-
- /**
- * Dialog of error message.
- */
- public static class ErrorDialog extends InstrumentedDialogFragment {
- /**
- * Show error dialog.
- */
- public static void showError(ApnEditor editor) {
- final ErrorDialog dialog = new ErrorDialog();
- dialog.setTargetFragment(editor, 0);
- dialog.show(editor.getFragmentManager(), "error");
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- final String msg = ((ApnEditor) getTargetFragment()).validateApnData();
-
- return new AlertDialog.Builder(getContext())
- .setTitle(R.string.error_title)
- .setPositiveButton(android.R.string.ok, null)
- .setMessage(msg)
- .create();
- }
-
- @Override
- public int getMetricsCategory() {
- return SettingsEnums.DIALOG_APN_EDITOR_ERROR;
- }
- }
-
- @VisibleForTesting
- ApnData getApnDataFromUri(Uri uri) {
- ApnData apnData = null;
- try (Cursor cursor = getContentResolver().query(
- uri,
- sProjection,
- null /* selection */,
- null /* selectionArgs */,
- null /* sortOrder */)) {
- if (cursor != null && cursor.moveToFirst()) {
- apnData = new ApnData(uri, cursor);
- }
- }
-
- if (apnData == null) {
- Log.d(TAG, "Can't get apnData from Uri " + uri);
- }
-
- return apnData;
- }
-
- @VisibleForTesting
boolean isUserRestricted() {
UserManager userManager = getContext().getSystemService(UserManager.class);
if (userManager == null) {
@@ -1502,80 +201,4 @@
}
return false;
}
-
- @VisibleForTesting
- static class ApnData {
- /**
- * The uri correspond to a database row of the apn data. This should be null if the apn
- * is not in the database.
- */
- Uri mUri;
-
- /** Each element correspond to a column of the database row. */
- Object[] mData;
-
- ApnData(int numberOfField) {
- mData = new Object[numberOfField];
- }
-
- ApnData(Uri uri, Cursor cursor) {
- mUri = uri;
- mData = new Object[cursor.getColumnCount()];
- for (int i = 0; i < mData.length; i++) {
- switch (cursor.getType(i)) {
- case Cursor.FIELD_TYPE_FLOAT:
- mData[i] = cursor.getFloat(i);
- break;
- case Cursor.FIELD_TYPE_INTEGER:
- mData[i] = cursor.getInt(i);
- break;
- case Cursor.FIELD_TYPE_STRING:
- mData[i] = cursor.getString(i);
- break;
- case Cursor.FIELD_TYPE_BLOB:
- mData[i] = cursor.getBlob(i);
- break;
- default:
- mData[i] = null;
- }
- }
- }
-
- Uri getUri() {
- return mUri;
- }
-
- void setUri(Uri uri) {
- mUri = uri;
- }
-
- Integer getInteger(int index) {
- return (Integer) mData[index];
- }
-
- Integer getInteger(int index, Integer defaultValue) {
- final Integer val = getInteger(index);
- return val == null ? defaultValue : val;
- }
-
- String getString(int index) {
- return (String) mData[index];
- }
- }
-
- private static int getBitmaskForTech(int radioTech) {
- if (radioTech >= 1) {
- return (1 << (radioTech - 1));
- }
- return 0;
- }
-
- private static boolean bitmaskHasTech(int bearerBitmask, int radioTech) {
- if (bearerBitmask == 0) {
- return true;
- } else if (radioTech >= 1) {
- return ((bearerBitmask & (1 << (radioTech - 1))) != 0);
- }
- return false;
- }
}
diff --git a/src/com/android/settings/network/telephony/NetworkSelectSettings.java b/src/com/android/settings/network/telephony/NetworkSelectSettings.java
index a16f4b5..4ae51ab 100644
--- a/src/com/android/settings/network/telephony/NetworkSelectSettings.java
+++ b/src/com/android/settings/network/telephony/NetworkSelectSettings.java
@@ -219,7 +219,7 @@
setProgressBarVisible(true);
mNetworkScanJob = mNetworkScanRepository.launchNetworkScan(getViewLifecycleOwner(),
(networkScanResult) -> {
- if (isPreferenceScreenEnabled()) {
+ if (isPreferenceScreenEnabled() && !isFinishingOrDestroyed()) {
scanResultHandler(networkScanResult);
}
diff --git a/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java b/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java
index fe90a2a..2dc5b2d 100644
--- a/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java
+++ b/src/com/android/settings/users/AddUserWhenLockedPreferenceController.java
@@ -46,8 +46,6 @@
restrictedSwitchPreference.setVisible(true);
if (mUserCaps.mDisallowAddUserSetByAdmin) {
restrictedSwitchPreference.setDisabledByAdmin(mUserCaps.mEnforcedAdmin);
- } else if (mUserCaps.mDisallowAddUser) {
- restrictedSwitchPreference.setVisible(false);
}
} else {
restrictedSwitchPreference.setDisabledByAdmin(
@@ -62,7 +60,11 @@
if (!mUserCaps.isAdmin()) {
return DISABLED_FOR_USER;
} else if (android.multiuser.Flags.newMultiuserSettingsUx()) {
- return AVAILABLE;
+ if (mUserCaps.mDisallowAddUser && !mUserCaps.mDisallowAddUserSetByAdmin) {
+ return DISABLED_FOR_USER;
+ } else {
+ return AVAILABLE;
+ }
} else if (mUserCaps.disallowAddUser() || mUserCaps.disallowAddUserSetByAdmin()) {
return DISABLED_FOR_USER;
} else {
diff --git a/tests/robotests/src/com/android/settings/accessibility/ColorAndMotionScreenTest.kt b/tests/robotests/src/com/android/settings/accessibility/ColorAndMotionScreenTest.kt
index 6d7164e..67fbc1a 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ColorAndMotionScreenTest.kt
+++ b/tests/robotests/src/com/android/settings/accessibility/ColorAndMotionScreenTest.kt
@@ -27,7 +27,9 @@
@RunWith(AndroidJUnit4::class)
class ColorAndMotionScreenTest : CatalystScreenTestCase() {
override val preferenceScreenCreator: PreferenceScreenCreator = ColorAndMotionScreen()
- override val flagName: String = Flags.FLAG_CATALYST_ACCESSIBILITY_COLOR_AND_MOTION
+
+ override val flagName: String
+ get() = Flags.FLAG_CATALYST_ACCESSIBILITY_COLOR_AND_MOTION
override fun migration() {}
@@ -35,4 +37,4 @@
fun key() {
assertThat(preferenceScreenCreator.key).isEqualTo(ColorAndMotionScreen.KEY)
}
-}
\ No newline at end of file
+}
diff --git a/tests/robotests/src/com/android/settings/applications/contacts/ContactsStoragePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/contacts/ContactsStoragePreferenceControllerTest.java
index a934cba..f55cbb4 100644
--- a/tests/robotests/src/com/android/settings/applications/contacts/ContactsStoragePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/contacts/ContactsStoragePreferenceControllerTest.java
@@ -16,8 +16,9 @@
package com.android.settings.applications.contacts;
-import static android.provider.ContactsContract.Settings.KEY_DEFAULT_ACCOUNT;
-import static android.provider.ContactsContract.Settings.QUERY_DEFAULT_ACCOUNT_METHOD;
+import static android.provider.ContactsContract.RawContacts.DefaultAccount.KEY_DEFAULT_ACCOUNT_STATE;
+import static android.provider.ContactsContract.RawContacts.DefaultAccount.QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD;
+import static android.provider.ContactsContract.Settings;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
@@ -28,25 +29,26 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
-
import android.accounts.Account;
import android.accounts.AccountManager;
+import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
import android.platform.test.annotations.EnableFlags;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.ContactsContract;
+import android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState;
import com.android.settings.R;
import com.android.settings.flags.Flags;
import com.android.settings.testutils.shadow.ShadowAuthenticationHelper;
import org.junit.Before;
-import android.platform.test.annotations.RequiresFlagsDisabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -62,11 +64,6 @@
private static final String CONTACTS_DEFAULT_ACCOUNT_PREFERENCE_KEY =
"contacts_default_account";
- private static final Account TEST_ACCOUNT1 = new Account("test@gmail.com", "type1");
-
- private static final Account TEST_ACCOUNT2 = new Account("test@samsung.com", "type2");
-
- private static final Account TEST_ACCOUNT3 = new Account("LABEL3", "type3");
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@@ -84,6 +81,9 @@
private ContentResolver mContentResolver;
@Mock
+ private ContentProviderClient mContentProviderClient;
+
+ @Mock
private Resources mResources;
@Mock
@@ -94,9 +94,15 @@
@Before
public void setUp() throws Exception {
when(mContext.getContentResolver()).thenReturn(mContentResolver);
+ when(mContentResolver.acquireContentProviderClient(
+ eq(ContactsContract.AUTHORITY_URI))).thenReturn(mContentProviderClient);
when(mContext.getSystemService(eq(Context.ACCOUNT_SERVICE))).thenReturn(mAccountManager);
when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[]{});
-
+ Bundle bundle = new Bundle();
+ bundle.putInt(KEY_DEFAULT_ACCOUNT_STATE,
+ DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_NOT_SET);
+ when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
+ any())).thenReturn(bundle);
mPreferenceController = new ContactsStoragePreferenceController(mContext,
CONTACTS_DEFAULT_ACCOUNT_PREFERENCE_KEY);
}
@@ -104,13 +110,39 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_CONTACTS_DEFAULT_ACCOUNT_IN_SETTINGS)
public void getAvailabilityStatus_flagIsOn_shouldReturnAvailable() {
-
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_CONTACTS_DEFAULT_ACCOUNT_IN_SETTINGS)
public void getAvailabilityStatus_flagIsOff_shouldReturnConditionallyUnavailable() {
+ assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(
+ CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_CONTACTS_DEFAULT_ACCOUNT_IN_SETTINGS)
+ public void getAvailabilityStatus_illegalStateExceptionThrown_shouldReturnConditionallyUnavailable()
+ throws Exception {
+ when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
+ any())).thenThrow(new IllegalStateException());
+
+ mPreferenceController = new ContactsStoragePreferenceController(mContext,
+ CONTACTS_DEFAULT_ACCOUNT_PREFERENCE_KEY);
+
+ assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(
+ CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_CONTACTS_DEFAULT_ACCOUNT_IN_SETTINGS)
+ public void getAvailabilityStatus_runtimeExceptionThrown_shouldReturnConditionallyUnavailable()
+ throws Exception {
+ when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
+ any())).thenThrow(new RuntimeException());
+
+ mPreferenceController = new ContactsStoragePreferenceController(mContext,
+ CONTACTS_DEFAULT_ACCOUNT_PREFERENCE_KEY);
assertThat(mPreferenceController.getAvailabilityStatus()).isEqualTo(
CONDITIONALLY_UNAVAILABLE);
@@ -118,43 +150,77 @@
@Test
public void getSummary_noAccountIsSetAsDefault_shouldReturnNoAccountSetSummary() {
- Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_DEFAULT_ACCOUNT, null);
- when(mContentResolver.call(eq(ContactsContract.AUTHORITY_URI),
- eq(QUERY_DEFAULT_ACCOUNT_METHOD), any(), any())).thenReturn(bundle);
when(mContext.getResources()).thenReturn(mResources);
- when(mResources.getString(eq(R.string.contacts_storage_no_account_set))).thenReturn(
+ when(mResources.getString(eq(R.string.contacts_storage_no_account_set_summary))).thenReturn(
"No default set");
+ // Fetch the default account from CP2.
+ mPreferenceController = new ContactsStoragePreferenceController(mContext,
+ CONTACTS_DEFAULT_ACCOUNT_PREFERENCE_KEY);
+
assertThat(mPreferenceController.getSummary()).isEqualTo("No default set");
}
@Test
- public void getSummary_googleAccountIsSetAsDefault_shouldReturnGoogleAccountTypeAndAccountName() {
+ public void getSummary_localAccountIsSetAsDefault_shouldReturnLocalAccountSetSummary()
+ throws Exception {
Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_DEFAULT_ACCOUNT, TEST_ACCOUNT1);
- when(mContentResolver.call(eq(ContactsContract.AUTHORITY_URI),
- eq(QUERY_DEFAULT_ACCOUNT_METHOD), any(), any())).thenReturn(bundle);
+ bundle.putInt(KEY_DEFAULT_ACCOUNT_STATE,
+ DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_LOCAL);
+ when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
+ any())).thenReturn(bundle);
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getString(eq(R.string.contacts_storage_local_account_summary))).thenReturn(
+ "Device only");
+ mPreferenceController = new ContactsStoragePreferenceController(mContext,
+ CONTACTS_DEFAULT_ACCOUNT_PREFERENCE_KEY);
+
+ assertThat(mPreferenceController.getSummary()).isEqualTo("Device only");
+ }
+
+ @Test
+ public void getSummary_googleAccountIsSetAsDefault_shouldReturnGoogleAccountTypeAndAccountName()
+ throws Exception {
+ Bundle bundle = new Bundle();
+ bundle.putInt(KEY_DEFAULT_ACCOUNT_STATE,
+ DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD);
+ bundle.putString(Settings.ACCOUNT_TYPE, "type1");
+ bundle.putString(Settings.ACCOUNT_NAME, "test@gmail.com");
+ when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
+ any())).thenReturn(bundle);
+ mPreferenceController = new ContactsStoragePreferenceController(mContext,
+ CONTACTS_DEFAULT_ACCOUNT_PREFERENCE_KEY);
assertThat(mPreferenceController.getSummary()).isEqualTo("LABEL1 | test@gmail.com");
}
@Test
- public void getSummary_samsungAccountIsSetAsDefault_shouldReturnSamsungAccountTypeAndAccountName() {
+ public void getSummary_samsungAccountIsSetAsDefault_shouldReturnSamsungAccountTypeAndAccountName()
+ throws Exception {
Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_DEFAULT_ACCOUNT, TEST_ACCOUNT2);
- when(mContentResolver.call(eq(ContactsContract.AUTHORITY_URI),
- eq(QUERY_DEFAULT_ACCOUNT_METHOD), any(), any())).thenReturn(bundle);
+ bundle.putInt(KEY_DEFAULT_ACCOUNT_STATE,
+ DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD);
+ bundle.putString(Settings.ACCOUNT_TYPE, "type2");
+ bundle.putString(Settings.ACCOUNT_NAME, "test@samsung.com");
+ when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
+ any())).thenReturn(bundle);
+ mPreferenceController = new ContactsStoragePreferenceController(mContext,
+ CONTACTS_DEFAULT_ACCOUNT_PREFERENCE_KEY);
assertThat(mPreferenceController.getSummary()).isEqualTo("LABEL2 | test@samsung.com");
}
@Test
- public void getSummary_accountLabelSameAsAccountName_onlyReturnAccountName() {
+ public void getSummary_accountLabelSameAsAccountName_onlyReturnAccountName() throws Exception {
Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_DEFAULT_ACCOUNT, TEST_ACCOUNT3);
- when(mContentResolver.call(eq(ContactsContract.AUTHORITY_URI),
- eq(QUERY_DEFAULT_ACCOUNT_METHOD), any(), any())).thenReturn(bundle);
+ bundle.putInt(KEY_DEFAULT_ACCOUNT_STATE,
+ DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD);
+ bundle.putString(Settings.ACCOUNT_TYPE, "type3");
+ bundle.putString(Settings.ACCOUNT_NAME, "LABEL3");
+ when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
+ any())).thenReturn(bundle);
+ mPreferenceController = new ContactsStoragePreferenceController(mContext,
+ CONTACTS_DEFAULT_ACCOUNT_PREFERENCE_KEY);
// Since package name and account name is the same, we only return account name.
assertThat(mPreferenceController.getSummary()).isEqualTo("LABEL3");
diff --git a/tests/robotests/src/com/android/settings/applications/contacts/ContactsStorageSettingsTest.java b/tests/robotests/src/com/android/settings/applications/contacts/ContactsStorageSettingsTest.java
index 785ef4a..a8c86e1 100644
--- a/tests/robotests/src/com/android/settings/applications/contacts/ContactsStorageSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/contacts/ContactsStorageSettingsTest.java
@@ -15,16 +15,17 @@
*/
package com.android.settings.applications.contacts;
-import static android.provider.ContactsContract.Settings.KEY_DEFAULT_ACCOUNT;
-import static android.provider.ContactsContract.Settings.QUERY_DEFAULT_ACCOUNT_METHOD;
-import static android.provider.ContactsContract.Settings.SET_DEFAULT_ACCOUNT_METHOD;
+import static android.provider.ContactsContract.RawContacts.DefaultAccount.KEY_DEFAULT_ACCOUNT_STATE;
+import static android.provider.ContactsContract.RawContacts.DefaultAccount.KEY_ELIGIBLE_DEFAULT_ACCOUNTS;
+import static android.provider.ContactsContract.RawContacts.DefaultAccount.QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD;
+import static android.provider.ContactsContract.RawContacts.DefaultAccount.QUERY_ELIGIBLE_DEFAULT_ACCOUNTS_METHOD;
+import static android.provider.ContactsContract.RawContacts.DefaultAccount.SET_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD;
import static android.provider.Settings.ACTION_ADD_ACCOUNT;
import static android.provider.Settings.EXTRA_ACCOUNT_TYPES;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -33,14 +34,17 @@
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.settings.SettingsEnums;
+import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.provider.ContactsContract;
+import android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState;
import android.provider.SearchIndexableResource;
+import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
@@ -63,6 +67,7 @@
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import java.util.ArrayList;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
@@ -76,6 +81,8 @@
private static final Account TEST_ACCOUNT2 = new Account("test@samsung.com", "type2");
+ private static final Account TEST_ACCOUNT3 = new Account("test@outlook.com", "type3");
+
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@Spy
@@ -83,8 +90,7 @@
@Mock
private ContentResolver mContentResolver;
@Mock
- private AccountManager mAccountManager;
-
+ private ContentProviderClient mContentProviderClient;
private PreferenceManager mPreferenceManager;
private TestContactsStorageSettings mContactsStorageSettings;
private PreferenceScreen mScreen;
@@ -92,8 +98,8 @@
@Before
public void setUp() throws Exception {
mContactsStorageSettings = spy(new TestContactsStorageSettings(mContext, mContentResolver));
- when(mContext.getSystemService(eq(Context.ACCOUNT_SERVICE))).thenReturn(mAccountManager);
- when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[]{});
+ when(mContentResolver.acquireContentProviderClient(
+ eq(ContactsContract.AUTHORITY_URI))).thenReturn(mContentProviderClient);
mPreferenceManager = new PreferenceManager(mContext);
when(mContactsStorageSettings.getPreferenceManager()).thenReturn(mPreferenceManager);
mScreen = spy(new PreferenceScreen(mContext, /* attrs= */ null));
@@ -115,12 +121,17 @@
}
@Test
- public void verifyDeviceOnlyPreference_onClick_setDefaultAccountToNull() {
- when(mAccountManager.getAccounts()).thenReturn(new Account[]{});
- Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_DEFAULT_ACCOUNT, null);
- when(mContentResolver.call(eq(ContactsContract.AUTHORITY_URI),
- eq(QUERY_DEFAULT_ACCOUNT_METHOD), any(), any())).thenReturn(bundle);
+ public void verifyDeviceOnlyPreference_onClick_setDefaultAccountToNull() throws Exception {
+ Bundle currentDefaultAccount = new Bundle();
+ currentDefaultAccount.putInt(KEY_DEFAULT_ACCOUNT_STATE,
+ DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_NOT_SET);
+ when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
+ any())).thenReturn(currentDefaultAccount);
+ Bundle eligibleAccountBundle = new Bundle();
+ eligibleAccountBundle.putParcelableArrayList(KEY_ELIGIBLE_DEFAULT_ACCOUNTS,
+ new ArrayList<>());
+ when(mContentProviderClient.call(eq(QUERY_ELIGIBLE_DEFAULT_ACCOUNTS_METHOD), any(),
+ any())).thenReturn(eligibleAccountBundle);
PreferenceScreen settingScreen = mPreferenceManager.inflateFromResource(mContext,
R.xml.contacts_storage_settings, mScreen);
@@ -139,18 +150,27 @@
assertThat(deviceOnlyPreference.isChecked()).isTrue();
ArgumentCaptor<Bundle> captor = ArgumentCaptor.forClass(Bundle.class);
- verify(mContentResolver).call(eq(ContactsContract.AUTHORITY_URI),
- eq(SET_DEFAULT_ACCOUNT_METHOD), any(), captor.capture());
+ verify(mContentProviderClient).call(eq(SET_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
+ captor.capture());
Bundle accountBundle = captor.getValue();
assertThat(accountBundle.getString(ContactsContract.Settings.ACCOUNT_NAME)).isNull();
assertThat(accountBundle.getString(ContactsContract.Settings.ACCOUNT_TYPE)).isNull();
}
@Test
- public void verifyAddAccountPreference_onClick_startAddAccountActivity() {
- when(mAccountManager.getAccounts()).thenReturn(new Account[]{});
- when(mContentResolver.call(eq(ContactsContract.AUTHORITY_URI),
- eq(QUERY_DEFAULT_ACCOUNT_METHOD), any(), any())).thenReturn(Bundle.EMPTY);
+ public void verifyAddAccountPreference_eligibleAccountsAvailable_startAddAccountActivityOnClick()
+ throws Exception {
+ Bundle currentDefaultAccount = new Bundle();
+ currentDefaultAccount.putInt(KEY_DEFAULT_ACCOUNT_STATE,
+ DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_NOT_SET);
+ when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
+ any())).thenReturn(currentDefaultAccount);
+ Bundle eligibleAccountBundle = new Bundle();
+ eligibleAccountBundle.putParcelableArrayList(KEY_ELIGIBLE_DEFAULT_ACCOUNTS,
+ new ArrayList<>());
+ when(mContentProviderClient.call(eq(QUERY_ELIGIBLE_DEFAULT_ACCOUNTS_METHOD), any(),
+ any())).thenReturn(eligibleAccountBundle);
+ mContactsStorageSettings.setEligibleAccountTypes(new String[]{"com.google"});
mContactsStorageSettings.refreshUI();
@@ -167,16 +187,45 @@
assertThat(addAccountIntent.getComponent().getClassName()).isEqualTo(
AddAccountSettings.class.getCanonicalName());
String[] eligibleAccounts = (String[]) addAccountIntent.getExtra(EXTRA_ACCOUNT_TYPES);
- assertThat(eligibleAccounts).isEmpty();
+ assertThat(List.of(eligibleAccounts)).containsExactly("com.google");
}
@Test
- public void verifyEligibleAccountPreference_onClick_setSelectedDefaultAccount() {
- when(mAccountManager.getAccounts()).thenReturn(new Account[]{TEST_ACCOUNT1, TEST_ACCOUNT2});
- Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_DEFAULT_ACCOUNT, TEST_ACCOUNT2);
- when(mContentResolver.call(eq(ContactsContract.AUTHORITY_URI),
- eq(QUERY_DEFAULT_ACCOUNT_METHOD), any(), any())).thenReturn(bundle);
+ public void verifyAddAccountPreference_noEligibleAccountsAvailable_dontShowPreference()
+ throws Exception {
+ Bundle currentDefaultAccount = new Bundle();
+ currentDefaultAccount.putInt(KEY_DEFAULT_ACCOUNT_STATE,
+ DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_NOT_SET);
+ when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
+ any())).thenReturn(currentDefaultAccount);
+ Bundle eligibleAccountBundle = new Bundle();
+ eligibleAccountBundle.putParcelableArrayList(KEY_ELIGIBLE_DEFAULT_ACCOUNTS,
+ new ArrayList<>());
+ when(mContentProviderClient.call(eq(QUERY_ELIGIBLE_DEFAULT_ACCOUNTS_METHOD), any(),
+ any())).thenReturn(eligibleAccountBundle);
+ mContactsStorageSettings.setEligibleAccountTypes(new String[]{});
+
+ mContactsStorageSettings.refreshUI();
+
+ Preference addAccountPreference = mScreen.findPreference(PREF_KEY_ADD_ACCOUNT);
+ assertThat(addAccountPreference).isNull();
+ }
+
+ @Test
+ public void verifyEligibleAccountPreference_onClick_setSelectedDefaultAccount()
+ throws Exception {
+ Bundle currentDefaultAccount = new Bundle();
+ currentDefaultAccount.putInt(KEY_DEFAULT_ACCOUNT_STATE,
+ DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_LOCAL);
+ when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
+ any())).thenReturn(currentDefaultAccount);
+ Bundle eligibleAccountBundle = new Bundle();
+ ArrayList<Account> eligibleAccounts = new ArrayList<>(
+ List.of(TEST_ACCOUNT1, TEST_ACCOUNT2));
+ eligibleAccountBundle.putParcelableArrayList(KEY_ELIGIBLE_DEFAULT_ACCOUNTS,
+ eligibleAccounts);
+ when(mContentProviderClient.call(eq(QUERY_ELIGIBLE_DEFAULT_ACCOUNTS_METHOD), any(),
+ any())).thenReturn(eligibleAccountBundle);
mContactsStorageSettings.refreshUI();
@@ -197,8 +246,8 @@
assertThat(account2Preference.isChecked()).isTrue();
ArgumentCaptor<Bundle> captor = ArgumentCaptor.forClass(Bundle.class);
- verify(mContentResolver).call(eq(ContactsContract.AUTHORITY_URI),
- eq(SET_DEFAULT_ACCOUNT_METHOD), any(), captor.capture());
+ verify(mContentProviderClient).call(eq(SET_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
+ captor.capture());
Bundle setAccountBundle = captor.getValue();
assertThat(setAccountBundle.getString(ContactsContract.Settings.ACCOUNT_NAME)).isEqualTo(
"test@samsung.com");
@@ -207,6 +256,49 @@
}
@Test
+ public void verifyAccountPreference_defaultAccountIsNotEligibleCloudAccount_createNewDefaultAccountPreference()
+ throws Exception {
+ Bundle currentDefaultAccount = new Bundle();
+ currentDefaultAccount.putInt(KEY_DEFAULT_ACCOUNT_STATE,
+ DefaultAccountAndState.DEFAULT_ACCOUNT_STATE_CLOUD);
+ currentDefaultAccount.putString(ContactsContract.Settings.ACCOUNT_NAME, TEST_ACCOUNT3.name);
+ currentDefaultAccount.putString(ContactsContract.Settings.ACCOUNT_TYPE, TEST_ACCOUNT3.type);
+ when(mContentProviderClient.call(eq(QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD), any(),
+ any())).thenReturn(currentDefaultAccount);
+ Bundle eligibleAccountBundle = new Bundle();
+ ArrayList<Account> eligibleAccounts = new ArrayList<>(
+ List.of(TEST_ACCOUNT1, TEST_ACCOUNT2));
+ eligibleAccountBundle.putParcelableArrayList(KEY_ELIGIBLE_DEFAULT_ACCOUNTS,
+ eligibleAccounts);
+ when(mContentProviderClient.call(eq(QUERY_ELIGIBLE_DEFAULT_ACCOUNTS_METHOD), any(),
+ any())).thenReturn(eligibleAccountBundle);
+
+ mContactsStorageSettings.refreshUI();
+
+ SelectorWithWidgetPreference account1Preference = mScreen.findPreference(
+ String.valueOf(TEST_ACCOUNT1.hashCode()));
+ assertThat(account1Preference.getTitle()).isEqualTo("LABEL1");
+ assertThat(account1Preference.getSummary()).isEqualTo("test@gmail.com");
+ assertThat(account1Preference.getIcon()).isNotNull();
+
+ SelectorWithWidgetPreference account2Preference = mScreen.findPreference(
+ String.valueOf(TEST_ACCOUNT2.hashCode()));
+ assertThat(account2Preference.getTitle()).isEqualTo("LABEL2");
+ assertThat(account2Preference.getSummary()).isEqualTo("test@samsung.com");
+ assertThat(account2Preference.getIcon()).isNotNull();
+
+ SelectorWithWidgetPreference account3Preference = mScreen.findPreference(
+ String.valueOf(TEST_ACCOUNT3.hashCode()));
+ assertThat(account3Preference.getTitle()).isEqualTo("LABEL3");
+ assertThat(account3Preference.getSummary()).isEqualTo("test@outlook.com");
+ assertThat(account3Preference.getIcon()).isNotNull();
+
+ assertThat(account1Preference.isChecked()).isFalse();
+ assertThat(account2Preference.isChecked()).isFalse();
+ assertThat(account3Preference.isChecked()).isTrue();
+ }
+
+ @Test
public void searchIndexProvider_shouldIndexResource() {
final List<SearchIndexableResource> indexRes =
ContactsStorageSettings.SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex(
@@ -220,6 +312,7 @@
private static class TestContactsStorageSettings extends ContactsStorageSettings {
private final Context mContext;
private final ContentResolver mContentResolver;
+ private String[] mEligibleAccountTypes;
TestContactsStorageSettings(Context context, ContentResolver contentResolver) {
mContext = context;
@@ -236,5 +329,16 @@
// Override it so we can access this method in test
return mContentResolver;
}
+
+ @Override
+ String[] getEligibleAccountTypes() {
+ return mEligibleAccountTypes == null ? Resources.getSystem().getStringArray(
+ com.android.internal.R.array.config_rawContactsEligibleDefaultAccountTypes)
+ : mEligibleAccountTypes;
+ }
+
+ public void setEligibleAccountTypes(String[] eligibleAccountTypes) {
+ mEligibleAccountTypes = eligibleAccountTypes;
+ }
}
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/BluetoothDashboardScreenTest.kt b/tests/robotests/src/com/android/settings/connecteddevice/BluetoothDashboardScreenTest.kt
index 39c0294..16db841 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/BluetoothDashboardScreenTest.kt
+++ b/tests/robotests/src/com/android/settings/connecteddevice/BluetoothDashboardScreenTest.kt
@@ -15,7 +15,12 @@
*/
package com.android.settings.connecteddevice
+import android.content.Intent
+import android.provider.Settings.Global
+import androidx.preference.PreferenceFragmentCompat
+import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.Settings.BluetoothDashboardActivity
import com.android.settings.flags.Flags
import com.android.settingslib.preference.CatalystScreenTestCase
import com.google.common.truth.Truth.assertThat
@@ -34,6 +39,18 @@
assertThat(preferenceScreenCreator.key).isEqualTo(BluetoothDashboardScreen.KEY)
}
- override fun migration() {
+ override fun launchFragment(
+ fragmentClass: Class<PreferenceFragmentCompat>,
+ action: (PreferenceFragmentCompat) -> Unit,
+ ) {
+ Global.putInt(appContext.contentResolver, Global.DEVICE_PROVISIONED, 1)
+ val intent = Intent(appContext, BluetoothDashboardActivity::class.java)
+ ActivityScenario.launch<BluetoothDashboardActivity>(intent).use {
+ it.onActivity { activity ->
+ val fragment = activity.supportFragmentManager.fragments[0]
+ assertThat(fragment.javaClass).isEqualTo(fragmentClass)
+ action(fragment as PreferenceFragmentCompat)
+ }
+ }
}
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
index 1bc00a1..f3848b3 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
@@ -17,10 +17,10 @@
package com.android.settings.fuelgauge;
import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS;
-import static com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
@@ -49,13 +49,13 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
+import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
import com.android.settings.fuelgauge.batteryusage.BatteryDiffEntry;
import com.android.settings.fuelgauge.batteryusage.BatteryEntry;
import com.android.settings.fuelgauge.batteryusage.ConvertUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
import com.android.settings.widget.EntityHeaderController;
-import com.android.settingslib.PrimarySwitchPreference;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
@@ -87,12 +87,12 @@
})
public class AdvancedPowerUsageDetailTest {
- @Rule
- public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
private static final String APP_LABEL = "app label";
private static final String SUMMARY = "summary";
- private static final String[] PACKAGE_NAME = {"com.android.app"};
+ private static final String PACKAGE_NAME = "com.android.app";
+ private static final String INITIATING_PACKAGE_NAME = "com.android.vending";
private static final String USAGE_PERCENT = "16%";
private static final int ICON_ID = 123;
private static final int UID = 1;
@@ -100,39 +100,43 @@
private static final long FOREGROUND_SERVICE_TIME_MS = 123;
private static final long BACKGROUND_TIME_MS = 100;
private static final long SCREEN_ON_TIME_MS = 321;
- private static final String KEY_ALLOW_BACKGROUND_USAGE = "allow_background_usage";
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private FragmentActivity mActivity;
@Mock private EntityHeaderController mEntityHeaderController;
- @Mock private LayoutPreference mHeaderPreference;
@Mock private ApplicationsState mState;
@Mock private ApplicationsState.AppEntry mAppEntry;
@Mock private BatteryEntry mBatteryEntry;
@Mock private PackageManager mPackageManager;
@Mock private InstallSourceInfo mInstallSourceInfo;
+ @Mock private LayoutPreference mLayoutPreference;
@Mock private AppOpsManager mAppOpsManager;
@Mock private LoaderManager mLoaderManager;
- @Mock private BatteryOptimizeUtils mBatteryOptimizeUtils;
+ private int mTestMode;
private Context mContext;
- private PrimarySwitchPreference mAllowBackgroundUsagePreference;
private AdvancedPowerUsageDetail mFragment;
private SettingsActivity mTestActivity;
private FakeFeatureFactory mFeatureFactory;
private MetricsFeatureProvider mMetricsFeatureProvider;
private BatteryDiffEntry mBatteryDiffEntry;
private Bundle mBundle;
+ private BatteryOptimizeUtils mBatteryOptimizeUtils;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
mContext = spy(ApplicationProvider.getApplicationContext());
- when(mContext.getPackageName()).thenReturn("foo");
+ when(mContext.getPackageName()).thenReturn(PACKAGE_NAME);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(mInstallSourceInfo);
mFeatureFactory = FakeFeatureFactory.setupForTest();
mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
+ prepareTestBatteryOptimizationUtils();
mFragment = spy(new AdvancedPowerUsageDetail());
+ mFragment.mBatteryOptimizeUtils = mBatteryOptimizeUtils;
+ doReturn(mLayoutPreference).when(mFragment).findPreference(any());
mBundle = spy(new Bundle());
doReturn(mContext).when(mFragment).getContext();
doReturn(mActivity).when(mFragment).getActivity();
@@ -195,7 +199,6 @@
when(mBatteryDiffEntry.getAppLabel()).thenReturn(APP_LABEL);
when(mBatteryDiffEntry.getAppIconId()).thenReturn(ICON_ID);
- mFragment.mHeaderPreference = mHeaderPreference;
mFragment.mState = mState;
mFragment.mBatteryOptimizeUtils = mBatteryOptimizeUtils;
mFragment.mLogStringBuilder = new StringBuilder();
@@ -219,10 +222,6 @@
.startActivityAsUser(captor.capture(), nullable(UserHandle.class));
doAnswer(callable).when(mActivity).startActivity(captor.capture());
doAnswer(callable).when(mContext).startActivity(captor.capture());
-
- mAllowBackgroundUsagePreference = new PrimarySwitchPreference(mContext);
- mAllowBackgroundUsagePreference.setKey(KEY_ALLOW_BACKGROUND_USAGE);
- mFragment.mAllowBackgroundUsagePreference = mAllowBackgroundUsagePreference;
}
@After
@@ -320,17 +319,15 @@
.isEqualTo(SCREEN_ON_TIME_MS);
assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_POWER_USAGE_PERCENT))
.isEqualTo(USAGE_PERCENT);
- assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_SLOT_TIME))
- .isEqualTo(null);
+ assertThat(mBundle.getString(AdvancedPowerUsageDetail.EXTRA_SLOT_TIME)).isNull();
}
-
@Test
public void startBatteryDetailPage_noBatteryUsage_hasBasicData() {
final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
AdvancedPowerUsageDetail.startBatteryDetailPage(
- mActivity, mFragment, PACKAGE_NAME[0], UserHandle.OWNER);
+ mActivity, mFragment, PACKAGE_NAME, UserHandle.OWNER);
verify(mActivity).startActivity(captor.capture());
@@ -338,7 +335,7 @@
captor.getValue()
.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS)
.getString(AdvancedPowerUsageDetail.EXTRA_PACKAGE_NAME))
- .isEqualTo(PACKAGE_NAME[0]);
+ .isEqualTo(PACKAGE_NAME);
assertThat(
captor.getValue()
@@ -351,62 +348,21 @@
public void startBatteryDetailPage_batteryEntryNotExisted_extractUidFromPackageName()
throws PackageManager.NameNotFoundException {
mBundle.clear();
- doReturn(UID).when(mPackageManager).getPackageUid(PACKAGE_NAME[0], 0 /* no flag */);
+ doReturn(UID).when(mPackageManager).getPackageUid(PACKAGE_NAME, 0 /* no flag */);
AdvancedPowerUsageDetail.startBatteryDetailPage(
- mActivity, mFragment, PACKAGE_NAME[0], UserHandle.OWNER);
+ mActivity, mFragment, PACKAGE_NAME, UserHandle.OWNER);
assertThat(mBundle.getInt(AdvancedPowerUsageDetail.EXTRA_UID)).isEqualTo(UID);
}
@Test
- public void initFooter_isValidPackageName_hasCorrectString() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
+ public void onPause_optimizationModeIsChanged_logPreference() throws Exception {
+ mFragment.mOptimizationMode = BatteryOptimizeUtils.MODE_RESTRICTED;
+ when(mBatteryOptimizeUtils.getPackageName()).thenReturn(PACKAGE_NAME);
+ when(mInstallSourceInfo.getInitiatingPackageName()).thenReturn(INITIATING_PACKAGE_NAME);
- mFragment.initFooter();
-
- assertThat(mAllowBackgroundUsagePreference.getSummary().toString())
- .isEqualTo("This app requires optimized battery usage.");
- }
-
- @Test
- public void initFooter_isSystemOrDefaultApp_hasCorrectString() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
-
- mFragment.initFooter();
-
- assertThat(mAllowBackgroundUsagePreference.getSummary().toString())
- .isEqualTo("This app requires unrestricted battery usage.");
- }
-
- @Test
- public void initFooter_hasCorrectString() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(false);
-
- mFragment.initFooter();
-
- assertThat(mAllowBackgroundUsagePreference.getSummary().toString())
- .isEqualTo("Enable for real-time updates, disable to save battery");
- }
-
- @Test
- public void onPause_optimizationModeChanged_logPreference()
- throws PackageManager.NameNotFoundException, InterruptedException {
- final String packageName = "testPackageName";
- final int restrictedMode = BatteryOptimizeUtils.MODE_RESTRICTED;
- final int optimizedMode = BatteryOptimizeUtils.MODE_OPTIMIZED;
- mFragment.mOptimizationMode = restrictedMode;
- when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(restrictedMode);
- when(mBatteryOptimizeUtils.getPackageName()).thenReturn(packageName);
- when(mContext.getPackageManager()).thenReturn(mPackageManager);
- when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(mInstallSourceInfo);
- when(mInstallSourceInfo.getInitiatingPackageName()).thenReturn("com.android.vending");
-
- mFragment.onPreferenceChange(mAllowBackgroundUsagePreference, true);
- verify(mBatteryOptimizeUtils).setAppUsageState(optimizedMode, Action.APPLY);
- when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(optimizedMode);
+ mBatteryOptimizeUtils.setAppUsageState(BatteryOptimizeUtils.MODE_OPTIMIZED, Action.APPLY);
mFragment.onPause();
TimeUnit.SECONDS.sleep(1);
@@ -415,27 +371,18 @@
SettingsEnums.LEAVE_APP_BATTERY_USAGE,
SettingsEnums.ACTION_APP_BATTERY_USAGE_ALLOW_BACKGROUND,
SettingsEnums.FUELGAUGE_POWER_USAGE_DETAIL,
- packageName,
+ PACKAGE_NAME,
/* consumed battery */ 0);
}
@Test
- public void onPause_optimizationModeIsNotChanged_notInvokeLogging()
- throws PackageManager.NameNotFoundException, InterruptedException {
- final int restrictedMode = BatteryOptimizeUtils.MODE_RESTRICTED;
- final int optimizedMode = BatteryOptimizeUtils.MODE_OPTIMIZED;
- mFragment.mOptimizationMode = restrictedMode;
- when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(restrictedMode);
- when(mContext.getPackageManager()).thenReturn(mPackageManager);
- when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(mInstallSourceInfo);
- when(mInstallSourceInfo.getInitiatingPackageName()).thenReturn("com.android.vending");
+ public void onPause_optimizationModeIsNotChanged_notInvokeLogging() throws Exception {
+ mFragment.mOptimizationMode = BatteryOptimizeUtils.MODE_RESTRICTED;
+ when(mBatteryOptimizeUtils.getPackageName()).thenReturn(PACKAGE_NAME);
+ when(mInstallSourceInfo.getInitiatingPackageName()).thenReturn(INITIATING_PACKAGE_NAME);
- mFragment.onPreferenceChange(mAllowBackgroundUsagePreference, true);
- verify(mBatteryOptimizeUtils).setAppUsageState(optimizedMode, Action.APPLY);
- when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(optimizedMode);
- mFragment.onPreferenceChange(mAllowBackgroundUsagePreference, false);
- verify(mBatteryOptimizeUtils).setAppUsageState(restrictedMode, Action.APPLY);
- when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(restrictedMode);
+ mBatteryOptimizeUtils.setAppUsageState(BatteryOptimizeUtils.MODE_OPTIMIZED, Action.APPLY);
+ mBatteryOptimizeUtils.setAppUsageState(BatteryOptimizeUtils.MODE_RESTRICTED, Action.APPLY);
mFragment.onPause();
TimeUnit.SECONDS.sleep(1);
@@ -446,4 +393,16 @@
public void shouldSkipForInitialSUW_returnTrue() {
assertThat(mFragment.shouldSkipForInitialSUW()).isTrue();
}
+
+ private void prepareTestBatteryOptimizationUtils() {
+ mBatteryOptimizeUtils = spy(new BatteryOptimizeUtils(mContext, UID, PACKAGE_NAME));
+ Answer<Void> setTestMode =
+ invocation -> {
+ mTestMode = invocation.getArgument(0);
+ return null;
+ };
+ doAnswer(setTestMode).when(mBatteryOptimizeUtils).setAppUsageState(anyInt(), any());
+ Answer<Integer> getTestMode = invocation -> mTestMode;
+ doAnswer(getTestMode).when(mBatteryOptimizeUtils).getAppOptimizationMode();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AllowBackgroundPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AllowBackgroundPreferenceControllerTest.java
deleted file mode 100644
index 261a315..0000000
--- a/tests/robotests/src/com/android/settings/fuelgauge/AllowBackgroundPreferenceControllerTest.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.fuelgauge;
-
-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.when;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-
-import com.android.settingslib.widget.MainSwitchPreference;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class AllowBackgroundPreferenceControllerTest {
- private static final int UID = 12345;
- private static final String PACKAGE_NAME = "com.android.app";
-
- private AllowBackgroundPreferenceController mController;
- private MainSwitchPreference mMainSwitchPreference;
- private BatteryOptimizeUtils mBatteryOptimizeUtils;
-
- @Mock private PackageManager mMockPackageManager;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- Context context = spy(RuntimeEnvironment.application);
- BatteryUtils.getInstance(context).reset();
- doReturn(UID)
- .when(mMockPackageManager)
- .getPackageUid(PACKAGE_NAME, PackageManager.GET_META_DATA);
-
- mController = new AllowBackgroundPreferenceController(context, UID, PACKAGE_NAME);
- mMainSwitchPreference = new MainSwitchPreference(RuntimeEnvironment.application);
- mBatteryOptimizeUtils = spy(new BatteryOptimizeUtils(context, UID, PACKAGE_NAME));
- mController.mBatteryOptimizeUtils = mBatteryOptimizeUtils;
- }
-
- @Test
- public void testUpdateState_isValidPackage_prefEnabled() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(false);
-
- mController.updateState(mMainSwitchPreference);
-
- assertThat(mBatteryOptimizeUtils.isOptimizeModeMutable()).isTrue();
- assertThat(mMainSwitchPreference.isEnabled()).isTrue();
- }
-
- @Test
- public void testUpdateState_invalidPackage_prefDisabled() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
- when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(false);
-
- mController.updateState(mMainSwitchPreference);
-
- assertThat(mBatteryOptimizeUtils.isOptimizeModeMutable()).isFalse();
- assertThat(mMainSwitchPreference.isEnabled()).isFalse();
- }
-
- @Test
- public void testUpdateState_isSystemOrDefaultAppAndRestrictedStates_prefChecked() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
- when(mBatteryOptimizeUtils.getAppOptimizationMode())
- .thenReturn(BatteryOptimizeUtils.MODE_RESTRICTED);
-
- mController.updateState(mMainSwitchPreference);
-
- assertThat(mMainSwitchPreference.isEnabled()).isFalse();
- assertThat(mMainSwitchPreference.isChecked()).isFalse();
- }
-
- @Test
- public void testUpdateState_isSystemOrDefaultApp_prefUnchecked() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
- when(mBatteryOptimizeUtils.getAppOptimizationMode())
- .thenReturn(BatteryOptimizeUtils.MODE_OPTIMIZED);
-
- mController.updateState(mMainSwitchPreference);
-
- assertThat(mMainSwitchPreference.isEnabled()).isFalse();
- assertThat(mMainSwitchPreference.isChecked()).isTrue();
- }
-
- @Test
- public void testUpdateState_isRestrictedStates_prefChecked() {
- when(mBatteryOptimizeUtils.isOptimizeModeMutable()).thenReturn(true);
- when(mBatteryOptimizeUtils.getAppOptimizationMode())
- .thenReturn(BatteryOptimizeUtils.MODE_RESTRICTED);
-
- mController.updateState(mMainSwitchPreference);
-
- assertThat(mMainSwitchPreference.isEnabled()).isTrue();
- assertThat(mMainSwitchPreference.isChecked()).isFalse();
- }
-
- @Test
- public void testUpdateState_prefUnchecked() {
- when(mBatteryOptimizeUtils.isOptimizeModeMutable()).thenReturn(true);
- when(mBatteryOptimizeUtils.getAppOptimizationMode())
- .thenReturn(BatteryOptimizeUtils.MODE_OPTIMIZED);
-
- mController.updateState(mMainSwitchPreference);
-
- assertThat(mMainSwitchPreference.isEnabled()).isTrue();
- assertThat(mMainSwitchPreference.isChecked()).isTrue();
- }
-
- @Test
- public void testHandlePreferenceTreeClick_samePrefKey_verifyAction() {
- mMainSwitchPreference.setKey(
- AllowBackgroundPreferenceController.KEY_ALLOW_BACKGROUND_USAGE);
- mController.handlePreferenceTreeClick(mMainSwitchPreference);
-
- assertThat(mController.handlePreferenceTreeClick(mMainSwitchPreference)).isTrue();
- }
-
- @Test
- public void testHandlePreferenceTreeClick_incorrectPrefKey_noAction() {
- assertThat(mController.handlePreferenceTreeClick(mMainSwitchPreference)).isFalse();
- }
-}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BackgroundUsageAllowabilityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BackgroundUsageAllowabilityPreferenceControllerTest.java
new file mode 100644
index 0000000..190446e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BackgroundUsageAllowabilityPreferenceControllerTest.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
+import com.android.settingslib.PrimarySwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class BackgroundUsageAllowabilityPreferenceControllerTest {
+ private static final int UID = 12345;
+ private static final String PACKAGE_NAME = "com.android.app";
+
+ private int mTestMode;
+ private Context mContext;
+ private BackgroundUsageAllowabilityPreferenceController mBackgroundUsageController;
+ private BatteryOptimizeUtils mBatteryOptimizeUtils;
+
+ @Mock DashboardFragment mDashboardFragment;
+ @Mock PrimarySwitchPreference mBackgroundUsageAllowabilityPreference;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ prepareTestBatteryOptimizationUtils();
+ mBackgroundUsageController =
+ spy(
+ new BackgroundUsageAllowabilityPreferenceController(
+ mContext,
+ mDashboardFragment,
+ /* preferenceKey= */ "test",
+ mBatteryOptimizeUtils));
+ mBackgroundUsageController.mBackgroundUsageAllowabilityPreference =
+ mBackgroundUsageAllowabilityPreference;
+ }
+
+ @Test
+ public void initPreferences_immutableOptimized_setExpectedContent() {
+ doReturn(false).when(mBatteryOptimizeUtils).isOptimizeModeMutable();
+ doReturn(true).when(mBatteryOptimizeUtils).isDisabledForOptimizeModeOnly();
+
+ mBackgroundUsageController.initPreferences();
+
+ verify(mBackgroundUsageAllowabilityPreference).setEnabled(false);
+ verify(mBackgroundUsageAllowabilityPreference).setSwitchEnabled(false);
+ verify(mBackgroundUsageAllowabilityPreference)
+ .setSummary(
+ mContext.getString(
+ R.string.manager_battery_usage_footer_limited,
+ mContext.getString(R.string.manager_battery_usage_optimized_only)));
+ verify(mBackgroundUsageAllowabilityPreference, never())
+ .setOnPreferenceChangeListener(any());
+ verify(mBackgroundUsageAllowabilityPreference, never()).setOnPreferenceClickListener(any());
+ }
+
+ @Test
+ public void initPreferences_immutableUnrestricted_setExpectedContent() {
+ doReturn(false).when(mBatteryOptimizeUtils).isOptimizeModeMutable();
+ doReturn(false).when(mBatteryOptimizeUtils).isDisabledForOptimizeModeOnly();
+ doReturn(true).when(mBatteryOptimizeUtils).isSystemOrDefaultApp();
+
+ mBackgroundUsageController.initPreferences();
+
+ verify(mBackgroundUsageAllowabilityPreference).setEnabled(false);
+ verify(mBackgroundUsageAllowabilityPreference).setSwitchEnabled(false);
+ verify(mBackgroundUsageAllowabilityPreference)
+ .setSummary(
+ mContext.getString(
+ R.string.manager_battery_usage_footer_limited,
+ mContext.getString(
+ R.string.manager_battery_usage_unrestricted_only)));
+ verify(mBackgroundUsageAllowabilityPreference, never())
+ .setOnPreferenceChangeListener(any());
+ verify(mBackgroundUsageAllowabilityPreference, never()).setOnPreferenceClickListener(any());
+ }
+
+ @Test
+ public void initPreferences_mutableMode_setExpectedContent() {
+ doReturn(true).when(mBatteryOptimizeUtils).isOptimizeModeMutable();
+ doReturn(false).when(mBatteryOptimizeUtils).isDisabledForOptimizeModeOnly();
+ doReturn(false).when(mBatteryOptimizeUtils).isSystemOrDefaultApp();
+
+ mBackgroundUsageController.initPreferences();
+
+ verify(mBackgroundUsageAllowabilityPreference).setEnabled(true);
+ verify(mBackgroundUsageAllowabilityPreference).setSwitchEnabled(true);
+ verify(mBackgroundUsageAllowabilityPreference)
+ .setSummary(
+ mContext.getString(
+ R.string.manager_battery_usage_allow_background_usage_summary));
+ verify(mBackgroundUsageAllowabilityPreference).setOnPreferenceChangeListener(any());
+ verify(mBackgroundUsageAllowabilityPreference).setOnPreferenceClickListener(any());
+ }
+
+ @Test
+ public void updatePreferences_setIntoUnrestrictedMode_setExpectedPrefStatus() {
+ mTestMode = BatteryOptimizeUtils.MODE_UNRESTRICTED;
+
+ mBackgroundUsageController.updatePreferences(mTestMode);
+
+ verifyPreferences(mTestMode);
+ }
+
+ @Test
+ public void updatePreferences_setIntoOptimizedMode_setExpectedPrefStatus() {
+ mTestMode = BatteryOptimizeUtils.MODE_OPTIMIZED;
+
+ mBackgroundUsageController.updatePreferences(mTestMode);
+
+ verifyPreferences(mTestMode);
+ }
+
+ @Test
+ public void updatePreferences_setIntoRestrictedMode_setExpectedPrefStatus() {
+ mTestMode = BatteryOptimizeUtils.MODE_RESTRICTED;
+
+ mBackgroundUsageController.updatePreferences(mTestMode);
+
+ verifyPreferences(mTestMode);
+ }
+
+ @Test
+ public void handleBatteryOptimizeModeUpdated_modeChange_setExpectedPrefStatus() {
+ mTestMode = BatteryOptimizeUtils.MODE_RESTRICTED;
+
+ mBackgroundUsageController.handleBatteryOptimizeModeUpdated(
+ BatteryOptimizeUtils.MODE_OPTIMIZED);
+
+ verify(mBatteryOptimizeUtils)
+ .setAppUsageState(BatteryOptimizeUtils.MODE_OPTIMIZED, Action.APPLY);
+ assertThat(mTestMode).isEqualTo(BatteryOptimizeUtils.MODE_OPTIMIZED);
+ verifyPreferences(mTestMode);
+ }
+
+ @Test
+ public void handleBatteryOptimizeModeUpdated_modeNotChange_setExpectedPrefStatus() {
+ mTestMode = BatteryOptimizeUtils.MODE_RESTRICTED;
+
+ mBackgroundUsageController.handleBatteryOptimizeModeUpdated(
+ BatteryOptimizeUtils.MODE_RESTRICTED);
+
+ verify(mBatteryOptimizeUtils, never()).setAppUsageState(anyInt(), any());
+ assertThat(mTestMode).isEqualTo(BatteryOptimizeUtils.MODE_RESTRICTED);
+ verify(mBackgroundUsageController, never()).updatePreferences(mTestMode);
+ }
+
+ private void prepareTestBatteryOptimizationUtils() {
+ mBatteryOptimizeUtils = spy(new BatteryOptimizeUtils(mContext, UID, PACKAGE_NAME));
+ Answer<Void> setTestMode =
+ invocation -> {
+ mTestMode = invocation.getArgument(0);
+ return null;
+ };
+ doAnswer(setTestMode).when(mBatteryOptimizeUtils).setAppUsageState(anyInt(), any());
+ Answer<Integer> getTestMode = invocation -> mTestMode;
+ doAnswer(getTestMode).when(mBatteryOptimizeUtils).getAppOptimizationMode();
+ }
+
+ private void verifyPreferences(int mode) {
+ boolean isAllowBackground = mode != BatteryOptimizeUtils.MODE_RESTRICTED;
+ verify(mBackgroundUsageAllowabilityPreference).setChecked(isAllowBackground);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizationModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizationModePreferenceControllerTest.java
new file mode 100644
index 0000000..2ddc7eb
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizationModePreferenceControllerTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settingslib.widget.MainSwitchPreference;
+import com.android.settingslib.widget.SelectorWithWidgetPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class BatteryOptimizationModePreferenceControllerTest {
+ private static final int UID = 12345;
+ private static final String PACKAGE_NAME = "com.android.app";
+
+ private int mTestMode;
+ private Context mContext;
+ private BatteryOptimizationModePreferenceController mBackgroundUsageController;
+ private BatteryOptimizeUtils mBatteryOptimizeUtils;
+
+ @Mock MainSwitchPreference mBackgroundUsageAllowabilityPreference;
+ @Mock SelectorWithWidgetPreference mOptimizedPreference;
+ @Mock SelectorWithWidgetPreference mUnrestrictedPreference;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ prepareTestBatteryOptimizationUtils();
+ mBackgroundUsageController =
+ spy(
+ new BatteryOptimizationModePreferenceController(
+ mContext, "test", mBatteryOptimizeUtils));
+ mBackgroundUsageController.mBackgroundUsageAllowabilityPreference =
+ mBackgroundUsageAllowabilityPreference;
+ mBackgroundUsageController.mOptimizedPreference = mOptimizedPreference;
+ mBackgroundUsageController.mUnrestrictedPreference = mUnrestrictedPreference;
+ }
+
+ @Test
+ public void initPreferences_mutableMode_setEnabled() {
+ doReturn(true).when(mBatteryOptimizeUtils).isOptimizeModeMutable();
+
+ mBackgroundUsageController.initPreferences();
+
+ verify(mBackgroundUsageAllowabilityPreference).setEnabled(true);
+ verify(mOptimizedPreference).setEnabled(true);
+ verify(mUnrestrictedPreference).setEnabled(true);
+ verify(mBackgroundUsageAllowabilityPreference, never()).setOnPreferenceClickListener(any());
+ verify(mBackgroundUsageAllowabilityPreference).setOnPreferenceChangeListener(any());
+ verify(mOptimizedPreference).setOnPreferenceClickListener(any());
+ verify(mUnrestrictedPreference).setOnPreferenceClickListener(any());
+ }
+
+ @Test
+ public void initPreferences_immutableMode_setDisabledAndSkipSetListeners() {
+ doReturn(false).when(mBatteryOptimizeUtils).isOptimizeModeMutable();
+
+ mBackgroundUsageController.initPreferences();
+
+ verify(mBackgroundUsageAllowabilityPreference).setEnabled(false);
+ verify(mOptimizedPreference).setEnabled(false);
+ verify(mUnrestrictedPreference).setEnabled(false);
+ verify(mBackgroundUsageAllowabilityPreference, never()).setOnPreferenceClickListener(any());
+ verify(mBackgroundUsageAllowabilityPreference, never())
+ .setOnPreferenceChangeListener(any());
+ verify(mOptimizedPreference, never()).setOnPreferenceClickListener(any());
+ verify(mUnrestrictedPreference, never()).setOnPreferenceClickListener(any());
+ }
+
+ @Test
+ public void updatePreferences_setIntoUnrestrictedMode_setExpectedPrefStatus() {
+ mTestMode = BatteryOptimizeUtils.MODE_UNRESTRICTED;
+
+ mBackgroundUsageController.updatePreferences(mTestMode);
+
+ verifyPreferences(mTestMode);
+ }
+
+ @Test
+ public void updatePreferences_setIntoOptimizedMode_setExpectedPrefStatus() {
+ mTestMode = BatteryOptimizeUtils.MODE_OPTIMIZED;
+
+ mBackgroundUsageController.updatePreferences(mTestMode);
+
+ verifyPreferences(mTestMode);
+ }
+
+ @Test
+ public void updatePreferences_setIntoRestrictedMode_setExpectedPrefStatus() {
+ mTestMode = BatteryOptimizeUtils.MODE_RESTRICTED;
+
+ mBackgroundUsageController.updatePreferences(mTestMode);
+
+ verifyPreferences(mTestMode);
+ }
+
+ @Test
+ public void handleBatteryOptimizeModeUpdated_modeChange_setExpectedPrefStatus() {
+ mTestMode = BatteryOptimizeUtils.MODE_RESTRICTED;
+
+ mBackgroundUsageController.handleBatteryOptimizeModeUpdated(
+ BatteryOptimizeUtils.MODE_OPTIMIZED);
+
+ verify(mBatteryOptimizeUtils)
+ .setAppUsageState(
+ BatteryOptimizeUtils.MODE_OPTIMIZED,
+ BatteryOptimizeHistoricalLogEntry.Action.APPLY);
+ assertThat(mTestMode).isEqualTo(BatteryOptimizeUtils.MODE_OPTIMIZED);
+ verifyPreferences(mBatteryOptimizeUtils.getAppOptimizationMode());
+ }
+
+ @Test
+ public void handleBatteryOptimizeModeUpdated_modeNotChange_setExpectedPrefStatus() {
+ mTestMode = BatteryOptimizeUtils.MODE_RESTRICTED;
+
+ mBackgroundUsageController.handleBatteryOptimizeModeUpdated(
+ BatteryOptimizeUtils.MODE_RESTRICTED);
+
+ verify(mBatteryOptimizeUtils, never()).setAppUsageState(anyInt(), any());
+ assertThat(mTestMode).isEqualTo(BatteryOptimizeUtils.MODE_RESTRICTED);
+ verify(mBackgroundUsageController, never()).updatePreferences(anyInt());
+ }
+
+ private void prepareTestBatteryOptimizationUtils() {
+ mBatteryOptimizeUtils = spy(new BatteryOptimizeUtils(mContext, UID, PACKAGE_NAME));
+ Answer<Void> setTestMode =
+ invocation -> {
+ mTestMode = invocation.getArgument(0);
+ return null;
+ };
+ doAnswer(setTestMode).when(mBatteryOptimizeUtils).setAppUsageState(anyInt(), any());
+ Answer<Integer> getTestMode = invocation -> mTestMode;
+ doAnswer(getTestMode).when(mBatteryOptimizeUtils).getAppOptimizationMode();
+ }
+
+ private void verifyPreferences(int mode) {
+ boolean isAllowBackground = mode != BatteryOptimizeUtils.MODE_RESTRICTED;
+ verify(mBackgroundUsageAllowabilityPreference).setChecked(isAllowBackground);
+ verify(mOptimizedPreference).setEnabled(isAllowBackground);
+ verify(mUnrestrictedPreference).setEnabled(isAllowBackground);
+ verify(mOptimizedPreference).setChecked(mode == BatteryOptimizeUtils.MODE_OPTIMIZED);
+ verify(mUnrestrictedPreference).setChecked(mode == BatteryOptimizeUtils.MODE_UNRESTRICTED);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/OptimizedPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/OptimizedPreferenceControllerTest.java
deleted file mode 100644
index 6656471..0000000
--- a/tests/robotests/src/com/android/settings/fuelgauge/OptimizedPreferenceControllerTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.fuelgauge;
-
-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.when;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-
-import com.android.settingslib.widget.SelectorWithWidgetPreference;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class OptimizedPreferenceControllerTest {
- private static final int UID = 12345;
- private static final String PACKAGE_NAME = "com.android.app";
-
- private OptimizedPreferenceController mController;
- private SelectorWithWidgetPreference mPreference;
- private BatteryOptimizeUtils mBatteryOptimizeUtils;
-
- @Mock PackageManager mMockPackageManager;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- Context context = spy(RuntimeEnvironment.application);
- BatteryUtils.getInstance(context).reset();
- doReturn(UID)
- .when(mMockPackageManager)
- .getPackageUid(PACKAGE_NAME, PackageManager.GET_META_DATA);
-
- mController = new OptimizedPreferenceController(context, UID, PACKAGE_NAME);
- mPreference = new SelectorWithWidgetPreference(RuntimeEnvironment.application);
- mBatteryOptimizeUtils = spy(new BatteryOptimizeUtils(context, UID, PACKAGE_NAME));
- mController.mBatteryOptimizeUtils = mBatteryOptimizeUtils;
- }
-
- @Test
- public void testUpdateState_invalidPackage_prefEnabled() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isEnabled()).isFalse();
- assertThat(mPreference.isChecked()).isTrue();
- }
-
- @Test
- public void testUpdateState_isSystemOrDefaultAppAndOptimizeStates_prefChecked() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
- when(mBatteryOptimizeUtils.getAppOptimizationMode())
- .thenReturn(BatteryOptimizeUtils.MODE_OPTIMIZED);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isChecked()).isTrue();
- }
-
- @Test
- public void testUpdateState_isSystemOrDefaultApp_prefUnchecked() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isChecked()).isFalse();
- assertThat(mPreference.isEnabled()).isFalse();
- }
-
- @Test
- public void testUpdateState_isOptimizedStates_prefChecked() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mBatteryOptimizeUtils.getAppOptimizationMode())
- .thenReturn(BatteryOptimizeUtils.MODE_OPTIMIZED);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isChecked()).isTrue();
- }
-
- @Test
- public void testUpdateState_prefUnchecked() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isChecked()).isFalse();
- }
-
- @Test
- public void testHandlePreferenceTreeClick_samePrefKey_verifyAction() {
- mPreference.setKey(mController.KEY_OPTIMIZED_PREF);
- mController.handlePreferenceTreeClick(mPreference);
-
- assertThat(mController.handlePreferenceTreeClick(mPreference)).isTrue();
- }
-
- @Test
- public void testHandlePreferenceTreeClick_incorrectPrefKey_noAction() {
- assertThat(mController.handlePreferenceTreeClick(mPreference)).isFalse();
- }
-}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetailTest.java
index 9061117..9f98d78 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetailTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetailTest.java
@@ -17,10 +17,10 @@
package com.android.settings.fuelgauge;
import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS;
-import static com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
@@ -42,16 +42,17 @@
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
-import android.widget.CompoundButton;
import androidx.fragment.app.FragmentActivity;
import androidx.loader.app.LoaderManager;
import androidx.test.core.app.ApplicationProvider;
+import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.fuelgauge.batteryusage.BatteryEntry;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
+import com.android.settings.testutils.shadow.ShadowHelpUtils;
import com.android.settings.widget.EntityHeaderController;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
@@ -59,8 +60,6 @@
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.widget.FooterPreference;
import com.android.settingslib.widget.LayoutPreference;
-import com.android.settingslib.widget.MainSwitchPreference;
-import com.android.settingslib.widget.SelectorWithWidgetPreference;
import org.junit.After;
import org.junit.Before;
@@ -83,36 +82,33 @@
@Config(
shadows = {
ShadowEntityHeaderController.class,
+ ShadowHelpUtils.class,
com.android.settings.testutils.shadow.ShadowFragment.class,
})
public class PowerBackgroundUsageDetailTest {
- @Rule
- public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
private static final String APP_LABEL = "app label";
private static final String SUMMARY = "summary";
private static final int ICON_ID = 123;
private static final int UID = 1;
- private static final String KEY_PREF_UNRESTRICTED = "unrestricted_preference";
- private static final String KEY_PREF_OPTIMIZED = "optimized_preference";
- private static final String KEY_ALLOW_BACKGROUND_USAGE = "allow_background_usage";
+ private static final String PACKAGE_NAME = "com.android.app";
+ private static final String KEY_PREF_HEADER = "header_view";
+ private static final String KEY_FOOTER_PREFERENCE = "app_usage_footer_preference";
+ private static final String INITIATING_PACKAGE_NAME = "com.android.vending";
+ private int mTestMode;
private Context mContext;
private PowerBackgroundUsageDetail mFragment;
- private FooterPreference mFooterPreference;
- private MainSwitchPreference mMainSwitchPreference;
private MetricsFeatureProvider mMetricsFeatureProvider;
- private SelectorWithWidgetPreference mOptimizePreference;
- private SelectorWithWidgetPreference mUnrestrictedPreference;
private SettingsActivity mTestActivity;
+ private BatteryOptimizeUtils mBatteryOptimizeUtils;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private FragmentActivity mActivity;
@Mock private EntityHeaderController mEntityHeaderController;
- @Mock private BatteryOptimizeUtils mBatteryOptimizeUtils;
- @Mock private LayoutPreference mHeaderPreference;
@Mock private ApplicationsState mState;
@Mock private Bundle mBundle;
@Mock private LoaderManager mLoaderManager;
@@ -120,21 +116,26 @@
@Mock private BatteryEntry mBatteryEntry;
@Mock private PackageManager mPackageManager;
@Mock private AppOpsManager mAppOpsManager;
- @Mock private CompoundButton mMockSwitch;
@Mock private InstallSourceInfo mInstallSourceInfo;
+ @Mock private LayoutPreference mLayoutPreference;
+ @Mock private FooterPreference mFooterPreference;
@Before
public void setUp() throws Exception {
mContext = spy(ApplicationProvider.getApplicationContext());
- when(mContext.getPackageName()).thenReturn("foo");
+ when(mContext.getPackageName()).thenReturn(PACKAGE_NAME);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(mInstallSourceInfo);
final FakeFeatureFactory fakeFeatureFactory = FakeFeatureFactory.setupForTest();
mMetricsFeatureProvider = fakeFeatureFactory.metricsFeatureProvider;
+ prepareTestBatteryOptimizationUtils();
mFragment = spy(new PowerBackgroundUsageDetail());
+ mFragment.mBatteryOptimizeUtils = mBatteryOptimizeUtils;
mFragment.mLogStringBuilder = new StringBuilder();
+ doReturn(mLayoutPreference).when(mFragment).findPreference(KEY_PREF_HEADER);
+ doReturn(mFooterPreference).when(mFragment).findPreference(KEY_FOOTER_PREFERENCE);
doReturn(mContext).when(mFragment).getContext();
doReturn(mActivity).when(mFragment).getActivity();
doReturn(SUMMARY).when(mFragment).getString(anyInt());
@@ -169,9 +170,7 @@
when(mBatteryEntry.getLabel()).thenReturn(APP_LABEL);
mBatteryEntry.mIconId = ICON_ID;
- mFragment.mHeaderPreference = mHeaderPreference;
mFragment.mState = mState;
- mFragment.mBatteryOptimizeUtils = mBatteryOptimizeUtils;
mAppEntry.info = mock(ApplicationInfo.class);
mTestActivity = spy(new SettingsActivity());
@@ -191,23 +190,12 @@
.when(mActivity)
.startActivityAsUser(captor.capture(), nullable(UserHandle.class));
doAnswer(callable).when(mActivity).startActivity(captor.capture());
-
- mFooterPreference = spy(new FooterPreference(mContext));
- mMainSwitchPreference = spy(new MainSwitchPreference(mContext));
- mMainSwitchPreference.setKey(KEY_ALLOW_BACKGROUND_USAGE);
- mOptimizePreference = spy(new SelectorWithWidgetPreference(mContext));
- mOptimizePreference.setKey(KEY_PREF_OPTIMIZED);
- mUnrestrictedPreference = spy(new SelectorWithWidgetPreference(mContext));
- mUnrestrictedPreference.setKey(KEY_PREF_UNRESTRICTED);
- mFragment.mFooterPreference = mFooterPreference;
- mFragment.mMainSwitchPreference = mMainSwitchPreference;
- mFragment.mOptimizePreference = mOptimizePreference;
- mFragment.mUnrestrictedPreference = mUnrestrictedPreference;
}
@After
public void reset() {
ShadowEntityHeaderController.reset();
+ ShadowHelpUtils.reset();
}
@Test
@@ -258,91 +246,64 @@
}
@Test
- public void initFooter_hasCorrectString() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(false);
-
+ public void initFooter_setExpectedFooterContent() {
mFragment.initFooter();
- assertThat(mFooterPreference.getTitle().toString())
- .isEqualTo("Changing how an app uses your battery can affect its performance.");
+ verify(mFooterPreference)
+ .setTitle(mContext.getString(R.string.manager_battery_usage_footer));
+ verify(mFooterPreference).setLearnMoreAction(any());
+ verify(mFooterPreference)
+ .setLearnMoreText(mContext.getString(R.string.manager_battery_usage_link_a11y));
}
@Test
- public void onSwitchChanged_fromUnrestrictedModeSetDisabled_becomeRestrictedMode() {
- final int restrictedMode = BatteryOptimizeUtils.MODE_RESTRICTED;
- final int optimizedMode = BatteryOptimizeUtils.MODE_OPTIMIZED;
- mFragment.mOptimizationMode = optimizedMode;
+ public void onPause_optimizationModeIsChanged_logPreference() throws Exception {
+ mFragment.mOptimizationMode = BatteryOptimizeUtils.MODE_OPTIMIZED;
+ when(mBatteryOptimizeUtils.getPackageName()).thenReturn(PACKAGE_NAME);
+ when(mInstallSourceInfo.getInitiatingPackageName()).thenReturn(INITIATING_PACKAGE_NAME);
- mFragment.onCheckedChanged(mMockSwitch, /* isChecked= */ false);
-
- verify(mOptimizePreference).setEnabled(false);
- verify(mUnrestrictedPreference).setEnabled(false);
- verify(mFragment).onRadioButtonClicked(null);
- verify(mMainSwitchPreference).setChecked(false);
- assertThat(mFragment.getSelectedPreference()).isEqualTo(restrictedMode);
- verify(mBatteryOptimizeUtils).setAppUsageState(restrictedMode, Action.APPLY);
- }
-
- @Test
- public void onSwitchChanged_fromRestrictedModeSetEnabled_becomeOptimizedMode() {
- final int restrictedMode = BatteryOptimizeUtils.MODE_RESTRICTED;
- final int optimizedMode = BatteryOptimizeUtils.MODE_OPTIMIZED;
- mFragment.mOptimizationMode = restrictedMode;
-
- mFragment.onCheckedChanged(mMockSwitch, /* isChecked= */ true);
-
- verify(mOptimizePreference).setEnabled(true);
- verify(mUnrestrictedPreference).setEnabled(true);
- verify(mFragment).onRadioButtonClicked(mOptimizePreference);
- verify(mMainSwitchPreference).setChecked(true);
- verify(mOptimizePreference).setChecked(true);
- assertThat(mFragment.getSelectedPreference()).isEqualTo(optimizedMode);
- verify(mBatteryOptimizeUtils).setAppUsageState(optimizedMode, Action.APPLY);
- }
-
- @Test
- public void onPause_optimizationModeChanged_logPreference() throws Exception {
- final String packageName = "testPackageName";
- final int restrictedMode = BatteryOptimizeUtils.MODE_RESTRICTED;
- final int optimizedMode = BatteryOptimizeUtils.MODE_OPTIMIZED;
- mFragment.mOptimizationMode = restrictedMode;
- when(mBatteryOptimizeUtils.getPackageName()).thenReturn(packageName);
- when(mInstallSourceInfo.getInitiatingPackageName()).thenReturn("com.android.vending");
-
- mFragment.onCheckedChanged(mMockSwitch, /* isChecked= */ true);
- verify(mBatteryOptimizeUtils).setAppUsageState(optimizedMode, Action.APPLY);
- when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(optimizedMode);
+ mTestMode = BatteryOptimizeUtils.MODE_UNRESTRICTED;
+ assertThat(mBatteryOptimizeUtils.getAppOptimizationMode())
+ .isEqualTo(BatteryOptimizeUtils.MODE_UNRESTRICTED);
mFragment.onPause();
TimeUnit.SECONDS.sleep(1);
verify(mMetricsFeatureProvider)
.action(
SettingsEnums.LEAVE_POWER_USAGE_MANAGE_BACKGROUND,
- SettingsEnums.ACTION_APP_BATTERY_USAGE_OPTIMIZED,
+ SettingsEnums.ACTION_APP_BATTERY_USAGE_UNRESTRICTED,
SettingsEnums.FUELGAUGE_POWER_USAGE_MANAGE_BACKGROUND,
- packageName,
+ PACKAGE_NAME,
/* consumed battery */ 0);
}
@Test
public void onPause_optimizationModeIsNotChanged_notInvokeLogging() throws Exception {
- final String packageName = "testPackageName";
- final int restrictedMode = BatteryOptimizeUtils.MODE_RESTRICTED;
- final int optimizedMode = BatteryOptimizeUtils.MODE_OPTIMIZED;
- mFragment.mOptimizationMode = restrictedMode;
- when(mBatteryOptimizeUtils.getPackageName()).thenReturn(packageName);
- when(mInstallSourceInfo.getInitiatingPackageName()).thenReturn("com.android.vending");
+ mFragment.mOptimizationMode = BatteryOptimizeUtils.MODE_OPTIMIZED;
+ when(mBatteryOptimizeUtils.getPackageName()).thenReturn(PACKAGE_NAME);
+ when(mInstallSourceInfo.getInitiatingPackageName()).thenReturn(INITIATING_PACKAGE_NAME);
- mFragment.onCheckedChanged(mMockSwitch, /* isChecked= */ true);
- verify(mBatteryOptimizeUtils).setAppUsageState(optimizedMode, Action.APPLY);
- when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(optimizedMode);
- mFragment.onCheckedChanged(mMockSwitch, /* isChecked= */ false);
- verify(mBatteryOptimizeUtils).setAppUsageState(restrictedMode, Action.APPLY);
- when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(restrictedMode);
+ mTestMode = BatteryOptimizeUtils.MODE_UNRESTRICTED;
+ assertThat(mBatteryOptimizeUtils.getAppOptimizationMode())
+ .isEqualTo(BatteryOptimizeUtils.MODE_UNRESTRICTED);
+ mTestMode = BatteryOptimizeUtils.MODE_OPTIMIZED;
+ assertThat(mBatteryOptimizeUtils.getAppOptimizationMode())
+ .isEqualTo(BatteryOptimizeUtils.MODE_OPTIMIZED);
mFragment.onPause();
TimeUnit.SECONDS.sleep(1);
verifyNoInteractions(mMetricsFeatureProvider);
}
+
+ private void prepareTestBatteryOptimizationUtils() {
+ mBatteryOptimizeUtils = spy(new BatteryOptimizeUtils(mContext, UID, PACKAGE_NAME));
+ Answer<Void> setTestMode =
+ invocation -> {
+ mTestMode = invocation.getArgument(0);
+ return null;
+ };
+ doAnswer(setTestMode).when(mBatteryOptimizeUtils).setAppUsageState(anyInt(), any());
+ Answer<Integer> getTestMode = invocation -> mTestMode;
+ doAnswer(getTestMode).when(mBatteryOptimizeUtils).getAppOptimizationMode();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/UnrestrictedPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/UnrestrictedPreferenceControllerTest.java
deleted file mode 100644
index 0c6f7da..0000000
--- a/tests/robotests/src/com/android/settings/fuelgauge/UnrestrictedPreferenceControllerTest.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.fuelgauge;
-
-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.when;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-
-import com.android.settingslib.widget.SelectorWithWidgetPreference;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class UnrestrictedPreferenceControllerTest {
- private static final int UID = 12345;
- private static final String PACKAGE_NAME = "com.android.app";
-
- private UnrestrictedPreferenceController mController;
- private SelectorWithWidgetPreference mPreference;
- private BatteryOptimizeUtils mBatteryOptimizeUtils;
-
- @Mock PackageManager mMockPackageManager;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- Context context = spy(RuntimeEnvironment.application);
- BatteryUtils.getInstance(context).reset();
- doReturn(UID)
- .when(mMockPackageManager)
- .getPackageUid(PACKAGE_NAME, PackageManager.GET_META_DATA);
-
- mController = new UnrestrictedPreferenceController(context, UID, PACKAGE_NAME);
- mPreference = new SelectorWithWidgetPreference(RuntimeEnvironment.application);
- mBatteryOptimizeUtils = spy(new BatteryOptimizeUtils(context, UID, PACKAGE_NAME));
- mController.mBatteryOptimizeUtils = mBatteryOptimizeUtils;
- }
-
- @Test
- public void testUpdateState_isValidPackage_prefEnabled() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(false);
-
- mController.updateState(mPreference);
-
- assertThat(mBatteryOptimizeUtils.isOptimizeModeMutable()).isTrue();
- assertThat(mPreference.isEnabled()).isTrue();
- }
-
- @Test
- public void testUpdateState_invalidPackage_prefDisabled() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
- when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(false);
-
- mController.updateState(mPreference);
-
- assertThat(mBatteryOptimizeUtils.isOptimizeModeMutable()).isFalse();
- assertThat(mPreference.isEnabled()).isFalse();
- }
-
- @Test
- public void testUpdateState_isSystemOrDefaultAppAndUnrestrictedStates_prefChecked() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
- when(mBatteryOptimizeUtils.getAppOptimizationMode())
- .thenReturn(BatteryOptimizeUtils.MODE_UNRESTRICTED);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isChecked()).isTrue();
- }
-
- @Test
- public void testUpdateState_isSystemOrDefaultApp_prefUnchecked() {
- when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
- when(mBatteryOptimizeUtils.getAppOptimizationMode())
- .thenReturn(BatteryOptimizeUtils.MODE_OPTIMIZED);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isEnabled()).isFalse();
- assertThat(mPreference.isChecked()).isFalse();
- }
-
- @Test
- public void testUpdateState_isUnrestrictedStates_prefChecked() {
- when(mBatteryOptimizeUtils.isOptimizeModeMutable()).thenReturn(true);
- when(mBatteryOptimizeUtils.getAppOptimizationMode())
- .thenReturn(BatteryOptimizeUtils.MODE_UNRESTRICTED);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isEnabled()).isTrue();
- assertThat(mPreference.isChecked()).isTrue();
- }
-
- @Test
- public void testUpdateState_prefUnchecked() {
- when(mBatteryOptimizeUtils.isOptimizeModeMutable()).thenReturn(true);
- when(mBatteryOptimizeUtils.getAppOptimizationMode())
- .thenReturn(BatteryOptimizeUtils.MODE_OPTIMIZED);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isEnabled()).isTrue();
- assertThat(mPreference.isChecked()).isFalse();
- }
-
- @Test
- public void testHandlePreferenceTreeClick_samePrefKey_verifyAction() {
- mPreference.setKey(mController.KEY_UNRESTRICTED_PREF);
- mController.handlePreferenceTreeClick(mPreference);
-
- assertThat(mController.handlePreferenceTreeClick(mPreference)).isTrue();
- }
-
- @Test
- public void testHandlePreferenceTreeClick_incorrectPrefKey_noAction() {
- assertThat(mController.handlePreferenceTreeClick(mPreference)).isFalse();
- }
-}
diff --git a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
index 400f73f..df399d7 100644
--- a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
@@ -70,6 +70,7 @@
import com.android.settings.AirplaneModeEnabler;
import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFeatureProvider;
import com.android.settings.datausage.DataUsagePreference;
import com.android.settings.testutils.shadow.ShadowDataUsageUtils;
import com.android.settings.testutils.shadow.ShadowFragment;
@@ -98,6 +99,7 @@
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowToast;
+import org.robolectric.util.ReflectionHelpers;
import java.util.List;
@@ -190,6 +192,9 @@
.when(mFirstWifiEntryPreferenceCategory).getKey();
mNetworkProviderSettings.mFirstWifiEntryPreferenceCategory =
mFirstWifiEntryPreferenceCategory;
+
+ ReflectionHelpers.setField(mNetworkProviderSettings, "mDashboardFeatureProvider",
+ mock(DashboardFeatureProvider.class));
}
@Test
diff --git a/tests/robotests/src/com/android/settings/network/apn/ApnEditorTest.java b/tests/robotests/src/com/android/settings/network/apn/ApnEditorTest.java
deleted file mode 100644
index d8895d5..0000000
--- a/tests/robotests/src/com/android/settings/network/apn/ApnEditorTest.java
+++ /dev/null
@@ -1,625 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.network.apn;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.PersistableBundle;
-import android.os.UserManager;
-import android.telephony.CarrierConfigManager;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-
-import androidx.fragment.app.FragmentActivity;
-import androidx.preference.EditTextPreference;
-import androidx.preference.ListPreference;
-import androidx.preference.MultiSelectListPreference;
-import androidx.preference.SwitchPreference;
-
-import com.android.settings.R;
-import com.android.settings.network.ProxySubscriptionManager;
-import com.android.settings.network.apn.ApnEditor.ApnData;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {
- com.android.settings.testutils.shadow.ShadowFragment.class,
-})
-public class ApnEditorTest {
-
- private static final Object[] APN_DATA = {
- 0, /* ID */
- "apn_name" /* apn name */,
- "apn.com" /* apn */,
- "" /* proxy */,
- "" /* port */,
- "" /* username */,
- "" /* server */,
- "" /* password */,
- "" /* MMSC */,
- "123" /* MCC */,
- "456" /* MNC */,
- "123456" /* operator numeric */,
- "" /* MMS proxy */,
- "" /* MMS port */,
- 0 /* Authentication type */,
- "default,supl,ia" /* APN type */,
- "IP" /* APN protocol */,
- 1 /* APN enable/disable */,
- 0 /* Bearer */,
- 0 /* Bearer BITMASK*/,
- "IPV6" /* APN roaming protocol */,
- "None" /* MVNO type */,
- "", /* MVNO value */
- };
-
- private static final int CURSOR_INTEGER_INDEX = 0;
- private static final int CURSOR_STRING_INDEX = 1;
-
- private static final Uri APN_URI = Uri.parse("Apn://row/1");
-
- @Mock
- private Cursor mCursor;
-
- @Mock
- private FragmentActivity mActivity;
- @Mock
- private UserManager mUserManager;
- @Mock
- private ProxySubscriptionManager mProxySubscriptionMgr;
- @Mock
- private CarrierConfigManager mCarrierConfigManager;
- @Captor
- private ArgumentCaptor<Uri> mUriCaptor;
-
- private ApnEditor mApnEditorUT;
- private Context mContext;
- private Resources mResources;
- private PersistableBundle mBundle = new PersistableBundle();
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = spy(RuntimeEnvironment.application);
-
- mResources = mContext.getResources();
- mApnEditorUT = spy(new ApnEditor());
-
- doReturn(mActivity).when(mApnEditorUT).getActivity();
- doReturn(mResources).when(mApnEditorUT).getResources();
- doNothing().when(mApnEditorUT).finish();
- doNothing().when(mApnEditorUT).showError();
- doReturn(mContext).when(mApnEditorUT).getContext();
- doReturn(mContext.getTheme()).when(mActivity).getTheme();
- doReturn(mContext.getContentResolver()).when(mActivity).getContentResolver();
-
- doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
- doReturn(true).when(mUserManager).isAdminUser();
- doReturn(false).when(mUserManager)
- .hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
- doReturn(mCarrierConfigManager).when(mContext)
- .getSystemService(Context.CARRIER_CONFIG_SERVICE);
- doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt());
-
- setMockPreference(mContext);
- mApnEditorUT.mApnData = new FakeApnData(APN_DATA);
- mApnEditorUT.sNotSet = "Not Set";
- }
-
- @Test
- public void testApnEditor_doesNotUseManagedQuery() {
- mApnEditorUT.getApnDataFromUri(Mockito.mock(Uri.class));
-
- verify(mActivity, never()).managedQuery(
- any(Uri.class),
- any(String[].class),
- any(String.class),
- any(String.class));
-
- verify(mActivity, never()).managedQuery(
- any(Uri.class),
- any(String[].class),
- any(String.class),
- any(String[].class),
- any(String.class));
- }
-
- @Test
- public void getApnDataFromUri_emptyCursor_returnsNull() {
- var mockContentResolver = mock(ContentResolver.class);
- var mockCursor = mock(Cursor.class);
- doReturn(mockContentResolver).when(mActivity).getContentResolver();
- when(mockContentResolver.query(any(), any(), any(), any(), any())).thenReturn(mockCursor);
- when(mockCursor.moveToFirst()).thenReturn(false);
-
- var apnData = mApnEditorUT.getApnDataFromUri(mock(Uri.class));
-
- assertThat(apnData).isNull();
- }
-
- @Test
- public void testSetStringValue_valueChanged_shouldSetValue() {
- // GIVEN an APN value which is different than the APN value in database
- final String apnKey = "apn";
- final String apnValue = "testing.com";
- final ContentValues cv = new ContentValues();
-
- // WHEN try to check and set the apn value
- final boolean isDiff = mApnEditorUT.setStringValueAndCheckIfDiff(
- cv, apnKey, apnValue, false /* assumeDiff */, ApnEditor.APN_INDEX);
-
- // THEN the APN value is different than the one in database, and it has been stored in the
- // given ContentValues
- assertThat(isDiff).isTrue();
- assertThat(apnValue).isEqualTo(cv.getAsString(apnKey));
- }
-
- @Test
- public void testSetStringValue_valueNotChanged_shouldNotSetValue() {
- // GIVEN an APN value which is same as the APN value in database
- final String apnKey = "apn";
- final String apnValue = (String) APN_DATA[ApnEditor.APN_INDEX];
- final ContentValues cv = new ContentValues();
-
- // WHEN try to check and set the apn value
- final boolean isDiff = mApnEditorUT.setStringValueAndCheckIfDiff(
- cv, apnKey, apnValue, false /* assumeDiff */, ApnEditor.APN_INDEX);
-
- // THEN the APN value is same as the one in database, and the new APN value is not stored
- // in the given ContentValues
- assertThat(isDiff).isFalse();
- assertThat(cv.get(apnKey)).isNull();
- }
-
- @Test
- public void testSetStringValue_nullValue_shouldNotSetValue_shouldNotSetValue() {
- // GIVEN a null APN value
- final String apnKey = "apn";
- final String apnValue = null;
- final ContentValues cv = new ContentValues();
-
- // WHEN try to check and set the apn value
- final boolean isDiff = mApnEditorUT.setStringValueAndCheckIfDiff(
- cv, apnKey, apnValue, false /* assumeDiff */, ApnEditor.APN_INDEX);
-
- // THEN the APN value is different than the one in database, but the null value is not
- // stored in the given ContentValues
- assertThat(isDiff).isTrue();
- assertThat(cv.get(apnKey)).isNull();
- }
-
- @Test
- public void testSetIntValue_valueChanged_shouldSetValue() {
- // GIVEN a value indicated whether the apn is enabled, and it's different than the value in
- // the database
- final String apnEnabledKey = "apn_enabled";
- final int apnEnabledValue = 0;
- final ContentValues cv = new ContentValues();
-
- // WHEN try to check and set the apn enabled
- final boolean isDiff = mApnEditorUT.setIntValueAndCheckIfDiff(
- cv,
- apnEnabledKey,
- apnEnabledValue,
- false /* assumeDiff */,
- ApnEditor.CARRIER_ENABLED_INDEX);
-
- // THEN the apn enabled field is different than the one in database, and it has been stored
- // in the given ContentValues
- assertThat(isDiff).isTrue();
- assertThat(cv.getAsInteger(apnEnabledKey)).isEqualTo(apnEnabledValue);
- }
-
- @Test
- public void testSetIntValue_valueNotChanged_shouldNotSetValue() {
- // GIVEN a value indicated whether the apn is enabled, and it's same as the one in the
- // database
- final String apnEnabledKey = "apn_enabled";
- final int apnEnabledValue = (int) APN_DATA[ApnEditor.CARRIER_ENABLED_INDEX];
- final ContentValues cv = new ContentValues();
-
- // WHEN try to check and set the apn enabled
- final boolean isDiff = mApnEditorUT.setIntValueAndCheckIfDiff(
- cv,
- apnEnabledKey,
- apnEnabledValue,
- false /* assumeDiff */,
- ApnEditor.CARRIER_ENABLED_INDEX);
-
- // THEN the apn enabled field is same as the one in the database, and the filed is not
- // stored in the given ContentValues
- assertThat(isDiff).isFalse();
- assertThat(cv.get(apnEnabledKey)).isNull();
- }
-
- @Test
- public void testValidateApnData_validData_shouldReturnNull() {
- // GIVEN a valid apn data
- mApnEditorUT.fillUI(true /* firstTime */);
-
- // WHEN validate the apn data
- final String errMsg = mApnEditorUT.validateApnData();
-
- // THEN the error message should be null
- assertThat(errMsg).isNull();
- }
-
- @Test
- public void testValidateApn_apnNameNotSet_shouldReturnErrorMessage() {
- // GIVEN a apn data without the apn name
- mApnEditorUT.mApnData.mData[ApnEditor.NAME_INDEX] = "";
- mApnEditorUT.fillUI(true /* firstTime */);
-
- // THEN validate the apn data
- final String errMsg = mApnEditorUT.validateApnData();
-
- // THEN the error message indicated the apn name not set is returned
- assertThat(errMsg).isEqualTo(mResources.getString(R.string.error_name_empty));
- }
-
- @Test
- public void testValidateApnData_apnNotSet_shouldReturnErrorMessage() {
- // GIVEN a apn data without the apn
- mApnEditorUT.mApnData.mData[ApnEditor.APN_INDEX] = "";
- mApnEditorUT.fillUI(true /* firstTime */);
-
- // THEN validate the apn data
- final String errMsg = mApnEditorUT.validateApnData();
-
- // THEN the error message indicated the apn not set is returned
- assertThat(errMsg).isEqualTo(mResources.getString(R.string.error_apn_empty));
- }
-
- @Test
- public void testValidateApnData_mccInvalid_shouldReturnErrorMessage() {
- // The length of the mcc should be 3
- mApnEditorUT.mApnData.mData[ApnEditor.MCC_INDEX] = "1324";
- mApnEditorUT.fillUI(true /* firstTime */);
-
- // WHEN validate the apn data
- final String errMsg = mApnEditorUT.validateApnData();
-
- // THEN the error message indicated the mcc invalid is returned
- assertThat(errMsg).isEqualTo(mResources.getString(R.string.error_mcc_not3));
- }
-
- @Test
- public void testValidateApnData_mncInvalid_shouldReturnErrorMessage() {
- // GIVEN an apn data with invalid mnc
- // The length of the mnc should be 2 or 3
- mApnEditorUT.mApnData.mData[ApnEditor.MNC_INDEX] = "1324";
- mApnEditorUT.fillUI(true /* firstTime */);
-
- // WHEN validate the apn data
- final String errMsg = mApnEditorUT.validateApnData();
-
- // THEN the error message indicated the mnc invalid is returned
- assertThat(errMsg).isEqualTo(mResources.getString(R.string.error_mnc_not23));
- }
-
- @Test
- public void testSaveApnData_pressBackButtonWithValidApnData_shouldSaveApnData() {
- // GIVEN a valid apn data
- mApnEditorUT.fillUI(true /* firstTime */);
-
- // WHEN press the back button
- final KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
- mApnEditorUT.onKey(new View(mContext), KeyEvent.KEYCODE_BACK, event);
-
- // THEN the apn data is saved and the apn editor is closed
- verify(mApnEditorUT).validateAndSaveApnData();
- verify(mApnEditorUT).finish();
- }
-
- @Test
- public void testSaveApnData_pressSaveButtonWithValidApnData_shouldSaveApnData() {
- // GIVEN a valid apn data
- mApnEditorUT.fillUI(true /* firstTime */);
-
- // WHEN press the save button
- MenuItem item = Mockito.mock(MenuItem.class);
- // Menu.FIRST + 1 indicated the SAVE option in ApnEditor
- doReturn(Menu.FIRST + 1).when(item).getItemId();
- mApnEditorUT.onOptionsItemSelected(item);
-
- // THEN the apn data is saved and the apn editor is closed
- verify(mApnEditorUT).validateAndSaveApnData();
- verify(mApnEditorUT).finish();
- }
-
- @Test
- public void testSaveApnData_apnDataInvalid_shouldNotSaveApnData() {
- // GIVEN an invalid apn data
- // The valid apn data should contains a non-empty apn name
- mApnEditorUT.mApnData.mData[ApnEditor.NAME_INDEX] = "";
- mApnEditorUT.fillUI(true /* firstTime */);
-
- // WHEN press the save button
- final MenuItem item = Mockito.mock(MenuItem.class);
- // Menu.FIRST + 1 indicated the SAVE option in ApnEditor
- doReturn(Menu.FIRST + 1).when(item).getItemId();
- mApnEditorUT.onOptionsItemSelected(item);
-
- // THEN the error dialog is shown
- verify(mApnEditorUT).validateAndSaveApnData();
- verify(mApnEditorUT).showError();
- }
-
- @Test
- public void testDeleteApnData_shouldDeleteData() {
- // GIVEN a valid apn data correspond a row in database
- final Uri apnUri = Uri.parse("content://telephony/carriers/1");
- mApnEditorUT.mApnData = new FakeApnData(APN_DATA, apnUri);
- mApnEditorUT.fillUI(true /* firstTime */);
- ContentResolver mockContentResolver = Mockito.mock(ContentResolver.class);
- doReturn(mockContentResolver).when(mActivity).getContentResolver();
-
- // WHEN press the save button
- final MenuItem item = Mockito.mock(MenuItem.class);
- // Menu.FIRST indicated the DELETE option in ApnEditor
- doReturn(Menu.FIRST).when(item).getItemId();
- mApnEditorUT.onOptionsItemSelected(item);
-
- // THEN the apn data is deleted and the apn editor is closed
- verify(mockContentResolver).delete(mUriCaptor.capture(), any(), any());
- assertThat(apnUri).isEqualTo(mUriCaptor.getValue());
- verify(mApnEditorUT).finish();
- }
-
- @Test
- public void testDeleteApnData_shouldNotPresentMenuWhenNotSupportAdding() {
- mBundle.putBoolean(CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL, false);
-
- MenuItem item = Mockito.mock(MenuItem.class);
- Menu menu = Mockito.mock(Menu.class);
- doReturn(item).when(menu).add(anyInt(), anyInt(), anyInt(), anyInt());
-
- mApnEditorUT.getCarrierCustomizedConfig(mContext);
- mApnEditorUT.onCreateOptionsMenu(menu, null);
-
- verify(menu, times(0)).add(anyInt(), eq(ApnEditor.MENU_DELETE), anyInt(), anyInt());
- }
-
- @Test(expected = ClassCastException.class)
- public void testApnData_invalidIntegerType_throwsInvalidTypeException() {
- // GIVEN a ApnData constructed from cursor
- initCursor();
- final ApnData data = new ApnData(APN_URI, mCursor);
-
- // WHEN get a string from an integer column
- // THEN the InvalidTypeException is threw
- data.getString(CURSOR_INTEGER_INDEX);
- }
-
- @Test(expected = ClassCastException.class)
- public void testApnData_invalidStringType_throwsInvalidTypeException() {
- // GIVEN a ApnData constructed from cursor
- initCursor();
- final ApnData data = new ApnData(APN_URI, mCursor);
-
- // WHEN get a integer from a string column
- // THEN the InvalidTypeException is threw
- data.getInteger(CURSOR_STRING_INDEX);
- }
-
- @Test
- public void testApnData_validIntegerType_returnCorrectValue() {
- // GIVEN a ApnData constructed from cursor
- initCursor();
- final ApnData data = new ApnData(APN_URI, mCursor);
-
- // WHEN get integer from an integer column
- final int val = data.getInteger(CURSOR_INTEGER_INDEX);
-
- // THEN the integer is returned correctly
- assertThat(val).isEqualTo(mCursor.getInt(CURSOR_INTEGER_INDEX));
- }
-
- @Test
- public void testApnData_validStringType_returnCorrectValue() {
- // GIVEN a ApnData constructed from cursor
- initCursor();
- final ApnData data = new ApnData(APN_URI, mCursor);
-
- // WHEN get string from a string column
- final String str = data.getString(CURSOR_STRING_INDEX);
-
- // THEN the integer is returned correctly
- assertThat(str).isEqualTo(mCursor.getString(CURSOR_STRING_INDEX));
- }
-
- @Test
- public void testApnData_nullValueColumn_returnNull() {
- // GIVEN a empty ApnData
- final ApnData data = new ApnData(3);
-
- // WHEN get string value from a null column
- final String str = data.getString(0);
-
- // THEN the null value is returned
- assertThat(str).isNull();
- }
-
- @Test
- public void formatInteger_shouldParseString() {
- assertThat(ApnEditor.formatInteger("42")).isEqualTo("42");
- assertThat(ApnEditor.formatInteger("01")).isEqualTo("01");
- assertThat(ApnEditor.formatInteger("001")).isEqualTo("001");
- }
-
- @Test
- public void formatInteger_shouldIgnoreNonIntegers() {
- assertThat(ApnEditor.formatInteger("not an int")).isEqualTo("not an int");
- }
-
- @Test
- public void onCreate_notAdminUser_shouldFinish() {
- doReturn(false).when(mUserManager).isAdminUser();
-
- mApnEditorUT.onCreate(null);
-
- verify(mApnEditorUT).finish();
- }
-
- @Test
- public void onCreate_hasUserRestriction_shouldFinish() {
- doReturn(true).when(mUserManager)
- .hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
-
- mApnEditorUT.onCreate(null);
-
- verify(mApnEditorUT).finish();
- }
-
- @Test
- public void onCreate_noAction_shouldFinishAndNoCrash() {
- ProxySubscriptionManager proxySubscriptionMgr = mock(ProxySubscriptionManager.class);
- mApnEditorUT.mProxySubscriptionMgr = proxySubscriptionMgr;
- doReturn(new Intent()).when(mActivity).getIntent();
- doNothing().when(mApnEditorUT).addPreferencesFromResource(anyInt());
-
- mApnEditorUT.onCreate(null);
-
- verify(mApnEditorUT).finish();
- }
-
- @Test
- public void testOnViewStateRestored_customizedValueWithoutDefault_shouldShowCustomized() {
- mApnEditorUT.mDefaultApnProtocol = "IP";
- mApnEditorUT.mApnData.mData[ApnEditor.PROTOCOL_INDEX] = null;
- mApnEditorUT.mProtocol.setEntryValues(new CharSequence[]{"IP", "IPV6", "IPV4V6"});
-
- mApnEditorUT.onViewStateRestored(null);
-
- assertThat(mApnEditorUT.mProtocol.getSummary()).isEqualTo("IPv4");
- }
-
- @Test
- public void testOnViewStateRestored_customizedValueWithDefault_shouldShowDefault() {
- mApnEditorUT.mDefaultApnProtocol = "IP";
- mApnEditorUT.mApnData.mData[ApnEditor.PROTOCOL_INDEX] = "IPV6";
- mApnEditorUT.mProtocol.setEntryValues(new CharSequence[]{"IP", "IPV6", "IPV4V6"});
-
- mApnEditorUT.onViewStateRestored(null);
-
- assertThat(mApnEditorUT.mProtocol.getSummary()).isEqualTo("IPv6");
- }
-
- @Test
- public void getUserEnteredApnType_emptyApnType_shouldReturnDefault() {
- // case 1
- // GIVEN read only APN types with DUN
- mApnEditorUT.mReadOnlyApnTypes = new String [] {"dun"};
- // GIVEN read specificApnTypeForEmptyInput with DEFAULT,DUN
- mApnEditorUT.mDefaultApnTypes = new String [] {"default", "dun"};
-
- // Input empty in TYPE
- mApnEditorUT.mApnData.mData[ApnEditor.TYPE_INDEX] = "";
- mApnEditorUT.onViewStateRestored(null);
-
- // THEN APN type should be default
- assertThat(mApnEditorUT.getUserEnteredApnType()).isEqualTo("default");
-
- // case 2
- // GIVEN read only APN types with DUN
- mApnEditorUT.mReadOnlyApnTypes = new String [] {"dun"};
- // GIVEN read specificApnTypeForEmptyInput with DEFAULT
- mApnEditorUT.mDefaultApnTypes = new String [] {"default"};
-
- // Input empty in TYPE
- mApnEditorUT.mApnData.mData[ApnEditor.TYPE_INDEX] = "";
- mApnEditorUT.onViewStateRestored(null);
-
- // THEN APN type should be default
- assertThat(mApnEditorUT.getUserEnteredApnType()).isEqualTo("default");
- }
-
- private void initCursor() {
- doReturn(2).when(mCursor).getColumnCount();
- doReturn(2).when(mCursor).getInt(CURSOR_INTEGER_INDEX);
- doReturn("str").when(mCursor).getString(CURSOR_STRING_INDEX);
- doReturn(Cursor.FIELD_TYPE_INTEGER).when(mCursor).getType(CURSOR_INTEGER_INDEX);
- doReturn(Cursor.FIELD_TYPE_STRING).when(mCursor).getType(CURSOR_STRING_INDEX);
- }
-
- private void setMockPreference(Context context) {
- mApnEditorUT.mName = new EditTextPreference(context);
- mApnEditorUT.mApn = new EditTextPreference(context);
- mApnEditorUT.mProxy = new EditTextPreference(context);
- mApnEditorUT.mPort = new EditTextPreference(context);
- mApnEditorUT.mUser = new EditTextPreference(context);
- mApnEditorUT.mServer = new EditTextPreference(context);
- mApnEditorUT.mPassword = new EditTextPreference(context);
- mApnEditorUT.mMmsc = new EditTextPreference(context);
- mApnEditorUT.mMcc = new EditTextPreference(context);
- mApnEditorUT.mMnc = new EditTextPreference(context);
- mApnEditorUT.mMmsProxy = new EditTextPreference(context);
- mApnEditorUT.mMmsPort = new EditTextPreference(context);
- mApnEditorUT.mAuthType = new ListPreference(context);
- mApnEditorUT.mApnType = new EditTextPreference(context);
- mApnEditorUT.mProtocol = new ListPreference(context);
- mApnEditorUT.mRoamingProtocol = new ListPreference(context);
- mApnEditorUT.mCarrierEnabled = new SwitchPreference(context);
- mApnEditorUT.mBearerMulti = new MultiSelectListPreference(context);
- mApnEditorUT.mMvnoType = new ListPreference(context);
- mApnEditorUT.mMvnoMatchData = new EditTextPreference(context);
- }
-
- private final class FakeApnData extends ApnData {
- FakeApnData(Object[] data) {
- super(data.length);
- System.arraycopy(data, 0, mData, 0, data.length);
- }
-
- FakeApnData(Object[] data, Uri uri) {
- this(data);
- mUri = uri;
- }
- }
-}