diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 64aa8ee844239..560cfe6f7a116 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -164,21 +164,21 @@
Displayed in a dialog box. -->
Incorrect SIM PIN code you must now contact your carrier to unlock your device.
-
- - Incorrect SIM PIN code, you have %d remaining attempt before you must contact your carrier to unlock your device.
- - Incorrect SIM PIN code, you have %d remaining attempts.
-
+ to unlock the keyguard. Displayed in a dialog box. [CHAR LIMIT=NONE] -->
+ {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. }
+ }
SIM is unusable. Contact your carrier.
-
- - Incorrect SIM PUK code, you have %d remaining attempt before SIM becomes permanently unusable.
- - Incorrect SIM PUK code, you have %d remaining attempts before SIM becomes permanently unusable.
-
+ to unlock the keyguard. Displayed in a dialog box. [CHAR LIMIT=NONE] -->
+ {count, plural,
+ =1 {Incorrect SIM PUK code, you have # remaining attempt before SIM becomes permanently unusable.}
+ other {Incorrect SIM PUK code, you have # remaining attempts before SIM becomes permanently unusable.}
+ }
SIM PIN operation failed!
@@ -223,21 +223,17 @@
To use Face Unlock, turn on Camera access in Settings > Privacy
-
-
- - Enter SIM PIN. You have %d remaining
-attempt before you must contact your carrier to unlock your device.
- - Enter SIM PIN. You have %d remaining
-attempts.
-
+
+ {count, plural,
+ =1 {Enter SIM PIN. You have # remaining attempt before you must contact your carrier to unlock your device.}
+ other {Enter SIM PIN. You have # remaining attempts.}
+ }
-
-
- - SIM is now disabled. Enter PUK code to continue. You have %d remaining attempt before SIM becomes permanently unusable. Contact carrier for details.
- - SIM is now disabled. Enter PUK code to continue. You have %d remaining attempts before SIM becomes permanently unusable. Contact carrier for details.
-
+
+ {count, plural,
+ =1 {SIM is now disabled. Enter PUK code to continue. You have # remaining attempt before SIM becomes permanently unusable. Contact carrier for details.}
+ other {SIM is now disabled. Enter PUK code to continue. You have # remaining attempts before SIM becomes permanently unusable. Contact carrier for details.}
+ }
Default
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 2b33009498ab5..6cd47d24db4ed 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -505,10 +505,10 @@
+ %s
-
- - %s more notification inside.
- - %s more notifications inside.
-
+ {count, plural,
+ =1 {# more notification inside.}
+ other {# more notifications inside.}
+ }
@@ -654,10 +654,10 @@
the user why they can't toggle the hotspot tile. [CHAR LIMIT=20] -->
Data Saver is on
-
- - %d device
- - %d devices
-
+ {count, plural,
+ =1 {# device}
+ other {# devices}
+ }
Flashlight
@@ -928,10 +928,10 @@
User limit reached
-
- - Only one user can be created.
- - You can add up to %d users.
-
+ {count, plural,
+ =1 {Only one user can be created.}
+ other {You can add up to # users.}
+ }
Remove user?
@@ -1486,20 +1486,20 @@
Snoozed for %1$s
-
-
- - %d hour
- - %d hours
- - %d hours
- - %d hours
-
+
+ {count, plural,
+ =1 {# hour}
+ =2 {# hours}
+ few {# hours}
+ other {# hours}
+ }
-
-
- - %d minute
- - %d minutes
- - %d minutes
-
+
+ {count, plural,
+ =1 {# minute}
+ few {# minutes}
+ other {# minutes}
+ }
@@ -2136,10 +2136,10 @@
Choose app to add controls
-
- - %s control added.
- - %s controls added.
-
+ {count, plural,
+ =1 {# control added.}
+ other {# controls added.}
+ }
Removed
@@ -2495,10 +2495,10 @@
Select user
-
- - %s app is active
- - %s apps are active
-
+ {count, plural,
+ =1 {# app is active}
+ other {# apps are active}
+ }
New information
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index 47df70b522f73..2f6fa145664ef 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -16,6 +16,8 @@
package com.android.keyguard;
+import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
+
import android.annotation.NonNull;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
@@ -241,10 +243,9 @@ public class KeyguardSimPinViewController
displayMessage = mView.getResources().getString(
R.string.kg_password_wrong_pin_code_pukked);
} else if (attemptsRemaining > 0) {
- msgId = isDefault ? R.plurals.kg_password_default_pin_message :
- R.plurals.kg_password_wrong_pin_code;
- displayMessage = mView.getResources()
- .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
+ msgId = isDefault ? R.string.kg_password_default_pin_message :
+ R.string.kg_password_wrong_pin_code;
+ displayMessage = icuMessageFormat(mView.getResources(), msgId, attemptsRemaining);
} else {
msgId = isDefault ? R.string.kg_sim_pin_instructions : R.string.kg_password_pin_failed;
displayMessage = mView.getResources().getString(msgId);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index 760c2ccb71b59..c0971bf8c16de 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -16,6 +16,8 @@
package com.android.keyguard;
+import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
+
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
@@ -57,10 +59,9 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
if (attemptsRemaining == 0) {
displayMessage = getContext().getString(R.string.kg_password_wrong_puk_code_dead);
} else if (attemptsRemaining > 0) {
- int msgId = isDefault ? R.plurals.kg_password_default_puk_message :
- R.plurals.kg_password_wrong_puk_code;
- displayMessage = getContext().getResources()
- .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
+ int msgId = isDefault ? R.string.kg_password_default_puk_message :
+ R.string.kg_password_wrong_puk_code;
+ displayMessage = icuMessageFormat(getResources(), msgId, attemptsRemaining);
} else {
int msgId = isDefault ? R.string.kg_puk_enter_puk_hint :
R.string.kg_password_puk_failed;
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
index 0bc6579739dba..a174ed0312c83 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
@@ -28,6 +28,7 @@ import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.R
import com.android.systemui.controls.ControlsServiceInfo
+import com.android.systemui.util.icuMessageFormat
import java.text.Collator
import java.util.concurrent.Executor
@@ -74,8 +75,10 @@ class AppAdapter(
}
override fun onCreateViewHolder(parent: ViewGroup, i: Int): Holder {
- return Holder(layoutInflater.inflate(R.layout.controls_app_item, parent, false),
- favoritesRenderer)
+ return Holder(
+ layoutInflater.inflate(R.layout.controls_app_item, parent, false),
+ favoritesRenderer
+ )
}
override fun getItemCount() = listOfServices.size
@@ -116,10 +119,10 @@ class FavoritesRenderer(
fun renderFavoritesForComponent(component: ComponentName): String? {
val qty = favoriteFunction(component)
- if (qty != 0) {
- return resources.getQuantityString(R.plurals.controls_number_of_favorites, qty, qty)
+ return if (qty != 0) {
+ icuMessageFormat(resources, R.string.controls_number_of_favorites, qty)
} else {
- return null
+ null
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
index ba6b1dd28c97d..875493d73f9eb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
@@ -17,6 +17,7 @@
package com.android.systemui.qs;
import static com.android.systemui.qs.dagger.QSFragmentModule.QS_FGS_MANAGER_FOOTER_VIEW;
+import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
import android.content.Context;
import android.view.View;
@@ -141,8 +142,8 @@ public class QSFgsManagerFooter implements View.OnClickListener,
public void handleRefreshState() {
mMainExecutor.execute(() -> {
- CharSequence text = mContext.getResources().getQuantityString(
- R.plurals.fgs_manager_footer_label, mNumPackages, mNumPackages);
+ CharSequence text = icuMessageFormat(mContext.getResources(),
+ R.string.fgs_manager_footer_label, mNumPackages);
mFooterText.setText(text);
mNumberView.setText(Integer.toString(mNumPackages));
mNumberView.setContentDescription(text);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index da5202bc3645d..9a0d0d9656caf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
+
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -182,10 +184,8 @@ public class BluetoothTile extends QSTileImpl {
List connectedDevices = mController.getConnectedDevices();
if (enabled && connected && !connectedDevices.isEmpty()) {
if (connectedDevices.size() > 1) {
- // TODO(b/76102598): add a new string for "X connected devices" after P
- return mContext.getResources().getQuantityString(
- R.plurals.quick_settings_hotspot_secondary_label_num_devices,
- connectedDevices.size(),
+ return icuMessageFormat(mContext.getResources(),
+ R.string.quick_settings_hotspot_secondary_label_num_devices,
connectedDevices.size());
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 7c8e77b5d9931..b6f6e933bf84d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
+
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
@@ -186,9 +188,8 @@ public class HotspotTile extends QSTileImpl {
return mContext.getString(
R.string.quick_settings_hotspot_secondary_label_data_saver_enabled);
} else if (numConnectedDevices > 0 && isActive) {
- return mContext.getResources().getQuantityString(
- R.plurals.quick_settings_hotspot_secondary_label_num_devices,
- numConnectedDevices,
+ return icuMessageFormat(mContext.getResources(),
+ R.string.quick_settings_hotspot_secondary_label_num_devices,
numConnectedDevices);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
index 56f8e087d64dc..40a44ffd7fe3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridGroupManager.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.row;
+import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
+
import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
@@ -136,8 +138,8 @@ public class HybridGroupManager {
if (!text.equals(reusableView.getText())) {
reusableView.setText(text);
}
- String contentDescription = String.format(mContext.getResources().getQuantityString(
- R.plurals.notification_group_overflow_description, number), number);
+ String contentDescription = icuMessageFormat(mContext.getResources(),
+ R.string.notification_group_overflow_description, number);
reusableView.setContentDescription(contentDescription);
reusableView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mOverflowNumberSize);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
index 7269f55451639..512b049681664 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.row;
+import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -243,11 +245,11 @@ public class NotificationSnooze extends LinearLayout
private SnoozeOption createOption(int minutes, int accessibilityActionId) {
Resources res = getResources();
boolean showInHours = minutes >= 60;
- int pluralResId = showInHours
- ? R.plurals.snoozeHourOptions
- : R.plurals.snoozeMinuteOptions;
+ int stringResId = showInHours
+ ? R.string.snoozeHourOptions
+ : R.string.snoozeMinuteOptions;
int count = showInHours ? (minutes / 60) : minutes;
- String description = res.getQuantityString(pluralResId, count, count);
+ String description = icuMessageFormat(res, stringResId, count);
String resultText = String.format(res.getString(R.string.snoozed_for_time), description);
AccessibilityAction action = new AccessibilityAction(accessibilityActionId, description);
final int index = resultText.indexOf(description);
diff --git a/packages/SystemUI/src/com/android/systemui/util/PluralMessageFormater.kt b/packages/SystemUI/src/com/android/systemui/util/PluralMessageFormater.kt
new file mode 100644
index 0000000000000..83b471dff4b16
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/PluralMessageFormater.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 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.systemui.util
+
+import android.annotation.StringRes
+import android.content.res.Resources
+import android.util.PluralsMessageFormatter
+
+/**
+ * Utility method that provides the localized plural string for the given [messageId]
+ * using the [count] parameter.
+ */
+fun icuMessageFormat(res: Resources, @StringRes messageId: Int, count: Int): String {
+ return PluralsMessageFormatter.format(res, mapOf("count" to count), messageId)
+}