diff --git a/res/values/strings.xml b/res/values/strings.xml
index b62df6081ee..8c9045d8c10 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -33,9 +33,9 @@
Tap to show info
{count, plural,
- =1 {You are now # step away from being a developer.}
- other {You are now # steps away from being a developer.}
- }
+ =1 {You are now # step away from being a developer.}
+ other {You are now # steps away from being a developer.}
+ }
You are now a developer!
@@ -502,9 +502,9 @@
{count, plural,
- =1 {Remove selected language?}
- other {Remove selected languages?}
- }
+ =1 {Remove selected language?}
+ other {Remove selected languages?}
+ }
Text will be displayed in another language.
@@ -654,9 +654,9 @@
Off
{count, plural,
- =1 {On / # app has access to location}
- other {On / # apps have access to location}
- }
+ =1 {On / # app has access to location}
+ other {On / # apps have access to location}
+ }
Loading\u2026
@@ -845,9 +845,9 @@
Add fingerprint
{count, plural,
- =1 {Fingerprint added}
- other {# fingerprints added}
- }
+ =1 {Fingerprint added}
+ other {# fingerprints added}
+ }
Setup needed
@@ -1448,9 +1448,9 @@
Hide
Confirm your private space pattern
-
+
Re-enter your private space PIN
-
+
Re-enter your private space password
@@ -1686,21 +1686,21 @@
{count, plural,
- =1 {Must contain at least # character}
- other {Must be at least # characters}
- }
+ =1 {Must contain at least # character}
+ other {Must be at least # characters}
+ }
{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}
}
{count, plural,
- =1 {PIN must contain at least # digit}
- other {PIN must be at least # digits}
- }
+ =1 {PIN must contain at least # digit}
+ other {PIN must be at least # digits}
+ }
{count, plural,
@@ -1710,14 +1710,14 @@
{count, plural,
- =1 {Must be fewer than # character}
- other {Must be fewer than # characters}
- }
+ =1 {Must be fewer than # character}
+ other {Must be fewer than # characters}
+ }
{count, plural,
- =1 {Must be fewer than # digit}
- other {Must be fewer than # digits}
- }
+ =1 {Must be fewer than # digit}
+ other {Must be fewer than # digits}
+ }
Device admin doesn\'t allow using a recent PIN
@@ -1727,45 +1727,45 @@
{count, plural,
- =1 {Must contain at least 1 letter}
- other {Must contain at least # letters}
- }
+ =1 {Must contain at least 1 letter}
+ other {Must contain at least # letters}
+ }
{count, plural,
- =1 {Must contain at least 1 lowercase letter}
- other {Must contain at least # lowercase letters}
- }
+ =1 {Must contain at least 1 lowercase letter}
+ other {Must contain at least # lowercase letters}
+ }
{count, plural,
- =1 {Must contain at least 1 uppercase letter}
- other {Must contain at least # uppercase letters}
- }
+ =1 {Must contain at least 1 uppercase letter}
+ other {Must contain at least # uppercase letters}
+ }
{count, plural,
- =1 {Must contain at least 1 numerical digit}
- other {Must contain at least # numerical digits}
- }
+ =1 {Must contain at least 1 numerical digit}
+ other {Must contain at least # numerical digits}
+ }
{count, plural,
- =1 {Must contain at least 1 special symbol}
- other {Must contain at least # special symbols}
- }
+ =1 {Must contain at least 1 special symbol}
+ other {Must contain at least # special symbols}
+ }
{count, plural,
- =1 {Must contain at least 1 non-letter character}
- other {Must contain at least # non-letter characters}
- }
+ =1 {Must contain at least 1 non-letter character}
+ other {Must contain at least # non-letter characters}
+ }
{count, plural,
- =1 {Must contain at least 1 non-numerical character}
- other {Must contain at least # non-numerical characters}
- }
+ =1 {Must contain at least 1 non-numerical character}
+ other {Must contain at least # non-numerical characters}
+ }
Device admin doesn\'t allow using a recent
@@ -1801,9 +1801,9 @@
{count, plural,
- =1 {# active app}
- other {# active apps}
- }
+ =1 {# active app}
+ other {# active apps}
+ }
Trust agents
@@ -1816,9 +1816,9 @@
{count, plural,
- =1 {1 active trust agent}
- other {# active trust agents}
- }
+ =1 {1 active trust agent}
+ other {# active trust agents}
+ }
@@ -2412,19 +2412,19 @@
{count, plural,
- =1 {1 network}
- other {# networks}
- }
+ =1 {1 network}
+ other {# networks}
+ }
{count, plural,
- =1 {1 subscription}
- other {# subscriptions}
- }
+ =1 {1 subscription}
+ other {# subscriptions}
+ }
{count, plural,
- =1 {1 network & subscription}
- other {# networks & subscriptions}
- }
+ =1 {1 network & subscription}
+ other {# networks & subscriptions}
+ }
SSID
@@ -2998,11 +2998,11 @@
{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}
}
@@ -3153,9 +3153,9 @@
Incorrect SIM PIN code you must now contact your carrier to unlock your device.
{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.}
- }
+ =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.}
+ }
@@ -3324,27 +3324,27 @@
This ^1 is corrupted.
-\n\nTo use this ^1, you have to set it up first.
+ \n\nTo use this ^1, you have to set it up first.
You can format this SD card to store photos, videos, music,
and more and access them on other devices.
\n\nAll data on this SD card will be erased.
\n\nBefore formatting
-\n\nBack up photos & other media
-\nMove your media files to alternative storage on this device, or transfer them to a computer using a USB cable.
-\n\nBack up apps
-\nAll apps stored on this ^1 will be uninstalled and their data will be erased. To keep these apps, move them to alternative storage on this device.
+ \n\nBack up photos & other media
+ \nMove your media files to alternative storage on this device, or transfer them to a computer using a USB cable.
+ \n\nBack up apps
+ \nAll apps stored on this ^1 will be uninstalled and their data will be erased. To keep these apps, move them to alternative storage on this device.
When you eject this ^1, apps stored on it will stop working, and media files stored on it will not be available until it is reinserted.
-\n\nThis ^1 is formatted to work on this device only. It won\u2019t work on any others.
+ \n\nThis ^1 is formatted to work on this device only. It won\u2019t work on any others.
To use the apps, photos, or data this ^1 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.
+ \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.
Forget ^1?
@@ -3378,7 +3378,7 @@
Move ^1
Moving ^1 and its data to ^2 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 ^2 during the move.
+ \n\nDon\u2019t remove the ^2 during the move.
@@ -3388,7 +3388,7 @@
Moving ^1\u2026
Don\u2019t remove the ^1 during the move.
-\n\nThe ^2 app on this device won\u2019t be available until the move is complete.
+ \n\nThe ^2 app on this device won\u2019t be available until the move is complete.
@@ -3408,7 +3408,7 @@
Format this ^1?
This ^1 needs to be formatted to store apps, files, and media.
-\n\nFormatting will erase existing content on the ^2. To avoid losing content, back it up to another ^3 or device.
+ \n\nFormatting will erase existing content on the ^2. To avoid losing content, back it up to another ^3 or device.
This ^1 needs to be formatted to store photos, videos, music, and more.
\n\nFormatting will erase existing content on the ^2. To avoid losing content, back it up to another ^3 or device.
@@ -3437,8 +3437,8 @@
Slow ^1
You can still use this ^1, but it may be slow.
-\n\nApps stored on this ^2 may not work properly, and content transfers could take a long time.
-\n\nTry using a faster ^3, or use this ^4 for portable storage instead.
+ \n\nApps stored on this ^2 may not work properly, and content transfers could take a long time.
+ \n\nTry using a faster ^3, or use this ^4 for portable storage instead.
Start over
@@ -3753,9 +3753,9 @@
[CHAR LIMIT=NONE]-->
{count, plural,
- =1 {# of {total} apps has access to location}
- other {# of {total} apps have access to location}
- }
+ =1 {# of {total} apps has access to location}
+ other {# of {total} apps have access to location}
+ }
Recent access
@@ -4141,9 +4141,9 @@
Recently opened apps
{count, plural,
- =1 {See all apps}
- other {See all # apps}
- }
+ =1 {See all apps}
+ other {See all # apps}
+ }
Contact your IT admin
@@ -4174,9 +4174,9 @@
Cache
{count, plural,
- =1 {1 item}
- other {# items}
- }
+ =1 {1 item}
+ other {# items}
+ }
Clear access
@@ -4229,7 +4229,7 @@
Clear default preferences
This app may not be designed for your screen. You can control how it
- adjusts to your screen here.
+ adjusts to your screen here.
Ask when launched
@@ -4493,10 +4493,10 @@
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
- %1$s.
- Use this spell checker?
+ all the text you type, including personal data like passwords and credit
+ card numbers. It comes from the app
+ %1$s.
+ Use this spell checker?
Settings
@@ -5139,18 +5139,18 @@
To start and stop magnification, quickly tap the screen twice with %1$d fingers
{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.}
- }
+ =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.}
+ }
This shortcut will be available after you finish device setup.
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.
{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}
- }
+ =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}
+ }
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.
@@ -5183,9 +5183,9 @@
Tap the accessibility button %s at the bottom of your screen. To switch between features, touch & hold the accessibility button.
{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.}
- }
+ =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.}
+ }
More options
@@ -5194,14 +5194,14 @@
Quick Settings
{count, plural,
- =1 {Swipe down from the top of your screen}
- other {Swipe down with # fingers from the top of your screen}
- }
+ =1 {Swipe down from the top of your screen}
+ other {Swipe down with # fingers from the top of your screen}
+ }
{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.}
- }
+ =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.}
+ }
Quick Settings
@@ -5621,25 +5621,25 @@
{count, plural,
- =1 {Short ({time} second)}
- other {Short ({time} seconds)}
- }
+ =1 {Short ({time} second)}
+ other {Short ({time} seconds)}
+ }
{count, plural,
- =1 {Medium ({time} second)}
- other {Medium ({time} seconds)}
- }
+ =1 {Medium ({time} second)}
+ other {Medium ({time} seconds)}
+ }
{count, plural,
- =1 {Long ({time} second)}
- other {Long ({time} seconds)}
- }
+ =1 {Long ({time} second)}
+ other {Long ({time} seconds)}
+ }
{count, plural,
- =1 {{time} second}
- other {{time} seconds}
- }
+ =1 {{time} second}
+ other {{time} seconds}
+ }
Settings
@@ -5801,15 +5801,15 @@
Off
{count, plural,
- =1 {1 print service on}
- other {# print services on}
- }
+ =1 {1 print service on}
+ other {# print services on}
+ }
{count, plural,
- =1 {1 print job}
- other {# print jobs}
- }
+ =1 {1 print job}
+ other {# print jobs}
+ }
Print services
@@ -5894,7 +5894,7 @@
What has been using the battery
%1$s
- - %2$s
+ - %2$s
%1$s remaining
@@ -6012,30 +6012,30 @@
Includes high-power background activity
{count, plural,
- =1 {Restrict # app}
- other {Restrict # apps}
- }
+ =1 {Restrict # app}
+ other {Restrict # apps}
+ }
{count, plural,
- =1 {{label} recently restricted}
- other {# apps recently restricted}
- }
+ =1 {{label} recently restricted}
+ other {# apps recently restricted}
+ }
{count, plural,
- =1 {{label} has high background battery usage}
- other {# apps have high background battery usage}
- }
+ =1 {{label} has high background battery usage}
+ other {# apps have high background battery usage}
+ }
{count, plural,
- =1 {This app can\'t run in the background}
- other {These apps can\'t run in the background}
- }
+ =1 {This app can\'t run in the background}
+ other {These apps can\'t run in the background}
+ }
{count, plural,
- =1 {Restrict app?}
- other {Restrict # apps?}
- }
+ =1 {Restrict app?}
+ other {Restrict # apps?}
+ }
To save battery, stop %1$s from using battery in the background. This app may not work properly and notifications may be delayed.
@@ -6069,9 +6069,9 @@
Restricted apps
{count, plural,
- =1 {Limiting battery usage for # app}
- other {Limiting battery usage for # apps}
- }
+ =1 {Limiting battery usage for # app}
+ other {Limiting battery usage for # apps}
+ }
Restricted %1$s
@@ -6091,9 +6091,9 @@
{count, plural,
- =1 {# app restricted}
- other {# apps restricted}
- }
+ =1 {# app restricted}
+ other {# apps restricted}
+ }
Problem reading the battery meter.
@@ -6581,9 +6581,9 @@
This app won\u2019t manage certificates, but it will stay on your device. Any certificates installed by the app will be uninstalled.
{count, plural,
- =1 {# URL}
- other {# URLs}
- }
+ =1 {# URL}
+ other {# URLs}
+ }
Emergency dialing signal
@@ -6685,9 +6685,9 @@
{count, plural,
- =1 {# notification}
- other {# notifications}
- }
+ =1 {# notification}
+ other {# notifications}
+ }
@@ -7108,9 +7108,9 @@
Done
{count, plural,
- =1 {Trust or remove certificate}
- other {Trust or remove certificates}
- }
+ =1 {Trust or remove certificate}
+ other {Trust or remove certificates}
+ }
{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 @@
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.
{count, plural,
- =1 {Check certificate}
- other {Check certificates}
- }
+ =1 {Check certificate}
+ other {Check certificates}
+ }
Users
@@ -8085,9 +8085,9 @@
{count, plural,
- =0 {None}
- =1 {1 schedule set}
- other {# schedules set}
+ =0 {None}
+ =1 {1 schedule set}
+ other {# schedules set}
}
@@ -8123,20 +8123,20 @@
{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}
}
{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}
}
@@ -8437,25 +8437,25 @@
{count, plural,
- =1 {1 hour}
- other {# hours}
+ =1 {1 hour}
+ other {# hours}
}
{count, plural,
- =1 {1 minute}
- other {# minutes}
+ =1 {1 minute}
+ other {# minutes}
}
{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}
}
@@ -8798,9 +8798,9 @@
{count, plural,
- =1 {# priority conversation}
- other {# priority conversations}
- }
+ =1 {# priority conversation}
+ other {# priority conversations}
+ }
Priority conversations
@@ -8897,13 +8897,13 @@
{count, plural,
- =1 {About # notification per day}
- other {About # notifications per day}
- }
+ =1 {About # notification per day}
+ other {About # notifications per day}
+ }
{count, plural,
- =1 {About # notification per week}
- other {About # notifications per week}
- }
+ =1 {About # notification per week}
+ other {About # notifications per week}
+ }
Never
@@ -8943,7 +8943,7 @@
Allow notification access for
- %1$s?
+ %1$s?
@@ -9007,7 +9007,7 @@
Allow VR service access for
- %1$s?
+ %1$s?
@@ -9114,9 +9114,9 @@
{count, plural,
- =1 {# app connected}
- other {# apps connected}
- }
+ =1 {# app connected}
+ other {# apps connected}
+ }
{count, plural,
- =1 {# category deleted}
- other {# categories deleted}
- }
+ =1 {# category deleted}
+ other {# categories deleted}
+ }
Block all
@@ -9351,9 +9351,9 @@
{count, plural,
- =0 {None}
- =1 {1 conversation}
- other {# conversations}
+ =0 {None}
+ =1 {1 conversation}
+ other {# conversations}
}
@@ -9385,11 +9385,11 @@
{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}
}
@@ -9416,9 +9416,9 @@
{count, plural,
- =0 {None}
- =1 {1 contact}
- other {# contacts}
+ =0 {None}
+ =1 {1 contact}
+ other {# contacts}
}
@@ -9494,11 +9494,11 @@
{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}
}
@@ -9533,11 +9533,11 @@
{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}
}
@@ -9551,11 +9551,11 @@
{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}
}
@@ -9599,14 +9599,14 @@
Change to alarms only indefinitely
{count, plural,
- =1 {Change to alarms only for one minute until {time}}
- other {Change to alarms only for # minutes (until {time})}
- }
+ =1 {Change to alarms only for one minute until {time}}
+ other {Change to alarms only for # minutes (until {time})}
+ }
{count, plural,
- =1 {Change to alarms only for one hour until {time}}
- other {Change to alarms only for # hours until {time}}
- }
+ =1 {Change to alarms only for one hour until {time}}
+ other {Change to alarms only for # hours until {time}}
+ }
Change to alarms only until %1$s
@@ -9828,13 +9828,13 @@
{count, plural,
- =1 {# verified link}
- other {# verified links}
- }
+ =1 {# verified link}
+ other {# verified links}
+ }
{count, plural,
- =1 {This link is verified and automatically opens in this app.}
- other {These links are verified and automatically open in this app.}
- }
+ =1 {This link is verified and automatically opens in this app.}
+ other {These links are verified and automatically open in this app.}
+ }
OK
@@ -9847,9 +9847,9 @@
{count, plural,
- =1 {# supported link}
- other {# supported links}
- }
+ =1 {# supported link}
+ other {# supported links}
+ }
Add
@@ -9885,15 +9885,15 @@
{count, plural,
- =1 {# category turned off}
- other {# categories turned off}
- }
+ =1 {# category turned off}
+ other {# categories turned off}
+ }
{count, plural,
- =1 {# additional permission}
- other {# additional permissions}
- }
+ =1 {# additional permission}
+ other {# additional permissions}
+ }
No permissions granted
@@ -9915,9 +9915,9 @@
{count, plural,
- =1 {# unused app}
- other {# unused apps}
- }
+ =1 {# unused app}
+ other {# unused apps}
+ }
Unused app settings
@@ -9985,9 +9985,9 @@
{count, plural,
- =1 {App claims to handle # link}
- other {App claims to handle # links}
- }
+ =1 {App claims to handle # link}
+ other {App claims to handle # links}
+ }
App claims to handle following links:
@@ -10257,9 +10257,9 @@
{count, plural,
- =1 {1 app used memory in the last {time}}
- other {# apps used memory in the last {time}}
- }
+ =1 {1 app used memory in the last {time}}
+ other {# apps used memory in the last {time}}
+ }
Enable memory usage profiling
@@ -10685,9 +10685,9 @@
{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}
- }
+ =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}
+ }
Primary data
@@ -10712,9 +10712,9 @@
{count, plural,
- =1 {# day left}
- other {# days left}
- }
+ =1 {# day left}
+ other {# days left}
+ }
No time remaining
@@ -11291,9 +11291,9 @@
Number of apps is estimated. It may not include apps installed outside of the Play Store.
{count, plural,
- =1 {Minimum # app}
- other {Minimum # apps}
- }
+ =1 {Minimum # app}
+ other {Minimum # apps}
+ }
Location permissions
@@ -11304,9 +11304,9 @@
Default apps
{count, plural,
- =1 {# app}
- other {# apps}
- }
+ =1 {# app}
+ other {# apps}
+ }
Default keyboard
@@ -11327,9 +11327,9 @@
Trusted credentials in your work profile
{count, plural,
- =1 {Minimum # CA certificate}
- other {Minimum # CA certificates}
- }
+ =1 {Minimum # CA certificate}
+ other {Minimum # CA certificates}
+ }
Admin can lock the device and reset password
@@ -11340,9 +11340,9 @@
Failed password attempts before deleting work profile data
{count, plural,
- =1 {# attempt}
- other {# attempts}
- }
+ =1 {# attempt}
+ other {# attempts}
+ }
This device is managed by your organization.
@@ -11405,25 +11405,25 @@
{count, plural,
- =1 {Camera app}
- other {Camera apps}
- }
+ =1 {Camera app}
+ other {Camera apps}
+ }
Calendar app
Contacts app
{count, plural,
- =1 {Email client app}
- other {Email client apps}
- }
+ =1 {Email client app}
+ other {Email client apps}
+ }
Map app
{count, plural,
- =1 {Phone app}
- other {Phone apps}
- }
+ =1 {Phone app}
+ other {Phone apps}
+ }
%1$s, %2$s
@@ -11518,9 +11518,9 @@
{count, plural,
- =1 {# password}
- other {# passwords}
- }
+ =1 {# password}
+ other {# passwords}
+ }
\u2014
@@ -12379,10 +12379,10 @@
Choose a SIM to use
{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}
- }
+ =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}
+ }
Turning on…
@@ -12513,9 +12513,9 @@
{count, plural,
- =1 {1 app has full access to your device}
- other {# apps have full access to your device}
- }
+ =1 {1 app has full access to your device}
+ other {# apps have full access to your device}
+ }
Important information
@@ -13268,9 +13268,9 @@
{count, plural,
- =1 {# app}
- other {# apps}
- }
+ =1 {# app}
+ other {# apps}
+ }
Apps installed in the background
@@ -13282,14 +13282,14 @@
Uninstall app
{count, plural,
- =1 {Apps installed in the last # month}
- other {Apps installed in the last # months}
- }
+ =1 {Apps installed in the last # month}
+ other {Apps installed in the last # months}
+ }
{count, plural,
- =1 {Apps installed more than # month ago}
- other {Apps installed more than # months ago}
- }
+ =1 {Apps installed more than # month ago}
+ other {Apps installed more than # months ago}
+ }
@@ -13482,11 +13482,11 @@
Show pointer while hovering
-
+
Media DRM settings
-
+
Force Software Secure Crypto
-
+
Force DRM key management to use software-based whitebox crypto
@@ -13729,8 +13729,12 @@
New contacts won\'t be synced with an account
Contacts will be saved to your device and synced to your account by default
+
+ Error setting the default account
- No default set
+ No default set
+
+ Device only
Add an account to get started
diff --git a/src/com/android/settings/applications/contacts/ContactsStoragePreferenceController.java b/src/com/android/settings/applications/contacts/ContactsStoragePreferenceController.java
index bc6931de466..6c179da9325 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 @@ public class ContactsStoragePreferenceController extends BasePreferenceControlle
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 90d593a0c7e..3d449cf63c0 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.search.SearchIndexable;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -59,7 +61,7 @@ public class ContactsStorageSettings extends DashboardFragment
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 mAccountMap = new HashMap<>();
+ private final Map mAccountMap = new HashMap<>();
private AuthenticatorHelper mAuthenticatorHelper;
@Override
@@ -73,13 +75,18 @@ public class ContactsStorageSettings extends DashboardFragment
@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 class ContactsStorageSettings extends DashboardFragment
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 @@ public class ContactsStorageSettings extends DashboardFragment
@Override
public void onCreatePreferences(@NonNull Bundle savedInstanceState,
- @NonNull String rootKey) {
+ @NonNull String rootKey) {
super.onCreatePreferences(savedInstanceState, rootKey);
refreshUI();
}
@@ -119,48 +123,60 @@ public class ContactsStorageSettings extends DashboardFragment
// 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 accounts = DefaultAccount.getEligibleCloudAccounts(getContentResolver());
+ for (int i = 0; i < accounts.size(); i++) {
+ screen.addPreference(buildAccountPreference(accounts.get(i), /*order=*/i));
+ }
+ // 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()));
}
- screen.addPreference(buildAddAccountPreference(accounts.length == 0));
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 @@ public class ContactsStorageSettings extends DashboardFragment
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/tests/robotests/src/com/android/settings/applications/contacts/ContactsStoragePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/contacts/ContactsStoragePreferenceControllerTest.java
index a934cba9a3c..f55cbb44f72 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.anyInt;
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 @@ public class ContactsStoragePreferenceControllerTest {
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();
@@ -83,6 +80,9 @@ public class ContactsStoragePreferenceControllerTest {
@Mock
private ContentResolver mContentResolver;
+ @Mock
+ private ContentProviderClient mContentProviderClient;
+
@Mock
private Resources mResources;
@@ -94,9 +94,15 @@ public class ContactsStoragePreferenceControllerTest {
@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 @@ public class ContactsStoragePreferenceControllerTest {
@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 @@ public class ContactsStoragePreferenceControllerTest {
@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 785ef4a9d11..a8c86e1e176 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 static org.mockito.Mockito.when;
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.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import java.util.ArrayList;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
@@ -76,6 +81,8 @@ public class ContactsStorageSettingsTest {
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 @@ public class ContactsStorageSettingsTest {
@Mock
private ContentResolver mContentResolver;
@Mock
- private AccountManager mAccountManager;
-
+ private ContentProviderClient mContentProviderClient;
private PreferenceManager mPreferenceManager;
private TestContactsStorageSettings mContactsStorageSettings;
private PreferenceScreen mScreen;
@@ -92,8 +98,8 @@ public class ContactsStorageSettingsTest {
@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 @@ public class ContactsStorageSettingsTest {
}
@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 @@ public class ContactsStorageSettingsTest {
assertThat(deviceOnlyPreference.isChecked()).isTrue();
ArgumentCaptor 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 @@ public class ContactsStorageSettingsTest {
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 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 @@ public class ContactsStorageSettingsTest {
assertThat(account2Preference.isChecked()).isTrue();
ArgumentCaptor 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");
@@ -206,6 +255,49 @@ public class ContactsStorageSettingsTest {
"type2");
}
+ @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 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 indexRes =
@@ -220,6 +312,7 @@ public class ContactsStorageSettingsTest {
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 @@ public class ContactsStorageSettingsTest {
// 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;
+ }
}
}