Merge "Create plumbing for disabling force-dark"
diff --git a/Android.bp b/Android.bp
index 415eff3..a603006 100644
--- a/Android.bp
+++ b/Android.bp
@@ -151,8 +151,8 @@
":libcamera_client_framework_aidl",
"core/java/android/hardware/IConsumerIrService.aidl",
"core/java/android/hardware/ISerialManager.aidl",
- "core/java/android/hardware/biometrics/IBiometricPromptService.aidl",
- "core/java/android/hardware/biometrics/IBiometricPromptServiceReceiver.aidl",
+ "core/java/android/hardware/biometrics/IBiometricService.aidl",
+ "core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl",
"core/java/android/hardware/biometrics/IBiometricPromptReceiver.aidl",
"core/java/android/hardware/biometrics/IBiometricServiceLockoutResetCallback.aidl",
"core/java/android/hardware/display/IDisplayManager.aidl",
diff --git a/api/current.txt b/api/current.txt
index 3beb491..63555b9 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -9527,6 +9527,7 @@
field public static final int BIND_IMPORTANT = 64; // 0x40
field public static final int BIND_NOT_FOREGROUND = 4; // 0x4
field public static final int BIND_WAIVE_PRIORITY = 32; // 0x20
+ field public static final java.lang.String BIOMETRIC_SERVICE = "biometric";
field public static final java.lang.String BLUETOOTH_SERVICE = "bluetooth";
field public static final java.lang.String CAMERA_SERVICE = "camera";
field public static final java.lang.String CAPTIONING_SERVICE = "captioning";
@@ -15934,6 +15935,10 @@
package android.hardware.biometrics {
+ public class BiometricManager {
+ method public boolean hasEnrolledBiometrics();
+ }
+
public class BiometricPrompt {
method public void authenticate(android.hardware.biometrics.BiometricPrompt.CryptoObject, android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.biometrics.BiometricPrompt.AuthenticationCallback);
method public void authenticate(android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.biometrics.BiometricPrompt.AuthenticationCallback);
@@ -18639,6 +18644,114 @@
method public java.lang.CharSequence getName();
}
+ public class Bidi {
+ ctor public Bidi();
+ ctor public Bidi(int, int);
+ ctor public Bidi(java.lang.String, int);
+ ctor public Bidi(java.text.AttributedCharacterIterator);
+ ctor public Bidi(char[], int, byte[], int, int, int);
+ method public boolean baseIsLeftToRight();
+ method public int countParagraphs();
+ method public int countRuns();
+ method public android.icu.text.Bidi createLineBidi(int, int);
+ method public static byte getBaseDirection(java.lang.CharSequence);
+ method public int getBaseLevel();
+ method public android.icu.text.BidiClassifier getCustomClassifier();
+ method public int getCustomizedClass(int);
+ method public byte getDirection();
+ method public int getLength();
+ method public byte getLevelAt(int);
+ method public byte[] getLevels();
+ method public int getLogicalIndex(int);
+ method public int[] getLogicalMap();
+ method public android.icu.text.BidiRun getLogicalRun(int);
+ method public byte getParaLevel();
+ method public android.icu.text.BidiRun getParagraph(int);
+ method public android.icu.text.BidiRun getParagraphByIndex(int);
+ method public int getParagraphIndex(int);
+ method public int getProcessedLength();
+ method public int getReorderingMode();
+ method public int getReorderingOptions();
+ method public int getResultLength();
+ method public int getRunCount();
+ method public int getRunLevel(int);
+ method public int getRunLimit(int);
+ method public int getRunStart(int);
+ method public char[] getText();
+ method public java.lang.String getTextAsString();
+ method public int getVisualIndex(int);
+ method public int[] getVisualMap();
+ method public android.icu.text.BidiRun getVisualRun(int);
+ method public static int[] invertMap(int[]);
+ method public boolean isInverse();
+ method public boolean isLeftToRight();
+ method public boolean isMixed();
+ method public boolean isOrderParagraphsLTR();
+ method public boolean isRightToLeft();
+ method public void orderParagraphsLTR(boolean);
+ method public static int[] reorderLogical(byte[]);
+ method public static int[] reorderVisual(byte[]);
+ method public static void reorderVisually(byte[], int, java.lang.Object[], int, int);
+ method public static boolean requiresBidi(char[], int, int);
+ method public void setContext(java.lang.String, java.lang.String);
+ method public void setCustomClassifier(android.icu.text.BidiClassifier);
+ method public void setInverse(boolean);
+ method public android.icu.text.Bidi setLine(int, int);
+ method public void setPara(java.lang.String, byte, byte[]);
+ method public void setPara(char[], byte, byte[]);
+ method public void setPara(java.text.AttributedCharacterIterator);
+ method public void setReorderingMode(int);
+ method public void setReorderingOptions(int);
+ method public java.lang.String writeReordered(int);
+ method public static java.lang.String writeReverse(java.lang.String, int);
+ field public static final int DIRECTION_DEFAULT_LEFT_TO_RIGHT = 126; // 0x7e
+ field public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = 127; // 0x7f
+ field public static final int DIRECTION_LEFT_TO_RIGHT = 0; // 0x0
+ field public static final int DIRECTION_RIGHT_TO_LEFT = 1; // 0x1
+ field public static final short DO_MIRRORING = 2; // 0x2
+ field public static final short INSERT_LRM_FOR_NUMERIC = 4; // 0x4
+ field public static final short KEEP_BASE_COMBINING = 1; // 0x1
+ field public static final byte LEVEL_DEFAULT_LTR = 126; // 0x7e
+ field public static final byte LEVEL_DEFAULT_RTL = 127; // 0x7f
+ field public static final byte LEVEL_OVERRIDE = -128; // 0xffffff80
+ field public static final byte LTR = 0; // 0x0
+ field public static final int MAP_NOWHERE = -1; // 0xffffffff
+ field public static final byte MAX_EXPLICIT_LEVEL = 125; // 0x7d
+ field public static final byte MIXED = 2; // 0x2
+ field public static final byte NEUTRAL = 3; // 0x3
+ field public static final int OPTION_DEFAULT = 0; // 0x0
+ field public static final int OPTION_INSERT_MARKS = 1; // 0x1
+ field public static final int OPTION_REMOVE_CONTROLS = 2; // 0x2
+ field public static final int OPTION_STREAMING = 4; // 0x4
+ field public static final short OUTPUT_REVERSE = 16; // 0x10
+ field public static final short REMOVE_BIDI_CONTROLS = 8; // 0x8
+ field public static final short REORDER_DEFAULT = 0; // 0x0
+ field public static final short REORDER_GROUP_NUMBERS_WITH_R = 2; // 0x2
+ field public static final short REORDER_INVERSE_FOR_NUMBERS_SPECIAL = 6; // 0x6
+ field public static final short REORDER_INVERSE_LIKE_DIRECT = 5; // 0x5
+ field public static final short REORDER_INVERSE_NUMBERS_AS_L = 4; // 0x4
+ field public static final short REORDER_NUMBERS_SPECIAL = 1; // 0x1
+ field public static final short REORDER_RUNS_ONLY = 3; // 0x3
+ field public static final byte RTL = 1; // 0x1
+ }
+
+ public class BidiClassifier {
+ ctor public BidiClassifier(java.lang.Object);
+ method public int classify(int);
+ method public java.lang.Object getContext();
+ method public void setContext(java.lang.Object);
+ }
+
+ public class BidiRun {
+ method public byte getDirection();
+ method public byte getEmbeddingLevel();
+ method public int getLength();
+ method public int getLimit();
+ method public int getStart();
+ method public boolean isEvenRun();
+ method public boolean isOddRun();
+ }
+
public abstract class BreakIterator implements java.lang.Cloneable {
ctor protected BreakIterator();
method public java.lang.Object clone();
@@ -27145,6 +27258,7 @@
method public android.net.Network[] getAllNetworks();
method public deprecated boolean getBackgroundDataSetting();
method public android.net.Network getBoundNetworkForProcess();
+ method public int getConnectionOwnerUid(int, java.net.InetSocketAddress, java.net.InetSocketAddress);
method public android.net.ProxyInfo getDefaultProxy();
method public android.net.LinkProperties getLinkProperties(android.net.Network);
method public int getMultipathPreference(android.net.Network);
@@ -33292,6 +33406,7 @@
method public static final void setThreadPriority(int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
method public static final deprecated boolean supportsProcesses();
field public static final int FIRST_APPLICATION_UID = 10000; // 0x2710
+ field public static final int INVALID_UID = -1; // 0xffffffff
field public static final int LAST_APPLICATION_UID = 19999; // 0x4e1f
field public static final int PHONE_UID = 1001; // 0x3e9
field public static final int SIGNAL_KILL = 9; // 0x9
@@ -41851,6 +41966,7 @@
field public static final java.lang.String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE";
field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
+ field public static final java.lang.String EXTRA_CALL_NETWORK_TYPE = "android.telecom.extra.CALL_NETWORK_TYPE";
field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
field public static final java.lang.String EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME = "android.telecom.extra.CHANGE_DEFAULT_DIALER_PACKAGE_NAME";
field public static final java.lang.String EXTRA_INCOMING_CALL_ADDRESS = "android.telecom.extra.INCOMING_CALL_ADDRESS";
diff --git a/api/system-current.txt b/api/system-current.txt
index 8f7606a..0038afb 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4305,6 +4305,13 @@
field public static final java.lang.String STATE = "state";
}
+ public static final class ContactsContract.RawContacts implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.RawContactsColumns android.provider.ContactsContract.SyncColumns {
+ field public static final android.net.Uri RAW_CONTACTS_NOTIFICATION_DELETE_URI;
+ field public static final android.net.Uri RAW_CONTACTS_NOTIFICATION_INSERT_URI;
+ field public static final android.net.Uri RAW_CONTACTS_NOTIFICATION_UPDATE_URI;
+ field public static final android.net.Uri RAW_CONTACTS_NOTIFICATION_URI;
+ }
+
public abstract class SearchIndexableData {
ctor public SearchIndexableData();
ctor public SearchIndexableData(android.content.Context);
diff --git a/api/test-current.txt b/api/test-current.txt
index e22f516..f4d7cbc 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -932,6 +932,13 @@
field public static final android.net.Uri ENTERPRISE_CONTENT_URI;
}
+ public static final class ContactsContract.RawContacts implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.RawContactsColumns android.provider.ContactsContract.SyncColumns {
+ field public static final android.net.Uri RAW_CONTACTS_NOTIFICATION_DELETE_URI;
+ field public static final android.net.Uri RAW_CONTACTS_NOTIFICATION_INSERT_URI;
+ field public static final android.net.Uri RAW_CONTACTS_NOTIFICATION_UPDATE_URI;
+ field public static final android.net.Uri RAW_CONTACTS_NOTIFICATION_URI;
+ }
+
public static final class ContactsContract.RawContactsEntity implements android.provider.BaseColumns android.provider.ContactsContract.DataColumns android.provider.ContactsContract.RawContactsColumns {
field public static final android.net.Uri CORP_CONTENT_URI;
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index c6c10ec..485b91f 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -175,8 +175,9 @@
ProcStats proc_stats = 10029;
}
- // DO NOT USE field numbers above 100,000 in AOSP. Field numbers above
- // 100,000 are reserved for non-AOSP (e.g. OEMs) to use.
+ // DO NOT USE field numbers above 100,000 in AOSP.
+ // Field numbers 100,000 - 199,999 are reserved for non-AOSP (e.g. OEMs) to use.
+ // Field numbers 200,000 and above are reserved for future use; do not use them at all.
}
/**
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 63c583f..d93befd 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -2381,7 +2381,6 @@
android.os.-$$Lambda$StrictMode$yZJXPvy2veRNA-xL_SWdXzX_OLg
android.os.-$$Lambda$Trace$2zLZ-Lc2kAXsVjw_nLYeNhqmGq0
android.os.AsyncResult
-android.os.AsyncTask
android.os.AsyncTask$1
android.os.AsyncTask$2
android.os.AsyncTask$3
diff --git a/config/preloaded-classes-blacklist b/config/preloaded-classes-blacklist
index 8b8d640..eca3bf3 100644
--- a/config/preloaded-classes-blacklist
+++ b/config/preloaded-classes-blacklist
@@ -1,4 +1,5 @@
android.net.ConnectivityThread$Singleton
+android.os.AsyncTask
android.os.FileObserver
android.widget.Magnifier
sun.nio.fs.UnixChannelFactory
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 055a91e..14b8ae4 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3379,7 +3379,7 @@
*/
public ConfigurationInfo getDeviceConfigurationInfo() {
try {
- return getService().getDeviceConfigurationInfo();
+ return getTaskService().getDeviceConfigurationInfo();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 31e9a2d..6754df9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1541,7 +1541,7 @@
public void scheduleTrimMemory(int level) {
final Runnable r = PooledLambda.obtainRunnable(ActivityThread::handleTrimMemory,
- ActivityThread.this, level);
+ ActivityThread.this, level).recycleOnUse();
// Schedule trimming memory after drawing the frame to minimize jank-risk.
Choreographer choreographer = Choreographer.getMainThreadInstance();
if (choreographer != null) {
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 37a05f0..9d82ffa 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -239,7 +239,7 @@
* @param year the selected year
* @param month the selected month (0-11 for compatibility with
* {@link Calendar#MONTH})
- * @param dayOfMonth th selected day of the month (1-31, depending on
+ * @param dayOfMonth the selected day of the month (1-31, depending on
* month)
*/
void onDateSet(DatePicker view, int year, int month, int dayOfMonth);
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index c0c8b79..519a274 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -208,8 +208,6 @@
List<ActivityManager.RunningServiceInfo> getServices(int maxNum, int flags);
// Retrieve running application processes in the system
List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses();
- // Get device configuration
- ConfigurationInfo getDeviceConfigurationInfo();
IBinder peekService(in Intent service, in String resolvedType, in String callingPackage);
// Turn on/off profiling in a particular process.
boolean profileControl(in String process, int userId, boolean start,
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index abd1cca..b7b6352 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -344,6 +344,9 @@
void notifyPinnedStackAnimationStarted();
void notifyPinnedStackAnimationEnded();
+ // Get device configuration
+ ConfigurationInfo getDeviceConfigurationInfo();
+
/**
* Resizes the pinned stack.
*
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 9f819b9..07a8504 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1636,11 +1636,14 @@
try {
final ParceledListSlice<StatusBarNotification> parceledList
= service.getAppActiveNotifications(pkg, mContext.getUserId());
- final List<StatusBarNotification> list = parceledList.getList();
- return list.toArray(new StatusBarNotification[list.size()]);
+ if (parceledList != null) {
+ final List<StatusBarNotification> list = parceledList.getList();
+ return list.toArray(new StatusBarNotification[list.size()]);
+ }
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
+ return new StatusBarNotification[0];
}
/**
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 003f364..a679166 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -53,6 +53,8 @@
import android.hardware.SensorManager;
import android.hardware.SerialManager;
import android.hardware.SystemSensorManager;
+import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.IBiometricService;
import android.hardware.camera2.CameraManager;
import android.hardware.display.DisplayManager;
import android.hardware.face.FaceManager;
@@ -818,6 +820,19 @@
}
});
+ registerService(Context.BIOMETRIC_SERVICE, BiometricManager.class,
+ new CachedServiceFetcher<BiometricManager>() {
+ @Override
+ public BiometricManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ final IBinder binder =
+ ServiceManager.getServiceOrThrow(Context.BIOMETRIC_SERVICE);
+ final IBiometricService service =
+ IBiometricService.Stub.asInterface(binder);
+ return new BiometricManager(ctx.getOuterContext(), service);
+ }
+ });
+
registerService(Context.TV_INPUT_SERVICE, TvInputManager.class,
new CachedServiceFetcher<TvInputManager>() {
@Override
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index c0903b6..5a25f5a 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -1197,10 +1197,9 @@
}
if (listener != null) {
// Calling out only without a lock held.
- mLocalCallbackHandler.post(PooledLambda.obtainRunnable(
+ mLocalCallbackHandler.sendMessage(PooledLambda.obtainMessage(
OnAccessibilityEventListener::onAccessibilityEvent,
- listener, AccessibilityEvent.obtain(event))
- .recycleOnUse());
+ listener, AccessibilityEvent.obtain(event)));
}
}
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index e532ece..a554882 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -234,7 +234,7 @@
* Changes to night mode take effect globally and will result in a configuration change
* (and potentially an Activity lifecycle event) being applied to all running apps.
* Developers interested in an app-local implementation of night mode should consider using
- * {@link androidx.appcompat.app.AppCompatDelegate#setDefaultNightMode(int)} to manage the
+ * {@link android.support.v7.app.AppCompatDelegate#setDefaultNightMode(int)} to manage the
* -night qualifier locally.
*
* @param mode the night mode to set
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index d88f6e3..981be83 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3031,6 +3031,7 @@
AUDIO_SERVICE,
FINGERPRINT_SERVICE,
//@hide: FACE_SERVICE,
+ BIOMETRIC_SERVICE,
MEDIA_ROUTER_SERVICE,
TELEPHONY_SERVICE,
TELEPHONY_SUBSCRIPTION_SERVICE,
@@ -3681,15 +3682,6 @@
public static final String AUDIO_SERVICE = "audio";
/**
- * Use with {@link #getSystemService(String)}
- *
- * @hide
- * @see #getSystemService(String)
- * @see com.android.server.biometrics.BiometricPromptService
- */
- public static final String BIOMETRIC_PROMPT_SERVICE = "biometric_prompt";
-
- /**
* Use with {@link #getSystemService(String)} to retrieve a
* {@link android.hardware.fingerprint.FingerprintManager} for handling management
* of fingerprints.
@@ -3701,7 +3693,6 @@
/**
* Use with {@link #getSystemService(String)} to retrieve a
- * Use with {@link #getSystemService} to retrieve a
* {@link android.hardware.face.FaceManager} for handling management
* of face authentication.
*
@@ -3712,6 +3703,16 @@
public static final String FACE_SERVICE = "face";
/**
+ * Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.hardware.biometrics.BiometricManager} for handling management
+ * of face authentication.
+ *
+ * @see #getSystemService
+ * @see android.hardware.biometrics.BiometricManager
+ */
+ public static final String BIOMETRIC_SERVICE = "biometric";
+
+ /**
* Use with {@link #getSystemService} to retrieve a
* {@link android.media.MediaRouter} for controlling and managing
* routing of media.
diff --git a/core/java/android/content/res/package.html b/core/java/android/content/res/package.html
index 3d0bac1..3970b16 100644
--- a/core/java/android/content/res/package.html
+++ b/core/java/android/content/res/package.html
@@ -1,7 +1,7 @@
<HTML>
<BODY>
<p>Contains classes for accessing application resources,
-such as raw asset files, colors, drawables, media or other other files
+such as raw asset files, colors, drawables, media, or other files
in the package, plus important device configuration details
(orientation, input types, etc.) that affect how the application may behave.</p>
@@ -9,4 +9,4 @@
href="{@docRoot}guide/topics/resources/index.html">Application Resources</a> guide.</p>
{@more}
</BODY>
-</HTML>
\ No newline at end of file
+</HTML>
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
new file mode 100644
index 0000000..36e978b
--- /dev/null
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -0,0 +1,56 @@
+/*
+ * 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 android.hardware.biometrics;
+
+import static android.Manifest.permission.USE_BIOMETRIC;
+
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.os.RemoteException;
+
+/**
+ * A class that contains biometric utilities. For authentication, see {@link BiometricPrompt}.
+ */
+public class BiometricManager {
+
+ private final Context mContext;
+ private final IBiometricService mService;
+
+ /**
+ * @hide
+ * @param context
+ * @param service
+ */
+ public BiometricManager(Context context, IBiometricService service) {
+ mContext = context;
+ mService = service;
+ }
+
+ /**
+ * Determine if there is at least one biometric enrolled.
+ *
+ * @return true if at least one biometric is enrolled, false otherwise
+ */
+ @RequiresPermission(USE_BIOMETRIC)
+ public boolean hasEnrolledBiometrics() {
+ try {
+ return mService.hasEnrolledBiometrics();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+}
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 1cca27d..92a814c 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -225,7 +225,7 @@
private final IBinder mToken = new Binder();
private final Context mContext;
- private final IBiometricPromptService mService;
+ private final IBiometricService mService;
private final Bundle mBundle;
private final ButtonInfo mPositiveButtonInfo;
private final ButtonInfo mNegativeButtonInfo;
@@ -250,8 +250,8 @@
}
};
- IBiometricPromptServiceReceiver mBiometricPromptServiceReceiver =
- new IBiometricPromptServiceReceiver.Stub() {
+ IBiometricServiceReceiver mBiometricServiceReceiver =
+ new IBiometricServiceReceiver.Stub() {
@Override
public void onAuthenticationSucceeded(long deviceId) throws RemoteException {
@@ -290,8 +290,8 @@
mBundle = bundle;
mPositiveButtonInfo = positiveButtonInfo;
mNegativeButtonInfo = negativeButtonInfo;
- mService = IBiometricPromptService.Stub.asInterface(
- ServiceManager.getService(Context.BIOMETRIC_PROMPT_SERVICE));
+ mService = IBiometricService.Stub.asInterface(
+ ServiceManager.getService(Context.BIOMETRIC_SERVICE));
}
/**
@@ -516,7 +516,7 @@
mAuthenticationCallback = callback;
final long sessionId = crypto != null ? crypto.getOpId() : 0;
mService.authenticate(mToken, sessionId, mContext.getUserId(),
- mBiometricPromptServiceReceiver, 0 /* flags */, mContext.getOpPackageName(),
+ mBiometricServiceReceiver, 0 /* flags */, mContext.getOpPackageName(),
mBundle, mDialogReceiver);
} catch (RemoteException e) {
Log.e(TAG, "Remote exception while authenticating", e);
diff --git a/core/java/android/hardware/biometrics/IBiometricPromptService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
similarity index 66%
rename from core/java/android/hardware/biometrics/IBiometricPromptService.aidl
rename to core/java/android/hardware/biometrics/IBiometricService.aidl
index 2c93579..bfd6941 100644
--- a/core/java/android/hardware/biometrics/IBiometricPromptService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -18,21 +18,25 @@
import android.os.Bundle;
import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.IBiometricPromptServiceReceiver;
+import android.hardware.biometrics.IBiometricServiceReceiver;
/**
- * Communication channel from BiometricPrompt to BiometricPromptService. The interface does not
- * expose specific biometric modalities. The system will use the default biometric for apps. On
- * devices with more than one, the choice is dictated by user preference in Settings.
+ * Communication channel from BiometricPrompt and BiometricManager to BiometricService. The
+ * interface does not expose specific biometric modalities. The system will use the default
+ * biometric for apps. On devices with more than one, the choice is dictated by user preference in
+ * Settings.
* @hide
*/
-interface IBiometricPromptService {
+interface IBiometricService {
// Requests authentication. The service choose the appropriate biometric to use, and show
// the corresponding BiometricDialog.
void authenticate(IBinder token, long sessionId, int userId,
- IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
+ IBiometricServiceReceiver receiver, int flags, String opPackageName,
in Bundle bundle, IBiometricPromptReceiver dialogReceiver);
// Cancel authentication for the given sessionId
void cancelAuthentication(IBinder token, String opPackageName);
+
+ // Returns true if the user has at least one enrolled biometric.
+ boolean hasEnrolledBiometrics();
}
\ No newline at end of file
diff --git a/core/java/android/hardware/biometrics/IBiometricPromptServiceReceiver.aidl b/core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl
similarity index 88%
rename from core/java/android/hardware/biometrics/IBiometricPromptServiceReceiver.aidl
rename to core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl
index 1ef6c52..71abdd2 100644
--- a/core/java/android/hardware/biometrics/IBiometricPromptServiceReceiver.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl
@@ -20,10 +20,10 @@
import android.os.UserHandle;
/**
- * Communication channel from the BiometricPromptService back to BiometricPrompt.
+ * Communication channel from the BiometricService back to BiometricPrompt.
* @hide
*/
-oneway interface IBiometricPromptServiceReceiver {
+oneway interface IBiometricServiceReceiver {
void onAuthenticationSucceeded(long deviceId);
void onAuthenticationFailed(long deviceId);
void onError(long deviceId, int error, String message);
diff --git a/core/java/android/hardware/camera2/utils/CloseableLock.java b/core/java/android/hardware/camera2/utils/CloseableLock.java
index 9ac89c8..3b8beac 100644
--- a/core/java/android/hardware/camera2/utils/CloseableLock.java
+++ b/core/java/android/hardware/camera2/utils/CloseableLock.java
@@ -290,7 +290,7 @@
/**
* Release a single lock that was acquired.
*
- * <p>Any other other that is blocked and trying to acquire a lock will get a chance
+ * <p>Any other thread that is blocked and trying to acquire a lock will get a chance
* to acquire the lock.</p>
*
* @throws IllegalStateException if no locks were acquired, or if the lock was already closed
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 20e0116..66613ea 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -521,16 +521,16 @@
*/
public static String getErrorString(Context context, int errMsg, int vendorCode) {
switch (errMsg) {
- case FACE_ERROR_HW_UNAVAILABLE:
- return context.getString(
- com.android.internal.R.string.face_error_hw_not_available);
case FACE_ERROR_UNABLE_TO_PROCESS:
return context.getString(
com.android.internal.R.string.face_error_unable_to_process);
- case FACE_ERROR_TIMEOUT:
- return context.getString(com.android.internal.R.string.face_error_timeout);
+ case FACE_ERROR_HW_UNAVAILABLE:
+ return context.getString(
+ com.android.internal.R.string.face_error_hw_not_available);
case FACE_ERROR_NO_SPACE:
return context.getString(com.android.internal.R.string.face_error_no_space);
+ case FACE_ERROR_TIMEOUT:
+ return context.getString(com.android.internal.R.string.face_error_timeout);
case FACE_ERROR_CANCELED:
return context.getString(com.android.internal.R.string.face_error_canceled);
case FACE_ERROR_LOCKOUT:
@@ -538,6 +538,8 @@
case FACE_ERROR_LOCKOUT_PERMANENT:
return context.getString(
com.android.internal.R.string.face_error_lockout_permanent);
+ case FACE_ERROR_USER_CANCELED:
+ return context.getString(com.android.internal.R.string.face_error_user_canceled);
case FACE_ERROR_NOT_ENROLLED:
return context.getString(com.android.internal.R.string.face_error_not_enrolled);
case FACE_ERROR_HW_NOT_PRESENT:
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index dd995c9..50d0744 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -17,7 +17,7 @@
import android.os.Bundle;
import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.IBiometricPromptServiceReceiver;
+import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.face.IFaceServiceReceiver;
import android.hardware.face.Face;
@@ -34,8 +34,8 @@
// This method invokes the BiometricDialog. The arguments are almost the same as above,
// but should only be called from (BiometricPromptService).
- void authenticateFromService(IBinder token, long sessionId, int userId,
- IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
+ void authenticateFromService(boolean requireConfirmation, IBinder token, long sessionId,
+ int userId, IBiometricServiceReceiver receiver, int flags, String opPackageName,
in Bundle bundle, IBiometricPromptReceiver dialogReceiver,
int callingUid, int callingPid, int callingUserId);
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 2b2c0b7..2662a11 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -17,7 +17,7 @@
import android.os.Bundle;
import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.IBiometricPromptServiceReceiver;
+import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
@@ -40,7 +40,7 @@
// called from BiometricPromptService. The additional uid, pid, userId arguments should be
// determined by BiometricPromptService.
void authenticateFromService(IBinder token, long sessionId, int userId,
- IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
+ IBiometricServiceReceiver receiver, int flags, String opPackageName,
in Bundle bundle, IBiometricPromptReceiver dialogReceiver,
int callingUid, int callingPid, int callingUserId);
diff --git a/core/java/android/net/ConnectionInfo.aidl b/core/java/android/net/ConnectionInfo.aidl
new file mode 100644
index 0000000..07faf8b
--- /dev/null
+++ b/core/java/android/net/ConnectionInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** 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 android.net;
+
+parcelable ConnectionInfo;
diff --git a/core/java/android/net/ConnectionInfo.java b/core/java/android/net/ConnectionInfo.java
new file mode 100644
index 0000000..58d0e05
--- /dev/null
+++ b/core/java/android/net/ConnectionInfo.java
@@ -0,0 +1,83 @@
+/*
+ * 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 android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Describe a network connection including local and remote address/port of a connection and the
+ * transport protocol.
+ *
+ * @hide
+ */
+public final class ConnectionInfo implements Parcelable {
+ public final int protocol;
+ public final InetSocketAddress local;
+ public final InetSocketAddress remote;
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public ConnectionInfo(int protocol, InetSocketAddress local, InetSocketAddress remote) {
+ this.protocol = protocol;
+ this.local = local;
+ this.remote = remote;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(protocol);
+ out.writeByteArray(local.getAddress().getAddress());
+ out.writeInt(local.getPort());
+ out.writeByteArray(remote.getAddress().getAddress());
+ out.writeInt(remote.getPort());
+ }
+
+ public static final Creator<ConnectionInfo> CREATOR = new Creator<ConnectionInfo>() {
+ public ConnectionInfo createFromParcel(Parcel in) {
+ int protocol = in.readInt();
+ InetAddress localAddress;
+ try {
+ localAddress = InetAddress.getByAddress(in.createByteArray());
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException("Invalid InetAddress");
+ }
+ int localPort = in.readInt();
+ InetAddress remoteAddress;
+ try {
+ remoteAddress = InetAddress.getByAddress(in.createByteArray());
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException("Invalid InetAddress");
+ }
+ int remotePort = in.readInt();
+ InetSocketAddress local = new InetSocketAddress(localAddress, localPort);
+ InetSocketAddress remote = new InetSocketAddress(remoteAddress, remotePort);
+ return new ConnectionInfo(protocol, local, remote);
+ }
+
+ public ConnectionInfo[] newArray(int size) {
+ return new ConnectionInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ce18796..f2e9078 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -59,6 +59,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -3930,4 +3931,26 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Returns the {@code uid} of the owner of a network connection.
+ *
+ * @param protocol The protocol of the connection. Only {@code IPPROTO_TCP} and
+ * {@code IPPROTO_UDP} currently supported.
+ * @param local The local {@link InetSocketAddress} of a connection.
+ * @param remote The remote {@link InetSocketAddress} of a connection.
+ *
+ * @return {@code uid} if the connection is found and the app has permission to observe it
+ * (e.g., if it is associated with the calling VPN app's tunnel) or
+ * {@link android.os.Process#INVALID_UID} if the connection is not found.
+ */
+ public int getConnectionOwnerUid(int protocol, InetSocketAddress local,
+ InetSocketAddress remote) {
+ ConnectionInfo connectionInfo = new ConnectionInfo(protocol, local, remote);
+ try {
+ return mService.getConnectionOwnerUid(connectionInfo);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index ce95b60..e7d441d 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -17,6 +17,7 @@
package android.net;
import android.app.PendingIntent;
+import android.net.ConnectionInfo;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -182,4 +183,6 @@
String getCaptivePortalServerUrl();
byte[] getNetworkWatchlistConfigHash();
+
+ int getConnectionOwnerUid(in ConnectionInfo connectionInfo);
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 5cd2ffc..6fab3c4 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -42,6 +42,11 @@
public static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";
/**
+ * An invalid UID value.
+ */
+ public static final int INVALID_UID = -1;
+
+ /**
* Defines the root UID.
* @hide
*/
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 3e8e885..8492b0c 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -36,16 +36,12 @@
import android.view.Display;
import android.view.WindowManager;
-import com.android.internal.logging.MetricsLogger;
-
import libcore.io.Streams;
-import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
@@ -97,7 +93,7 @@
/** Used to communicate with recovery. See bootable/recovery/recovery.cpp. */
private static final File RECOVERY_DIR = new File("/cache/recovery");
private static final File LOG_FILE = new File(RECOVERY_DIR, "log");
- private static final File LAST_INSTALL_FILE = new File(RECOVERY_DIR, "last_install");
+ private static final String LAST_INSTALL_PATH = "last_install";
private static final String LAST_PREFIX = "last_";
private static final String ACTION_EUICC_FACTORY_RESET =
"com.android.internal.action.EUICC_FACTORY_RESET";
@@ -935,116 +931,6 @@
throw new IOException("Reboot failed (no permissions?)");
}
- // Read last_install; then report time (in seconds) and I/O (in MiB) for
- // this update to tron.
- // Only report on the reboots immediately after an OTA update.
- private static void parseLastInstallLog(Context context) {
- try (BufferedReader in = new BufferedReader(new FileReader(LAST_INSTALL_FILE))) {
- String line = null;
- int bytesWrittenInMiB = -1, bytesStashedInMiB = -1;
- int timeTotal = -1;
- int uncryptTime = -1;
- int sourceVersion = -1;
- int temperatureStart = -1;
- int temperatureEnd = -1;
- int temperatureMax = -1;
- int errorCode = -1;
- int causeCode = -1;
-
- while ((line = in.readLine()) != null) {
- // Here is an example of lines in last_install:
- // ...
- // time_total: 101
- // bytes_written_vendor: 51074
- // bytes_stashed_vendor: 200
- int numIndex = line.indexOf(':');
- if (numIndex == -1 || numIndex + 1 >= line.length()) {
- continue;
- }
- String numString = line.substring(numIndex + 1).trim();
- long parsedNum;
- try {
- parsedNum = Long.parseLong(numString);
- } catch (NumberFormatException ignored) {
- Log.e(TAG, "Failed to parse numbers in " + line);
- continue;
- }
-
- final int MiB = 1024 * 1024;
- int scaled;
- try {
- if (line.startsWith("bytes")) {
- scaled = Math.toIntExact(parsedNum / MiB);
- } else {
- scaled = Math.toIntExact(parsedNum);
- }
- } catch (ArithmeticException ignored) {
- Log.e(TAG, "Number overflows in " + line);
- continue;
- }
-
- if (line.startsWith("time")) {
- timeTotal = scaled;
- } else if (line.startsWith("uncrypt_time")) {
- uncryptTime = scaled;
- } else if (line.startsWith("source_build")) {
- sourceVersion = scaled;
- } else if (line.startsWith("bytes_written")) {
- bytesWrittenInMiB = (bytesWrittenInMiB == -1) ? scaled :
- bytesWrittenInMiB + scaled;
- } else if (line.startsWith("bytes_stashed")) {
- bytesStashedInMiB = (bytesStashedInMiB == -1) ? scaled :
- bytesStashedInMiB + scaled;
- } else if (line.startsWith("temperature_start")) {
- temperatureStart = scaled;
- } else if (line.startsWith("temperature_end")) {
- temperatureEnd = scaled;
- } else if (line.startsWith("temperature_max")) {
- temperatureMax = scaled;
- } else if (line.startsWith("error")) {
- errorCode = scaled;
- } else if (line.startsWith("cause")) {
- causeCode = scaled;
- }
- }
-
- // Don't report data to tron if corresponding entry isn't found in last_install.
- if (timeTotal != -1) {
- MetricsLogger.histogram(context, "ota_time_total", timeTotal);
- }
- if (uncryptTime != -1) {
- MetricsLogger.histogram(context, "ota_uncrypt_time", uncryptTime);
- }
- if (sourceVersion != -1) {
- MetricsLogger.histogram(context, "ota_source_version", sourceVersion);
- }
- if (bytesWrittenInMiB != -1) {
- MetricsLogger.histogram(context, "ota_written_in_MiBs", bytesWrittenInMiB);
- }
- if (bytesStashedInMiB != -1) {
- MetricsLogger.histogram(context, "ota_stashed_in_MiBs", bytesStashedInMiB);
- }
- if (temperatureStart != -1) {
- MetricsLogger.histogram(context, "ota_temperature_start", temperatureStart);
- }
- if (temperatureEnd != -1) {
- MetricsLogger.histogram(context, "ota_temperature_end", temperatureEnd);
- }
- if (temperatureMax != -1) {
- MetricsLogger.histogram(context, "ota_temperature_max", temperatureMax);
- }
- if (errorCode != -1) {
- MetricsLogger.histogram(context, "ota_non_ab_error_code", errorCode);
- }
- if (causeCode != -1) {
- MetricsLogger.histogram(context, "ota_non_ab_cause_code", causeCode);
- }
-
- } catch (IOException e) {
- Log.e(TAG, "Failed to read lines in last_install", e);
- }
- }
-
/**
* Called after booting to process and remove recovery-related files.
* @return the log file from recovery, or null if none was found.
@@ -1062,9 +948,6 @@
Log.e(TAG, "Error reading recovery log", e);
}
- if (log != null) {
- parseLastInstallLog(context);
- }
// Only remove the OTA package if it's partially processed (uncrypt'd).
boolean reservePackage = BLOCK_MAP_FILE.exists();
@@ -1095,7 +978,8 @@
// GmsCore to avoid re-downloading everything again.
String[] names = RECOVERY_DIR.list();
for (int i = 0; names != null && i < names.length; i++) {
- if (names[i].startsWith(LAST_PREFIX)) continue;
+ // Do not remove the last_install file since the recovery-persist takes care of it.
+ if (names[i].startsWith(LAST_PREFIX) || names[i].equals(LAST_INSTALL_PATH)) continue;
if (reservePackage && names[i].equals(BLOCK_MAP_FILE.getName())) continue;
if (reservePackage && names[i].equals(UNCRYPT_PACKAGE_FILE.getName())) continue;
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 112329e..f126c49 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -2783,7 +2783,48 @@
* The content:// style URI for this table, which requests a directory of
* raw contact rows matching the selection criteria.
*/
- public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "raw_contacts");
+ public static final Uri CONTENT_URI =
+ Uri.withAppendedPath(AUTHORITY_URI, "raw_contacts");
+
+ /**
+ * The URI to register for all raw contacts change notification.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final Uri RAW_CONTACTS_NOTIFICATION_URI =
+ Uri.parse("content://com.android.contacts.raw_contacts");
+
+ /**
+ * The URI to register for raw contacts insert notification.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final Uri RAW_CONTACTS_NOTIFICATION_INSERT_URI =
+ Uri.withAppendedPath(RAW_CONTACTS_NOTIFICATION_URI, "insert");
+
+ /**
+ * The URI to register for raw contacts update notification.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final Uri RAW_CONTACTS_NOTIFICATION_UPDATE_URI =
+ Uri.withAppendedPath(RAW_CONTACTS_NOTIFICATION_URI, "update");
+
+ /**
+ * The URI to register for raw contacts delete notification.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final Uri RAW_CONTACTS_NOTIFICATION_DELETE_URI =
+ Uri.withAppendedPath(RAW_CONTACTS_NOTIFICATION_URI, "delete");
/**
* The MIME type of the results from {@link #CONTENT_URI} when a specific
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 6c18b45..573d577 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -651,14 +651,11 @@
/**
* Called when the user requests the service to save the contents of a screen.
*
- * <p>Service must call one of the {@link SaveCallback} methods (like
- * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)})
- * to notify the Android System of the result of the request.
- *
* <p>If the service could not handle the request right away—for example, because it must
* launch an activity asking the user to authenticate first or because the network is
* down—the service could keep the {@link SaveRequest request} and reuse it later,
- * but the service must call {@link SaveCallback#onSuccess()} right away.
+ * but the service <b>must always</b> call {@link SaveCallback#onSuccess()} or
+ * {@link SaveCallback#onSuccess(android.content.IntentSender)} right away.
*
* <p><b>Note:</b> To retrieve the actual value of fields input by the user, the service
* should call
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
index 3893f2a..06e2896 100644
--- a/core/java/android/service/autofill/FillCallback.java
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -83,19 +83,24 @@
* fulfill the request; in this case, the service should call {@link #onSuccess(FillResponse)
* onSuccess(null)} instead.
*
- * <p><b>Note: </b>on Android versions up to {@link android.os.Build.VERSION_CODES#P}, this
- * method is not working as intended, and the service should call
+ * <p><b>Note: </b>prior to {@link android.os.Build.VERSION_CODES#Q}, this
+ * method was not working as intended and the service should always call
* {@link #onSuccess(FillResponse) onSuccess(null)} instead.
*
- * @param message error message to be displayed to the user. <b>Note: </b> this message is
- * displayed on {@code logcat} logs and should not contain PII (Personally Identifiable
- * Information, such as username or email address).
+ * <p><b>Note: </b>for apps targeting {@link android.os.Build.VERSION_CODES#Q} or higher, this
+ * method just logs the message on {@code logcat}; for apps targetting older SDKs, it also
+ * displays the message to user using a {@link android.widget.Toast}. Generally speaking, you
+ * should not display an error to the user if the request failed, unless the request had the
+ * {@link FillRequest#FLAG_MANUAL_REQUEST} flag.
+ *
+ * @param message error message. <b>Note: </b> this message should <b>not</b> contain PII
+ * (Personally Identifiable Information, such as username or email address).
*
* @throws IllegalStateException if this method or {@link #onSuccess(FillResponse)} was already
* called.
*/
public void onFailure(@Nullable CharSequence message) {
- Log.w(TAG, "onFailure(): " + (message == null ? null : message.length() + "_chars"));
+ Log.w(TAG, "onFailure(): " + message);
assertNotCalled();
mCalled = true;
try {
diff --git a/core/java/android/service/autofill/SaveCallback.java b/core/java/android/service/autofill/SaveCallback.java
index 0625095..1753ecf 100644
--- a/core/java/android/service/autofill/SaveCallback.java
+++ b/core/java/android/service/autofill/SaveCallback.java
@@ -83,28 +83,30 @@
}
}
+
+
+
/**
* Notifies the Android System that an
* {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)} could not be handled
* by the service.
*
- * <p>This method should only be called when the service could not handle the request right away
- * and could not recover or retry it. If the service could retry or recover, it could keep
- * the {@link SaveRequest} and call {@link #onSuccess()} instead.
+ * <p>This method is just used for logging purposes, the Android System won't call the service
+ * again in case of failures—if you need to recover from the failure, just save the
+ * {@link SaveRequest} and try again later.
*
- * <p><b>Note:</b> The Android System displays an UI with the supplied error message; if
- * you prefer to show your own message, call {@link #onSuccess()} or
- * {@link #onSuccess(IntentSender)} instead.
+ * <p><b>Note: </b>for apps targeting {@link android.os.Build.VERSION_CODES#Q} or higher, this
+ * method just logs the message on {@code logcat}; for apps targetting older SDKs, it also
+ * displays the message to user using a {@link android.widget.Toast}.
*
- * @param message error message to be displayed to the user. <b>Note: </b> this message is
- * displayed on {@code logcat} logs and should not contain PII (Personally Identifiable
- * Information, such as username or email address).
+ * @param message error message. <b>Note: </b> this message should <b>not</b> contain PII
+ * (Personally Identifiable Information, such as username or email address).
*
* @throws IllegalStateException if this method, {@link #onSuccess()},
* or {@link #onSuccess(IntentSender)} was already called.
*/
public void onFailure(CharSequence message) {
- Log.w(TAG, "onFailure(): " + (message == null ? null : message.length() + "_chars"));
+ Log.w(TAG, "onFailure(): " + message);
assertNotCalled();
mCalled = true;
try {
diff --git a/core/java/android/view/animation/DecelerateInterpolator.java b/core/java/android/view/animation/DecelerateInterpolator.java
index f89743c..2d1249d 100644
--- a/core/java/android/view/animation/DecelerateInterpolator.java
+++ b/core/java/android/view/animation/DecelerateInterpolator.java
@@ -41,8 +41,8 @@
* Constructor
*
* @param factor Degree to which the animation should be eased. Setting factor to 1.0f produces
- * an upside-down y=x^2 parabola. Increasing factor above 1.0f makes exaggerates the
- * ease-out effect (i.e., it starts even faster and ends evens slower)
+ * an upside-down y=x^2 parabola. Increasing factor above 1.0f exaggerates the
+ * ease-out effect (i.e., it starts even faster and ends evens slower).
*/
public DecelerateInterpolator(float factor) {
mFactor = factor;
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index e87048e..7abe19e79 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -301,6 +301,14 @@
*/
public static final int STATE_UNKNOWN_COMPAT_MODE = 5;
+ /**
+ * Same as {@link #STATE_UNKNOWN}, but used on
+ * {@link AutofillManagerClient#setSessionFinished(int)} when the session was finished because
+ * the service failed to fullfil a request.
+ *
+ * @hide
+ */
+ public static final int STATE_UNKNOWN_FAILED = 6;
/**
* Timeout in ms for calls to the field classification service.
@@ -2023,8 +2031,10 @@
* @param newState {@link #STATE_FINISHED} (because the autofill service returned a {@code null}
* FillResponse), {@link #STATE_UNKNOWN} (because the session was removed),
* {@link #STATE_UNKNOWN_COMPAT_MODE} (beucase the session was finished when the URL bar
- * changed on compat mode), or {@link #STATE_DISABLED_BY_SERVICE} (because the autofill service
- * disabled further autofill requests for the activity).
+ * changed on compat mode), {@link #STATE_UNKNOWN_FAILED} (because the session was finished
+ * when the service failed to fullfil the request, or {@link #STATE_DISABLED_BY_SERVICE}
+ * (because the autofill service or {@link #STATE_DISABLED_BY_SERVICE} (because the autofill
+ * service disabled further autofill requests for the activity).
*/
private void setSessionFinished(int newState) {
synchronized (mLock) {
@@ -2032,7 +2042,7 @@
Log.v(TAG, "setSessionFinished(): from " + getStateAsStringLocked() + " to "
+ getStateAsString(newState));
}
- if (newState == STATE_UNKNOWN_COMPAT_MODE) {
+ if (newState == STATE_UNKNOWN_COMPAT_MODE || newState == STATE_UNKNOWN_FAILED) {
resetSessionLocked(/* resetEnteredIds= */ true);
mState = STATE_UNKNOWN;
} else {
@@ -2229,6 +2239,8 @@
return "DISABLED_BY_SERVICE";
case STATE_UNKNOWN_COMPAT_MODE:
return "UNKNOWN_COMPAT_MODE";
+ case STATE_UNKNOWN_FAILED:
+ return "UNKNOWN_FAILED";
default:
return "INVALID:" + state;
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 9ede57f..36ede22 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -57,6 +57,7 @@
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import android.view.autofill.AutofillManager;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
import com.android.internal.os.SomeArgs;
import com.android.internal.view.IInputConnectionWrapper;
@@ -69,6 +70,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -263,6 +265,9 @@
*/
public static final boolean ENABLE_LEGACY_EAGER_INITIALIZATION = true;
+ private static final Object sLock = new Object();
+
+ @GuardedBy("sLock")
@UnsupportedAppUsage
static InputMethodManager sInstance;
@@ -666,13 +671,63 @@
final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
- InputMethodManager(Looper looper) throws ServiceNotFoundException {
- this(IInputMethodManager.Stub.asInterface(
- ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE)), looper);
+ /**
+ * For layoutlib to clean up static objects inside {@link InputMethodManager}.
+ */
+ static void tearDownEditMode() {
+ if (!isInEditMode()) {
+ throw new UnsupportedOperationException(
+ "This method must be called only from layoutlib");
+ }
+ synchronized (sLock) {
+ sInstance = null;
+ }
}
- InputMethodManager(IInputMethodManager service, Looper looper) {
- mService = service;
+ /**
+ * For layoutlib to override this method to return {@code true}.
+ *
+ * @return {@code true} if the process is running for developer tools
+ * @see View#isInEditMode()
+ */
+ private static boolean isInEditMode() {
+ return false;
+ }
+
+ private static IInputMethodManager getIInputMethodManager() throws ServiceNotFoundException {
+ if (!isInEditMode()) {
+ return IInputMethodManager.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE));
+ }
+ // If InputMethodManager is running for layoutlib, stub out IPCs into IMMS.
+ final Class<IInputMethodManager> c = IInputMethodManager.class;
+ return (IInputMethodManager) Proxy.newProxyInstance(c.getClassLoader(),
+ new Class[]{c}, (proxy, method, args) -> {
+ final Class<?> returnType = method.getReturnType();
+ if (returnType == boolean.class) {
+ return false;
+ } else if (returnType == int.class) {
+ return 0;
+ } else if (returnType == long.class) {
+ return 0L;
+ } else if (returnType == short.class) {
+ return 0;
+ } else if (returnType == char.class) {
+ return 0;
+ } else if (returnType == byte.class) {
+ return 0;
+ } else if (returnType == float.class) {
+ return 0f;
+ } else if (returnType == double.class) {
+ return 0.0;
+ } else {
+ return null;
+ }
+ });
+ }
+
+ InputMethodManager(Looper looper) throws ServiceNotFoundException {
+ mService = getIInputMethodManager();
mMainLooper = looper;
mH = new H(looper);
mIInputContext = new ControlledInputConnectionWrapper(looper,
@@ -686,7 +741,7 @@
*/
@UnsupportedAppUsage
public static InputMethodManager getInstance() {
- synchronized (InputMethodManager.class) {
+ synchronized (sLock) {
if (sInstance == null) {
try {
final InputMethodManager imm = new InputMethodManager(Looper.getMainLooper());
@@ -709,7 +764,9 @@
@Deprecated
@UnsupportedAppUsage
public static InputMethodManager peekInstance() {
- return sInstance;
+ synchronized (sLock) {
+ return sInstance;
+ }
}
/** @hide */
diff --git a/core/java/android/widget/DigitalClock.java b/core/java/android/widget/DigitalClock.java
index c503ef2..8ebf303 100644
--- a/core/java/android/widget/DigitalClock.java
+++ b/core/java/android/widget/DigitalClock.java
@@ -27,7 +27,7 @@
import java.util.Calendar;
/**
- * Like AnalogClock, but digital. Shows seconds.
+ * Like AnalogClock, but digital.
*
* @deprecated It is recommended you use {@link TextClock} instead.
*/
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index c4214cf..9b8f120 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -141,7 +141,8 @@
void showShutdownUi(boolean isReboot, String reason);
// Used to show the dialog when BiometricService starts authentication
- void showBiometricDialog(in Bundle bundle, IBiometricPromptReceiver receiver, int type);
+ void showBiometricDialog(in Bundle bundle, IBiometricPromptReceiver receiver, int type,
+ boolean requireConfirmation);
// Used to hide the dialog when a biometric is authenticated
void onBiometricAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index e48e733..90f2002 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -91,7 +91,8 @@
void showPinningEscapeToast();
// Used to show the dialog when BiometricService starts authentication
- void showBiometricDialog(in Bundle bundle, IBiometricPromptReceiver receiver, int type);
+ void showBiometricDialog(in Bundle bundle, IBiometricPromptReceiver receiver, int type,
+ boolean requireConfirmation);
// Used to hide the dialog when a biometric is authenticated
void onBiometricAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 0c9a85a..897f6fa5 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -325,33 +325,6 @@
return true;
}
-//////////////////// ToColor procs
-
-static void ToColor_SA8(SkColor dst[], const void* src, int width) {
- SkASSERT(width > 0);
- const uint8_t* s = (const uint8_t*)src;
- do {
- uint8_t c = *s++;
- *dst++ = SkColorSetARGB(c, 0, 0, 0);
- } while (--width != 0);
-}
-
-static void ToF16_SA8(void* dst, const void* src, int width) {
- SkASSERT(width > 0);
- uint64_t* d = (uint64_t*)dst;
- const uint8_t* s = (const uint8_t*)src;
-
- for (int i = 0; i < width; i++) {
- uint8_t c = *s++;
- SkPM4f a;
- a.fVec[SkPM4f::R] = 0.0f;
- a.fVec[SkPM4f::G] = 0.0f;
- a.fVec[SkPM4f::B] = 0.0f;
- a.fVec[SkPM4f::A] = c / 255.0f;
- *d++ = a.toF16();
- }
-}
-
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@@ -416,23 +389,12 @@
SkImageInfo dstInfo = srcPM.info().makeColorType(dstCT);
switch (dstCT) {
case kRGB_565_SkColorType:
- // copyTo() has never been strict on alpha type. Here we set the src to opaque to
- // allow the call to readPixels() to succeed and preserve this lenient behavior.
- if (kOpaque_SkAlphaType != srcPM.alphaType()) {
- srcPM = SkPixmap(srcPM.info().makeAlphaType(kOpaque_SkAlphaType), srcPM.addr(),
- srcPM.rowBytes());
- dstInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType);
- }
+ dstInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType);
break;
case kRGBA_F16_SkColorType:
// The caller does not have an opportunity to pass a dst color space. Assume that
// they want linear sRGB.
dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear());
-
- if (!srcPM.colorSpace()) {
- // Skia needs a color space to convert to F16. nullptr should be treated as sRGB.
- srcPM.setColorSpace(SkColorSpace::MakeSRGB());
- }
break;
default:
break;
@@ -445,57 +407,11 @@
return false;
}
- // Skia does not support copying from kAlpha8 to types that are not alpha only.
- // We will handle this case here.
- if (kAlpha_8_SkColorType == srcPM.colorType() && kAlpha_8_SkColorType != dstCT) {
- switch (dstCT) {
- case kRGBA_8888_SkColorType:
- case kBGRA_8888_SkColorType: {
- for (int y = 0; y < src.height(); y++) {
- const uint8_t* srcRow = srcPM.addr8(0, y);
- uint32_t* dstRow = dst->getAddr32(0, y);
- ToColor_SA8(dstRow, srcRow, src.width());
- }
- return true;
- }
- case kRGB_565_SkColorType: {
- for (int y = 0; y < src.height(); y++) {
- uint16_t* dstRow = dst->getAddr16(0, y);
- memset(dstRow, 0, sizeof(uint16_t) * src.width());
- }
- return true;
- }
- case kRGBA_F16_SkColorType: {
- for (int y = 0; y < src.height(); y++) {
- const uint8_t* srcRow = srcPM.addr8(0, y);
- void* dstRow = dst->getAddr(0, y);
- ToF16_SA8(dstRow, srcRow, src.width());
- }
- return true;
- }
- default:
- return false;
- }
- }
-
SkPixmap dstPM;
if (!dst->peekPixels(&dstPM)) {
return false;
}
- // Skia needs a color space to convert from F16. nullptr should be treated as sRGB.
- if (kRGBA_F16_SkColorType == srcPM.colorType() && !dstPM.colorSpace()) {
- dstPM.setColorSpace(SkColorSpace::MakeSRGB());
- }
-
- // readPixels does not support color spaces with parametric transfer functions. This
- // works around that restriction when the color spaces are equal.
- if (kRGBA_F16_SkColorType != dstCT && kRGBA_F16_SkColorType != srcPM.colorType() &&
- dstPM.colorSpace() == srcPM.colorSpace()) {
- dstPM.setColorSpace(nullptr);
- srcPM.setColorSpace(nullptr);
- }
-
return srcPM.readPixels(dstPM);
}
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index e2dc52b..5f67d30 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -21,11 +21,11 @@
#include "CreateJavaOutputStreamAdaptor.h"
-#include "SkDocument.h"
+#include "SkPDFDocument.h"
#include "SkPicture.h"
#include "SkPictureRecorder.h"
-#include "SkStream.h"
#include "SkRect.h"
+#include "SkStream.h"
#include <hwui/Canvas.h>
@@ -88,7 +88,7 @@
}
void write(SkWStream* stream) {
- sk_sp<SkDocument> document = SkDocument::MakePDF(stream);
+ sk_sp<SkDocument> document = SkPDF::MakeDocument(stream);
for (unsigned i = 0; i < mPages.size(); i++) {
PageRecord* page = mPages[i];
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index 6f4a58a..58a2379 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -130,7 +130,7 @@
static jfloat getRootAlpha(JNIEnv*, jobject, jlong treePtr) {
VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
- return tree->stagingProperties()->getRootAlpha();
+ return tree->stagingProperties().getRootAlpha();
}
static void updateFullPathPropertiesAndStrokeStyles(JNIEnv*, jobject, jlong fullPathPtr,
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 1257336..d33ea0c 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -157,6 +157,7 @@
optional int32 rotation = 11;
optional ScreenRotationAnimationProto screen_rotation_animation = 12;
optional DisplayFramesProto display_frames = 13;
+ optional int32 surface_size = 14;
}
/* represents DisplayFrames */
@@ -211,6 +212,8 @@
optional .android.graphics.RectProto bounds = 5;
optional .android.graphics.RectProto temp_inset_bounds = 6;
optional bool defer_removal = 7;
+ optional int32 surface_width = 8;
+ optional int32 surface_height = 9;
}
/* represents AppWindowToken */
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1df3f7f..5a1f2e8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -615,6 +615,8 @@
<protected-broadcast android:name="com.android.server.jobscheduler.FORCE_IDLE" />
<protected-broadcast android:name="com.android.server.jobscheduler.UNFORCE_IDLE" />
+ <protected-broadcast android:name="android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
@@ -4136,6 +4138,12 @@
<permission android:name="android.permission.DISABLE_HIDDEN_API_CHECKS"
android:protectionLevel="signature" />
+ <!-- @hide Permission that protects the
+ {@link android.provider.Telephony.Intents#ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL}
+ broadcast -->
+ <permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE"
+ android:protectionLevel="signature" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index c2c9254..3b124da 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Probleem om Wi-Fi-oproepe by jou diensverskaffer te registreer: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi-oproep"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g>-Wi-Fi-oproepe"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-oproep"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g>-WLAN-oproep"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g>-Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi-oproepe | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g>-VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Af"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Verkies Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Verkies mobiel"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Nie herken nie"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Vingerafdruk is gestaaf"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Vingerafdrukhardeware is nie beskikbaar nie."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Vingerafdruk kan nie gestoor word nie. Verwyder asseblief \'n bestaande vingerafdruk."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vingerafdrukuittelling is bereik. Probeer weer."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Gesiguittelling is bereik. Probeer weer."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Gesig kan nie geberg word nie."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Gesighandeling is gekanselleer."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Te veel pogings. Probeer later weer."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Te veel pogings. Gesigstawingsensor is gedeaktiveer."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Probeer weer."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Kleurkorreksie"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Toeganklikheidskortpad het <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aangeskakel"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Toeganklikheidskortpad het <xliff:g id="SERVICE_NAME">%1$s</xliff:g> afgeskakel"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gebruik weer toeganklikheidskortpad om die huidige toeganklikheidskenmerk te begin"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Kies \'n kenmerk om te gebruik wanneer jy op die Toeganklikheid-knoppie tik:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Raak en hou die Toeganklikheid-knoppie om kenmerke te verander."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Vergroting"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 45f962b..3cd1b50 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"ከእርስዎ አገልግሎት አቅራቢ ጋር የWi‑Fi ጥሪን በማስመዝገብ ላይ ችግር፦ <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"የ%s Wi-Fi ጥሪ"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> የWi-Fi ጥሪ አደራረግ"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"የWLAN ጥሪ"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> የWLAN ጥሪ"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"የWiFi ጥሪ አደራረግ | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"ጠፍቷል"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi ተመርጧል"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"የተንቀሳቃሽ ስልክ ተመራጭ ነው"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"አልታወቀም"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"የጣት አሻራ ትክክለኛነት ተረጋግጧል"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"የጣት አሻራ ሃርድዌር አይገኝም።"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"የጣት አሻራ ሊከማች አይችልም። እባክዎ አሁን ያለውን የጣት አሻራ ያስወግዱ።"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"የጣት አሻራ ማብቂያ ጊዜ ደርሷል። እንደገና ይሞክሩ።"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"የፊት ማብቂያ ጊዜ ደርሷል። እንደገና ይሞክሩ።"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"ፊት ሊከማች አይችልም።"</string>
<string name="face_error_canceled" msgid="283945501061931023">"የፊት ሥርዓተ ክወና ተሰርዟል።"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"ከልክ በላይ ብዙ ሙከራዎች። በኋላ ላይ እንደገና ይሞክሩ።"</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"በጣም ብዙ ሙከራዎች። የፊት ማረጋገጫ ተሰናክሏል።"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"እንደገና ይሞክሩ።"</string>
@@ -868,7 +878,7 @@
<string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"በፊት መክፈት።"</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"በፒን መክፈት።"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="9149698847116962307">"የሲም ፒን ክፈት።"</string>
- <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"የሲም ፒዩኬ ክፈት።"</string>
+ <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"የሲም PUK ክፈት።"</string>
<string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"በይለፍ ቃል መክፈት።"</string>
<string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"የስርዓተ-ጥለት አካባቢ።"</string>
<string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"የማንሸራተቻ አካባቢ።"</string>
@@ -1582,7 +1592,7 @@
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"ሲም ካርዱን በመክፈት ላይ…"</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"ትክክል ያልሆነ ፒን ኮድ።"</string>
<string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"ከ4 እስከ 8 ቁጥሮች የያዘ ፒን ይተይቡ።"</string>
- <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"የፒዩኬ ኮድ 8 ቁጥሮች ነው መሆን ያለበት።"</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"የPUK ኮድ 8 ቁጥሮች ነው መሆን ያለበት።"</string>
<string name="kg_invalid_puk" msgid="3638289409676051243">"ትክክለኛውን የPUK ኮድ እንደገና ያስገቡ። ተደጋጋሚ ሙከራዎች ሲም ካርዱን እስከመጨረሻው ያሰናክሉታል።"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ፒን ኮዶች አይገጣጠሙም"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"በጣም ብዙ የስርዓተ ጥለት ሙከራዎች"</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"የቀለም ማስተካከያ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"የተደራሽነት አቋራጭ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን አብርቶታል"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"የተደራሽነት አቋራጭ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን አጥፍቶታል"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"አሁን ያለውን የተደራሽነት ባህሪ ለመጀመር እንደገና የተደራሽነት አቋራጭን ይጠቀሙ"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"የተደራሽነት አዝራርን መታ በሚያደርጉበት ጊዜ ጥቅም ላይ የሚውለውን ባህሪ ይምረጡ፦"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ባህሪያትን ለመለወጥ የተደራሽነት አዝራሩን ይንኩ እና ይያዙት።"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ማጉላት"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index bbdea6a..cf3b035 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -132,10 +132,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"حدثت مشكلة أثناء تسجيل الاتصال عبر Wi‑Fi باستخدام مشغِّل شبكة الجوّال: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s الاتصال عبر Wi-Fi"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"الاتصال عبر شبكة Wi-Fi التابعة لـ <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"مكالمة عبر شبكة WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"مكالمة عبر شبكة WLAN التابعة لـ <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"شبكة Wi-Fi التابعة لـ <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"الاتصال عبر شبكة WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"شبكة VoWifi التابعة لـ <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"إيقاف"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"شبكة Wi-Fi مفضّلة"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"شبكة بيانات الجوال مفضَّلة"</string>
@@ -536,6 +540,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"لم يتم التعرف عليها."</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"تم مصادقة بصمة الإصبع"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"جهاز بصمة الإصبع غير متاح."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"يتعذر تخزين بصمة الإصبع؛ يرجى إزالة إحدى البصمات المخزنة."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"تم بلوغ مهلة إدخال بصمة الإصبع. أعد المحاولة."</string>
@@ -572,6 +580,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"انتهت مهلة التعرُّف على الوجه. أعِد المحاولة."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"يتعذَّر حفظ الوجه."</string>
<string name="face_error_canceled" msgid="283945501061931023">"تمّ إلغاء عملية مصادقة الوجه."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"تمّ إجراء محاولات كثيرة. أعِد المحاولة لاحقًا."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"تمّ إجراء محاولات كثيرة. ميزة مصادقة الوجه متوقفة."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"يُرجى إعادة المحاولة."</string>
@@ -1712,6 +1722,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"تصحيح الألوان"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"شغَّل اختصار إمكانية الوصول خدمة <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"أوقف اختصار إمكانية الوصول خدمة <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"استخدِم اختصار إمكانية الوصول لبدء ميزة إمكانية الوصول الحالية."</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"يمكنك اختيار إحدى الميزات لاستخدامها عند النقر على زر إمكانية الوصول:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"لتغيير الميزات، يمكنك لمس زر \"إمكانية الوصول\" مع الاستمرار."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"التكبير"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 48d44b0..9974867 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"আপোনাৰ বাহকৰ ওচৰত ৱাই-ফাই কলিং সুবিধা পঞ্জীয়ন কৰাত সমস্যাৰ উদ্ভৱ হৈছে: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s ৱাই- ফাই কলিং"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> ৱাই- ফাই কলিং"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN কল"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN কল"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> ৱাই-ফাই"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"ৱাই- ফাই কলিং | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"অফ হৈ আছে"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ৱাই-ফাইক অগ্ৰাধিকাৰ দিয়া হৈছে"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ম\'বাইলক অগ্ৰাধিকাৰ দিয়া হৈছে"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"চিনাক্ত কৰিব পৰা নাই"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ফিংগাৰপ্ৰিণ্টৰ সত্যাপন কৰা হ’ল"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ফিংগাৰপ্ৰিণ্ট হাৰ্ডৱেৰ নাই।"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ফিংগাৰপ্ৰিণ্ট সঞ্চয় কৰিব পৰা নগ\'ল। পূর্বে সঞ্চিত ফিংগাৰপ্ৰিণ্ট এটা আঁতৰাওক।"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"ফিংগাৰপ্ৰিণ্ট গ্ৰহণৰ সময়সীমা উকলি গৈছে। আকৌ চেষ্টা কৰক।"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"মুখমণ্ডল গ্ৰহণৰ সময়সীমা উকলি গৈছে। আকৌ চেষ্টা কৰক।"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"মুখমণ্ডল সঞ্চয় কৰিব নোৱাৰি।"</string>
<string name="face_error_canceled" msgid="283945501061931023">"মুখমণ্ডলৰ প্ৰক্ৰিয়া বাতিল কৰা হ’ল।"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"অত্যধিক ভুল প্ৰয়াস। কিছুসময়ৰ পাছত আকৌ চেষ্টা কৰক।"</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"অত্যধিক প্ৰয়াস। মুখমণ্ডলৰ জৰিয়তে সত্যাপন অক্ষম কৰা হ’ল।"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"আকৌ চেষ্টা কৰক।"</string>
@@ -1404,7 +1414,7 @@
<string name="forward_intent_to_work" msgid="621480743856004612">"আপুনি আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলৰ ভিতৰত এই এপটো ব্যৱহাৰ কৰি আছে"</string>
<string name="input_method_binding_label" msgid="1283557179944992649">"ইনপুট পদ্ধতি"</string>
<string name="sync_binding_label" msgid="3687969138375092423">"ছিংক"</string>
- <string name="accessibility_binding_label" msgid="4148120742096474641">"সাধ্য় সুবিধাসমূহ"</string>
+ <string name="accessibility_binding_label" msgid="4148120742096474641">"সাধ্য সুবিধাসমূহ"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"ৱালপেপাৰ"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"ৱালপেপাৰ সলনি কৰক"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"জাননী নিৰীক্ষক"</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"ৰং শুধৰণী"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাটটোৱে <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ক অন কৰিছে"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাটটোৱে <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ক অফ কৰিছে"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"বর্তমানৰ সাধ্য সুবিধাসমূহৰ আৰম্ভ কৰিবলৈ সাধ্য সুবিধাসমূহৰ শ্বৰ্টকাট পুনৰ ব্যৱহাৰ কৰক"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"আপুনি দিব্যাংগসকলৰ সুবিধাৰ বুটামটো টিপিলে ব্যৱহাৰ কৰিবলগীয়া কোনো সুবিধা বাছক:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"সুবিধাসমূহ সলনি কৰিবলৈ দিব্যাংগসকলৰ সুবিধাৰ বুটামটো স্পৰ্শ কৰি থাকক।"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"বিবৰ্ধন"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 44bcd56..3236b52 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Operatorla Wi‑Fi zənglərini qeydə alarkən xəta baş verdi: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi Zəngi"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi Zəngi"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN Zəngi"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN Zəngi"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi Zəngi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Deaktiv"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi tərcih edilir"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobil tərcih"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Tanınmır"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Barmaq izi doğrulandı"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Barmaq izi üçün avadanlıq yoxdur."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Barmaq izi saxlana bilməz. Lütfən, mövcud barmaq izini silin."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Barmaq izinin vaxtı başa çatdı. Yenidən cəhd edin."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Üz proqramı taymerinin vaxtı bitdi. Yenidən cəhd edin."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Üz bərpa edilmədi."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Üz əməliyyatı ləğv edildi."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Həddindən çox cəhd. Sonraya saxlayın."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Həddindən çox cəhd. Üz identifikasiyası deaktiv edildi."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Yenidən cəhd edin."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Rəng korreksiyası"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Əlçatımlıq Qısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> xidmətini aktiv etdi"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Əlçatımlıq Qısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> xidmətini deaktiv etdi"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Cari əlçatımlılıq funksiyasını yenidən başlatmaq üçün Əlçatımlılıq Qısayolundan istifadə edin"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Əlçatımlılıq düyməsinə kliklədikdə istifadə etmək üçün funksiya seçin:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Funksiyaları dəyişmək üçün Əlçatımlılıq düyməsinə basıb saxlayın."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Böyütmə"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 260f63e..2bbf9b2 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -129,10 +129,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Problem u vezi sa registrovanjem pozivanja preko Wi‑Fi-ja kod mobilnog operatera: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Wi-Fi pozivanje preko operatera %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> pozivanje preko Wi-Fi-ja"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN poziv"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN poziv"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Pozivanje preko Wi-Fi-ja | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Isključeno"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Prednost ima Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Želim mobilne podatke"</string>
@@ -527,6 +531,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Nije prepoznato"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Otisak prsta je potvrđen"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otiske prstiju nije dostupan."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Nije moguće sačuvati otisak prsta. Uklonite neki od postojećih otisaka prstiju."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vremensko ograničenje za otisak prsta je isteklo. Probajte ponovo."</string>
@@ -563,6 +571,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Isteklo je vreme za proveru lica. Probajte ponovo."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Nije moguće sačuvati lice."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Obrada lica je otkazana."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Previše pokušaja. Probajte ponovo kasnije."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Više pokušaja. Potvrda identiteta je onemogućena."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Probajte ponovo."</string>
@@ -1640,6 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Korekcija boja"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečica za pristupačnost je uključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečica za pristupačnost je isključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Upotrebite ponovo prečicu za pristupačnost da biste pokrenuli aktuelnu funkciju pristupačnosti"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Izaberite funkciju koja će se koristiti kada dodirnete dugme za pristupačnost:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Pritisnite i zadržite dugme za pristupačnost da biste menjali funkcije."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Uvećanje"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 3d46662..0ec976f 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -130,10 +130,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Памылка падключэння Wi‑Fi-тэлефаніі ў вашага аператара: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Wi-Fi-тэлефанія %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Wi-Fi-тэлефанія ад <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Выклік праз WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Выклік праз WLAN ад <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi ад <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi-тэлефанія | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWi-Fi ад <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Выкл."</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Прыярытэт Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Прыярытэт мабільнай сеткі"</string>
@@ -530,6 +534,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Не распазнана"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Адбітак пальца распазнаны"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Апаратныя сродкі адбіткаў пальцаў недаступныя."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Адбіткі пальцаў нельга захаваць. Выдаліце існы адбітак."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Час чакання адбіткаў пальцаў выйшаў. Паспрабуйце яшчэ раз."</string>
@@ -566,6 +574,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Час чакання твару выйшаў. Паўтарыце спробу."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Не ўдалося захаваць твар."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Распазнаванне твару скасавана."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Занадта шмат спроб. Паўтарыце спробу пазней."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Занадта шмат спроб. Аўтэнтыфікацыя твару адключана"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Паўтарыце спробу."</string>
@@ -1664,6 +1674,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Карэкцыя колеру"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> быў уключаны з дапамогай камбінацыі хуткага доступу для спецыяльных магчымасцей"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> быў адключаны з дапамогай камбінацыі хуткага доступу для спецыяльных магчымасцей"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Каб запусціць функцыю спецыяльных магчымасцей, паўторна скарыстайце ярлык спецыяльных магчымасцей"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Выберыце функцыю для выкарыстання пры націску кнопкі \"Спецыяльныя магчымасці\":"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Каб змяняць функцыі, краніце і ўтрымлівайце кнопку \"Спецыяльныя магчымасці\"."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Павелічэнне"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index e9ecba6..3af930f 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"При регистрирането на функцията за обаждания през Wi-Fi с оператора ви възникна грешка: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s – обаждания през Wi-Fi"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Обаждания през Wi-Fi от <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Обаждане през WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Обаждане през WLAN от <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi от <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Обаждания през Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWi-Fi от <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Изключено"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Предпочита се Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Предпочитат се мобилни данни"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Не е разпознато"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Отпечатъкът е удостоверен"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хардуерът за отпечатъци не е налице."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Отпечатъкът не може да бъде съхранен. Моля, премахнете съществуващ."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Времето за изчакване за отпечатък изтече. Опитайте отново."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Времето за изчакване изтече. Опитайте отново."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Лицето не може да бъде съхранено."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Операцията с лице е анулирана."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Твърде много опити. Опитайте отново по-късно."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Твърде много опити. Удост. с лице е деактивирано."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Опитайте отново."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Коригиране на цветовете"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Прекият път за достъпност включи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Прекият път за достъпност изключи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Използвайте отново прекия път към функцията за достъпност, за да стартирате текущата"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Изберете функция, която да използвате, когато докоснете бутона за достъпност:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"За да промените функции, докоснете и задръжте бутона за достъпност."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ниво на мащаба"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 4ece21b..301bcc0 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"পরিষেবা প্রদানকারীতে ওয়াই-ফাই কলিং রেজিস্টার করতে সমস্যা হয়েছে: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s ওয়াই-ফাই কলিং"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> ওয়াই-ফাই কলিং"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN কল"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN কল"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> ওয়াই-ফাই"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"ওয়াই-ফাই কলিং | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"বন্ধ আছে"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"পছন্দের ওয়াই-ফাই"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"পছন্দের মোবাইল"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"স্বীকৃত নয়"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"আঙ্গুলের ছাপ যাচাই করা হয়েছে"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"আঙ্গুলের ছাপ নেওয়ার হার্ডওয়্যার অনুপলব্ধ৷"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"আঙ্গুলের ছাপ সংরক্ষণ করা যাবে না৷ অনুগ্রহ করে একটি বিদ্যমান আঙ্গুলের ছাপ সরান৷"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"আঙ্গুলের ছাপ নেওয়ার সময়সীমা শেষ হযেছে৷ আবার চেষ্টা করুন৷"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"ফেসের ছাপ নেওয়ার সময়সীমা শেষ৷ আবার চেষ্টা করুন৷"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"ফেস স্টোর করা যাবে না।"</string>
<string name="face_error_canceled" msgid="283945501061931023">"ফেস অপারেশন বাতিল করা হয়েছে৷"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"অনেকবার চেষ্টা করা হয়েছে। পরে আবার চেষ্টা করুন।"</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"অনেকবার চেষ্টা করা হয়েছে৷ ফেস যাচাইকরণ বন্ধ আছে।"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"আবার চেষ্টা করুন।"</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"রঙ সংশোধন"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"অ্যাক্সেসযোগ্যতা শর্টকাট <xliff:g id="SERVICE_NAME">%1$s</xliff:g> কে চালু করেছে"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"অ্যাক্সেসযোগ্যতা শর্টকাট <xliff:g id="SERVICE_NAME">%1$s</xliff:g> কে বন্ধ করেছে"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"বর্তমান অ্যাক্সেসিবিলিটি বৈশিষ্ট্য শুরু করার জন্য অ্যাক্সেসিবিলিটি শর্টকাটটি আবার ব্যবহার করুন"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"অ্যাক্সেসযোগ্যতা বোতামের সাহায্যে যে বৈশিষ্ট্যটি নিয়ন্ত্রণ করতে চান, সেটি বেছে নিন:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"বৈশিষ্ট্যগুলি পরিবর্তন করতে অ্যাক্সেসযোগ্যতা বোতামটি ট্যাপ করে ধরে রাখুন।"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"বড় করে দেখা"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 918ecf9..e6fde5b 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -129,10 +129,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Došlo je do problema prilikom registracije pozivanja putem WiFi mreže kod vašeg operatera: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Pozivanje putem WiFi-ja preko operatera %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Pozivanje putem WiFi-ja"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN poziv"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN poziv"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> WiFi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Pozivanje putem WiFi-ja | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Isključeno"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Preferira se WiFi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferira se mobilna mreža"</string>
@@ -527,6 +531,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Nije prepoznato"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Otisak prsta je potvrđen"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otisak prsta nije dostupan."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Otisak prsta se ne može pohraniti. Uklonite postojeći otisak prsta."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vrijeme za prepoznavanje otiska prsta je isteklo. Pokušajte ponovo."</string>
@@ -563,6 +571,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Vrijeme za prepoznavanje lica je isteklo. Pokušajte ponovo."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Nije moguće pohraniti lice."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Prepoznavanje lica je otkazano."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Previše pokušaja. Autentifikacija lica onemogućena."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Pokušajte ponovo."</string>
@@ -1642,6 +1652,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Ispravka boja"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečica za pristupačnost je uključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečica za pristupačnost je isključila uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Ponovo koristite Prečicu za pristupačnost da započnete trenutnu funkciju pristupačnosti"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Odaberite funkciju koja će se koristiti kada dodirnete dugme Pristupačnost:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Da promijenite funkcije, dodirnite i držite dugme Pristupačnost."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Uvećanje"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index f6c46ba..9318715 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Hi ha hagut un problema en registrar les trucades per Wi-Fi amb el teu operador de telefonia mòbil: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Trucades per Wi-Fi %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Trucades per Wi‑Fi (<xliff:g id="SPN">%s</xliff:g>)"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Trucada per WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Trucada per WLAN (<xliff:g id="SPN">%s</xliff:g>)"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi‑Fi (<xliff:g id="SPN">%s</xliff:g>)"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Trucades per Wi‑Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi (<xliff:g id="SPN">%s</xliff:g>)"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desactivat"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Preferència per la Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferència per dades mòbils"</string>
@@ -295,7 +299,7 @@
<string name="permgroupdesc_calllog" msgid="3006237336748283775">"llegir i editar el registre de trucades del telèfon"</string>
<string name="permgrouprequest_calllog" msgid="8487355309583773267">"Vols permetre que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> accedeixi als registres de trucades del telèfon?"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"Telèfon"</string>
- <string name="permgroupdesc_phone" msgid="6234224354060641055">"fer i gestionar trucades telefòniques"</string>
+ <string name="permgroupdesc_phone" msgid="6234224354060641055">"fer i gestionar trucades"</string>
<string name="permgrouprequest_phone" msgid="9166979577750581037">"Vols permetre que <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> faci trucades i les gestioni?"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Sensors corporals"</string>
<string name="permgroupdesc_sensors" msgid="7147968539346634043">"accedir a les dades del sensor sobre els signes vitals"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"No s\'ha reconegut"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"L\'empremta digital s\'ha autenticat"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"El maquinari per a empremtes digitals no està disponible."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"L\'empremta digital no es pot desar. Suprimeix-ne una."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"S\'ha esgotat el temps d\'espera per a l\'empremta digital. Torna-ho a provar."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"S\'ha esgotat el temps d\'espera. Torna-ho a provar."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"La cara no es pot desar."</string>
<string name="face_error_canceled" msgid="283945501061931023">"S\'ha cancel·lat el reconeixement facial."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Massa intents. Torna-ho a provar més tard."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Massa intents. Autenticació facial desactivada."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Torna-ho a provar."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Correcció del color"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"La drecera d\'accessibilitat ha activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"La drecera d\'accessibilitat ha desactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Torna a utilitzar la drecera d\'accessibilitat per iniciar la funció d\'accessibilitat actual"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Tria la funció que s\'utilitzarà quan toquis el botó Accessibilitat:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Per canviar les funcions, toca i mantén premut el botó Accessibilitat."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliació"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index e882f42..45c57d0 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -130,10 +130,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Při registraci volání přes Wi-Fi u operátora <xliff:g id="CODE">%1$s</xliff:g> došlo k chybě"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Volání přes Wi-Fi: %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g>: volání přes Wi-Fi"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Volání přes WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g>: volání přes WLAN"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g>: Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Volání přes Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g>: VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Vypnuto"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Preferována síť W-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferována mobilní data"</string>
@@ -530,6 +534,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Nerozpoznáno"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Otisk byl ověřen"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Není k dispozici hardware ke snímání otisků prstů."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Otisk prstu nelze uložit. Odstraňte existující otisk prstu."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Časový limit sejmutí otisku prstu vypršel. Zkuste to znovu."</string>
@@ -566,6 +574,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Limit ověření obličeje vypršel. Zkuste to znovu."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Obličej nelze uložit."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Operace snímání obličeje byla zrušena."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Příliš mnoho pokusů. Zkuste to později."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Příliš mnoho pokusů. Ověření obličeje je zakázáno."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Zkuste to znovu."</string>
@@ -1664,6 +1674,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Oprava barev"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Zkratka přístupnosti zapnula službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Zkratka přístupnosti vypnula službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Znovu použijte zkratku přístupnosti, čímž spustíte aktuální funkci pro usnadnění přístupu"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Určete, jakou funkci aktivujete klepnutím na tlačítko Přístupnost:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Chcete-li vybrat jinou funkci, podržte tlačítko Přístupnost."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Zvětšení"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 9a793a8..f279f0b 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Der opstod et problem under registrering af Wi-Fi-opkald hos dit mobilselskab: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi-opkald"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Wi-Fi-opkald via <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-opkald"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"WLAN-opkald via <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi via <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi-opkald | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi via <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Fra"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"WiFi-netværk er foretrukket"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobildata foretrækkes"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Ikke genkendt"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingeraftrykket blev godkendt"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardwaren til fingeraftryk er ikke tilgængelig."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingeraftrykket kan ikke gemmes. Fjern et eksisterende fingeraftryk."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Registrering af fingeraftryk fik timeout. Prøv igen."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Ansigtsgenkendelse fik timeout. Prøv igen."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Ansigtet kan ikke gemmes."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Ansigtshandlingen blev annulleret."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Du har prøvet for mange gange. Prøv igen senere."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"For mange forsøg – Ansigtsgenkendelse deaktiveret."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Prøv igen."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Korriger farve"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Genvejen til hjælpefunktioner aktiverede <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Genvejen til hjælpefunktioner deaktiverede <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Brug Genvej til hjælpefunktioner for at starte den aktuelle hjælpefunktion"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Vælg, hvilken funktion du vil bruge, når du trykker på knappen Hjælpefunktioner:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Tryk på knappen Hjælpefunktioner, og hold fingeren nede for at skifte funktioner."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Forstørrelse"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 8eb0eb8..7ec4401 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Probleme beim Registrieren der WLAN-Telefonie bei deinem Mobilfunkanbieter: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s WLAN-Telefonie"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> WLAN-Telefonie"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-Anruf"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN-Anruf"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> WLAN"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WLAN-Telefonie | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWLAN"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Aus"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"WLAN bevorzugt"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobilverbindung bevorzugt"</string>
@@ -150,7 +154,7 @@
<string name="httpErrorAuth" msgid="1435065629438044534">"Bei der Authentifizierung ist ein Fehler aufgetreten."</string>
<string name="httpErrorProxyAuth" msgid="1788207010559081331">"Authentifizierung via Proxyserver ist fehlgeschlagen."</string>
<string name="httpErrorConnect" msgid="8714273236364640549">"Verbindung zum Server konnte nicht hergestellt werden."</string>
- <string name="httpErrorIO" msgid="2340558197489302188">"Kommunikation mit dem Server konnte nicht hergestellt werden. Bitte versuche es später erneut."</string>
+ <string name="httpErrorIO" msgid="2340558197489302188">"Kommunikation mit dem Server konnte nicht hergestellt werden. Bitte versuche es später noch einmal."</string>
<string name="httpErrorTimeout" msgid="4743403703762883954">"Zeitüberschreitung bei Serververbindung."</string>
<string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Die Seite enthält zu viele Server-Redirects."</string>
<string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Das Protokoll wird nicht unterstützt."</string>
@@ -158,7 +162,7 @@
<string name="httpErrorBadUrl" msgid="3636929722728881972">"Die Seite kann nicht geöffnet werden, weil die URL ungültig ist."</string>
<string name="httpErrorFile" msgid="2170788515052558676">"Auf die Datei konnte nicht zugegriffen werden."</string>
<string name="httpErrorFileNotFound" msgid="6203856612042655084">"Die angeforderte Datei wurde nicht gefunden."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Es werden zurzeit zu viele Anfragen verarbeitet. Versuche es später erneut."</string>
+ <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Es werden zurzeit zu viele Anfragen verarbeitet. Bitte versuche es später noch einmal."</string>
<string name="notification_title" msgid="8967710025036163822">"Fehler bei Anmeldung für <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
<string name="contentServiceSync" msgid="8353523060269335667">"Synchronisierung"</string>
<string name="contentServiceSyncNotificationTitle" msgid="7036196943673524858">"Synchronisierung nicht möglich"</string>
@@ -515,23 +519,27 @@
<string name="permlab_mediaLocation" msgid="8675148183726247864">"Standorte aus meiner Mediensammlung abrufen"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Ermöglicht der App, Standorte aus deiner Mediensammlung abzurufen."</string>
<string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Biometrische Hardware nicht verfügbar"</string>
- <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Fingerabdruck teilweise erkannt. Versuche es erneut."</string>
- <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Fingerabdruck konnte nicht verarbeitet werden. Versuche es erneut."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingerabdrucksensor ist verschmutzt. Reinige ihn und versuche es erneut."</string>
- <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Finger zu schnell bewegt. Versuche es erneut."</string>
- <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Finger zu langsam bewegt. Versuche es erneut."</string>
+ <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Fingerabdruck teilweise erkannt. Bitte versuche es noch einmal."</string>
+ <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Fingerabdruck konnte nicht verarbeitet werden. Bitte versuche es noch einmal."</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Fingerabdrucksensor ist verschmutzt. Reinige ihn und versuche es noch einmal."</string>
+ <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Finger zu schnell bewegt. Bitte versuche es noch einmal."</string>
+ <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Finger zu langsam bewegt. Bitte versuche es noch einmal."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Nicht erkannt"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerabdruck wurde authentifiziert"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerabdruckhardware nicht verfügbar"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerabdruck kann nicht gespeichert werden. Entferne einen vorhandenen Fingerabdruck."</string>
- <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Zeitüberschreitung für Fingerabdruck. Versuche es erneut."</string>
+ <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Zeitüberschreitung für Fingerabdruck. Bitte versuche es noch einmal."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Fingerabdruckvorgang abgebrochen"</string>
<string name="fingerprint_error_user_canceled" msgid="7999639584615291494">"Vorgang der Fingerabdruckauthentifizierung vom Nutzer abgebrochen."</string>
- <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Zu viele Versuche. Versuche es später erneut."</string>
+ <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Zu viele Versuche. Bitte versuche es später noch einmal."</string>
<string name="fingerprint_error_lockout_permanent" msgid="5033251797919508137">"Zu viele Versuche. Der Fingerabdrucksensor wurde deaktiviert."</string>
- <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Bitte versuche es erneut."</string>
+ <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Bitte versuche es noch einmal."</string>
<string name="fingerprint_error_no_fingerprints" msgid="7654382120628334248">"Keine Fingerabdrücke erfasst."</string>
<string name="fingerprint_error_hw_not_present" msgid="5729436878065119329">"Dieses Gerät hat keinen Fingerabdrucksensor"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Zeitüberschreitung für Gesicht. Versuch es erneut."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Gesicht kann nicht gespeichert werden."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Gesichtserkennung abgebrochen."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Zu viele Versuche. Versuch es später noch einmal."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Zu viele Versuche. Gesichtserkennung deaktiviert."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Versuch es noch einmal."</string>
@@ -1085,7 +1095,7 @@
<string name="view_flight" msgid="7691640491425680214">"Verfolgen"</string>
<string name="view_flight_desc" msgid="3876322502674253506">"Ausgewählten Flug verfolgen"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der Speicherplatz wird knapp"</string>
- <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Einige Systemfunktionen funktionieren möglicherweise nicht."</string>
+ <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Einige Systemfunktionen funktionieren eventuell nicht."</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Der Speicherplatz reicht nicht für das System aus. Stelle sicher, dass 250 MB freier Speicherplatz vorhanden sind, und starte das Gerät dann neu."</string>
<string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> wird ausgeführt"</string>
<string name="app_running_notification_text" msgid="1197581823314971177">"Für weitere Informationen oder zum Beenden der App tippen."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Farbkorrektur"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> wurde durch die Bedienungshilfenverknüpfung aktiviert"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> wurde durch die Bedienungshilfenverknüpfung deaktiviert"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Verwende noch einmal die Verknüpfung für Bedienungshilfen, um die aktuelle Bedienungshilfe zu starten."</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Wähle eine Funktion aus, die verwendet wird, wenn du auf die Schaltfläche für die Bedienungshilfen tippst:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Um die Funktionen zu ändern, halte die Schaltfläche für die Bedienungshilfen gedrückt."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Vergrößerung"</string>
@@ -1723,7 +1734,7 @@
<string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Neue PIN"</string>
<string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Neue PIN bestätigen"</string>
<string name="restr_pin_create_pin" msgid="8017600000263450337">"PIN für das Ändern von Einschränkungen erstellen"</string>
- <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Die PINs stimmen nicht überein. Bitte versuche es erneut."</string>
+ <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Die PINs stimmen nicht überein. Bitte versuche es noch einmal."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"Die PIN ist zu kurz. Sie muss mindestens 4 Ziffern umfassen."</string>
<plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
<item quantity="other">In <xliff:g id="COUNT">%d</xliff:g> Sek. wiederholen</item>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 3a50f9e..f2309e8 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Παρουσιάστηκε πρόβλημα με την εγγραφή της κλήσης Wi‑Fi με την εταιρεία κινητής τηλεφωνίας: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Κλήση Wi-Fi"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Κλήση Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Κλήση μέσω WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Κλήση μέσω WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Κλήση Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Ανενεργό"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Προτίμηση Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Προτίμηση δικτύου κινητής τηλεφωνίας"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Δεν αναγνωρίστηκε"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Η ταυτότητα του δακτυλικού αποτυπώματος ελέγχθηκε"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Ο εξοπλισμός μοναδικού χαρακτηριστικού δεν είναι διαθέσιμος."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Δεν είναι δυνατή η αποθήκευση μοναδικού χαρακτηριστικού. Καταργήστε το υπάρχον μοναδικό χαρακτηριστικό."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Λήξη χρονικού ορίου μοναδικού χαρακτηριστικού. Δοκιμάστε ξανά."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Λήξη χρονικού ορίου προσώπου. Δοκιμάστε ξανά."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Δεν είναι δυνατή η αποθήκευση του προσώπου."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Η ενέργεια προσώπου ακυρώθηκε."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Πάρα πολλές προσπάθειες. Δοκιμάστε ξανά αργότερα."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Πολλές προσπάθειες. Αποτυχία ελέγ. ταυτ. προσώπου."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Δοκιμάστε ξανά."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Διόρθωση χρωμάτων"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Η συντόμευση προσβασιμότητας ενεργοποίησε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Η συντόμευση προσβασιμότητας απενεργοποίησε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Χρησιμοποιήστε τη Συντόμευση προσβασιμότητας ξανά, για να ξεκινήσετε την τρέχουσα λειτουργία προσβασιμότητας"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Επιλέξτε μια λειτουργία που θα χρησιμοποιείται κατά το πάτημα του κουμπιού \"Προσβασιμότητα\"."</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Για να αλλάξετε λειτουργίες, αγγίξτε παρατεταμένα το κουμπί \"Προσβασιμότητα\"."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Μεγιστοποίηση"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 04b20ba..1eeb1c3 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Issue registering Wi‑Fi calling with your operator: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi Calling"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi Calling"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN call"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN Call"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi Calling | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Off"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferred"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobile preferred"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint timeout reached. Try again."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Face operation cancelled."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Colour Correction"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch & hold the Accessibility button."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index c1ca0c4..699e50f 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Issue registering Wi‑Fi calling with your operator: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi Calling"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi Calling"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN call"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN Call"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi Calling | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Off"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferred"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobile preferred"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint timeout reached. Try again."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Face operation cancelled."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Colour Correction"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch & hold the Accessibility button."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 04b20ba..1eeb1c3 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Issue registering Wi‑Fi calling with your operator: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi Calling"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi Calling"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN call"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN Call"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi Calling | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Off"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferred"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobile preferred"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint timeout reached. Try again."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Face operation cancelled."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Colour Correction"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch & hold the Accessibility button."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 04b20ba..1eeb1c3 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Issue registering Wi‑Fi calling with your operator: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi Calling"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi Calling"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN call"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN Call"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi Calling | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Off"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferred"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobile preferred"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognised"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint timeout reached. Try again."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Face operation cancelled."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Colour Correction"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch & hold the Accessibility button."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 4add775..63726f8 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Issue registering Wi‑Fi calling with your carrier: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi Calling"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi Calling"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN Call"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN Call"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi Calling | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Off"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferred"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobile preferred"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Not recognized"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingerprint authenticated"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingerprint hardware not available."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingerprint can\'t be stored. Please remove an existing fingerprint."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint time out reached. Try again."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Face time out reached. Try again."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Face can’t be stored."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Face operation canceled."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Too many attempts. Try again later."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Too many attempts. Facial authentication disabled."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Try again."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Color Correction"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use Accessibility Shortcut again to start the current accessibility feature"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choose a feature to use when you tap the Accessibility button:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"To change features, touch & hold the Accessibility button."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Magnification"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index f317a4e..6a49e03 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Error al registrar la Llamada con Wi‑Fi con tu operador: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Llamada por Wi-Fi de %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Llamada por Wi-Fi de <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Llamada por WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Llamada por WLAN de <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi de <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Llamada por Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi de <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desactivada"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Red Wi-Fi preferida"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Red móvil preferida"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"No se reconoció"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Se autenticó la huella digital"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"El hardware para detectar huellas digitales no está disponible."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"No se puede almacenar la huella digital. Elimina una de las existentes."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Finalizó el tiempo de espera para la huella digital. Vuelve a intentarlo."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Se agotó el tiempo. Vuelve a intentarlo."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"No se puede almacenar el rostro."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Se canceló el reconocimiento facial."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Demasiados intentos. Inténtalo de nuevo más tarde."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Demasiados intentos. Autent. facial inhabilitada."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Vuelve a intentarlo."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Corrección de color"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"El acceso directo de accesibilidad activó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"El acceso directo de accesibilidad desactivó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Vuelve a usar el acceso directo de accesibilidad para iniciar la función de accesibilidad actual"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Elige una función para usar cuando presionas el botón Accesibilidad:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para cambiar funciones, mantén presionado el botón Accesibilidad."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliación"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index c42f53c..b62f4c9 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"No se ha podido registrar la llamada por Wi‑Fi con tu operador: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Llamadas Wi-Fi de %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Llamada por Wi‑Fi de <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Llamada por WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Llamada por WLAN de <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi‑Fi de <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Llamada por Wi‑Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWiFi de <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desactivado"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Dar preferencia a Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferir datos móviles"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"No se reconoce"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Se ha autenticado la huella digital"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"El hardware de huella digital no está disponible."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"No se puede almacenar la huella digital. Elimina una ya creada."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Se ha alcanzado el tiempo de espera de la huella digital. Vuelve a intentarlo."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Has sobrepasado el tiempo. Inténtalo de nuevo."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"No se pueden registrar más caras."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Se ha cancelado el reconocimiento facial."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Demasiados intentos. Inténtalo de nuevo más tarde."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Demasiados intentos. Autent. facial inhabilitada."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Inténtalo de nuevo."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Corrección de color"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"El acceso directo a accesibilidad ha activado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"El acceso directo a accesibilidad ha desactivado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Usa de nuevo la combinación de teclas de accesibilidad para iniciar la función de accesibilidad actual"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Selecciona la función que se utilizará cuando toques el botón Accesibilidad:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para cambiar las funciones, mantén pulsado el botón Accesibilidad."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliar"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index cc052c4..8f011f8 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Probleem WiFi-kõnede registreerimisel teie operaatoriga: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s WiFi kaudu helistamine"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g>: WiFi-kõned"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-kõne"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g>: WLAN-kõne"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g>: WiFi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi-kõne | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g>: VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Väljas"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"WiFi eelistusega"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Eelistatud on mobiilne andmeside"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Ei tuvastatud"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Sõrmejälg autenditi"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Sõrmejälje riistvara pole saadaval."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Sõrmejälge ei saa salvestada. Eemaldage olemasolev sõrmejälg."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Sõrmejälje riistvara taimeri ajalõpp. Proovige uuesti."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Näotuvastuse taimeri ajalõpp. Proovige uuesti."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Nägu ei saa salvestada."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Näotuvastuse toiming tühistati."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Liiga palju katseid. Proovige hiljem uuesti."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Liiga palju katseid. Näotuvastus on keelatud."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Proovige uuesti."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Värviparandus"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Juurdepääsetavuse otsetee lülitas teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> sisse"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Juurdepääsetavuse otsetee lülitas teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> välja"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Praeguse juurdepääsufunktsiooni käivitamiseks kasutage juurdpääsetavuse otseteed uuesti"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Valige, millist funktsiooni kasutada, kui vajutate nuppu Juurdepääsetavus:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Funktsioonide muutmiseks puudutage pikalt nuppu Juurdepääsetavus."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Suurendus"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 275e171..a070cc5 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Arazo bat izan da Wi‑Fi bidezko deiak zure operadorearekin erregistratzean: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi bidezko deiak"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi bidezko deiak"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN bidezko deia"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN bidezko deia"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi bidezko deiak | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desaktibatuta"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi sarea hobesten da"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Datu-konexioa hobesten da"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Ez da ezagutu"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Autentifikatu da hatz-marka"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hatz-markaren hardwarea ez dago erabilgarri."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Ezin da gorde hatz-marka digitala. Kendu lehendik gordeta duzunetako bat."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Hatz-marka digitalak prozesatzeko denbora-muga gainditu da. Saiatu berriro."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Gainditu da aurpegiak prozesatzeko denbora-muga. Saiatu berriro."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Ezin da gorde aurpegia."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Utzi da aurpegiaren bidezko eragiketa."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Saiakera gehiegi egin dituzu. Saiatu berriro geroago."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Saiakera gehiegi egin dituzu. Desgaitu egin da autentifikazioa."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Saiatu berriro."</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Koloreen zuzenketa"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Erabilerraztasun-lasterbideak <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktibatu du"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Erabilerraztasun-lasterbideak <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desaktibatu du"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Uneko erabilerraztasun-eginbidea abiarazteko, erabili erabilerraztasun-lasterbidea berriro"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Aukeratu zein eginbide erabili nahi duzun Erabilerraztasuna botoia sakatzean:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Eginbideak aldatzeko, eduki sakatuta Erabilerraztasuna botoia."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Lupa"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 5055e8b..3101b72 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"مشکل هنگام ثبت تماس ازطریق Wi‑Fi با شرکت مخابراتی: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"تماس %s Wi-Fi"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"تماس ازطریق Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"تماس ازطریق WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"تماس ازطریق WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"درحال تماس ازطریق WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"خاموش"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi ترجیحی"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"داده شبکه تلفن همراه ارجح است"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"شناسایی نشد"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"اثر انگشت احراز هویت شد"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"سختافزار اثرانگشت در دسترس نیست."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ذخیره اثر انگشت ممکن نیست. لطفاً یک اثر انگشت موجود را حذف کنید."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"مهلت زمانی ثبت اثر انگشت به پایان رسید. دوباره امتحان کنید."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"مهلت زمانی شناسایی چهره تمام شد. دوباره امتحان کنید"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"نمیتوان چهره را ذخیره کرد."</string>
<string name="face_error_canceled" msgid="283945501061931023">"عملیات شناسایی چهره لغو شد."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"تعداد زیادی تلاش ناموفق. بعداً دوباره امتحان کنید."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"چندین تلاش ناموفق. احراز هویت با چهره غیرفعال شد."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"دوباره امتحان کنید."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"تصحیح رنگ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"«میانبر دسترسپذیری» <xliff:g id="SERVICE_NAME">%1$s</xliff:g> را روشن کرد"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"«میانبر دسترسپذیری» <xliff:g id="SERVICE_NAME">%1$s</xliff:g> را خاموش کرد"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"برای راهاندازی ویژگی دسترسپذیری کنونی، دوباره از «میانبر دسترسپذیری» استفاده کنید"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"قابلیتی را انتخاب کنید که هنگام ضربه زدن روی دکمه «دسترسپذیری» استفاده میشود:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"برای تغییر دادن قابلیتها، دکمه «دسترسپذیری» را لمس کنید و نگهدارید."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"درشتنمایی"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index d54cb72..346992f 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Virhe otettaessa Wi-Fi-puheluita käyttöön operaattorille <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Wi-Fi-puhelut: %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Wi-Fi-puhelut (<xliff:g id="SPN">%s</xliff:g>)"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-puhelu"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"WLAN-puhelu (<xliff:g id="SPN">%s</xliff:g>)"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi-puhelut | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Ei käytössä"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi ensisijainen"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobiiliverkko ensisijainen"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Ei tunnistettu"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Sormenjälki tunnistettu"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Sormenjälkilaitteisto ei ole käytettävissä."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Sormenjälkeä ei voida tallentaa. Poista aiemmin lisätty sormenjälki."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Sormenjälkitunnistimen toiminta aikakatkaistiin. Yritä uudelleen."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Kasvotoiminto aikakatkaistiin. Yritä uudelleen."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Kasvoja ei voi tallentaa."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Kasvotoiminto peruutettu"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Liian monta yritystä. Yritä myöhemmin uudelleen."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Liikaa yrityksiä. Kasvojentodennus ei käytössä."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Yritä uudelleen."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Värinkorjaus"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> otettiin käyttöön esteettömyystilan pikanäppäimellä."</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> poistettiin käytöstä esteettömyystilan pikanäppäimellä."</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Valitse esteettömyystilan oikopolku uudelleen käynnistääksesi esteettömyysominaisuuden"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Valitse toiminto, jonka Esteettömyys-painike aktivoi:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Jos haluat muokata ominaisuuksia, kosketa Esteettömyys-painiketta pitkään."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Suurennus"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 0c0cdea..16fd62a 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Une erreur s\'est produite lors de l\'enregistrement des appels Wi-Fi avec votre fournisseur de services : <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Appels Wi-Fi %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Appels Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Appel WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Appel WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Appels Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"Voix par Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Désactivé"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Réseau Wi-Fi de préférence"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Connexion cellulaire de préférence"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Données biométriques non reconnues"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Empreinte digitale authentifiée"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Matériel d\'empreinte numérique indisponible."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"L\'empreinte digitale ne peut pas être enregistrée. Veuillez supprimer une empreinte existante."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Le temps attribué pour lire l\'empreinte est écoulé. Veuillez essayer de nouveau."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Temps de reconn. visage écoulé. Veuillez réessayer."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Impossible de stocker le visage."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Opération de reconnaissance du visage annulée."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Trop de tentatives. Veuillez réessayer plus tard."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Trop de tentatives. Capt. reconn. visage désactivé."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Réessayez."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Correction des couleurs"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Le raccourci d\'accessibilité a activé la fonction <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Le raccourci d\'accessibilité a désactivé la fonction <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Utilisez à nouveau le raccourci d\'accessibilité pour démarrer la fonctionnalité d\'accessibilité actuelle"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choisissez une fonctionnalité à utiliser lorsque vous touchez le bouton d\'accessibilité :"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Pour changer des fonctionnalités, maintenez le doigt sur le bouton d\'accessibilité."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Zoom"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index e153082..76eed1f 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Problème lors de l\'enregistrement des appels Wi‑Fi avec votre opérateur : <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Appels Wi-Fi %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Appels Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Appel WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Appel WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Appels Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWiFi <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Désactivé"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi de préférence"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Priorité au mobile"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Non reconnu"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Empreinte digitale authentifiée"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Matériel d\'empreinte numérique indisponible."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Impossible d\'enregistrer l\'empreinte numérique. Veuillez supprimer une empreinte."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Délai de détection de l\'empreinte numérique expiré. Veuillez réessayer."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Délai de détection du visage expiré. Réessayez."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Impossible de stocker les informations du visage."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Opération de reconnaissance faciale annulée."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Trop de tentatives. Réessayez plus tard."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Trop d\'essais. Authentification faciale désactivée."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Réessayez."</string>
@@ -1300,14 +1310,14 @@
<string name="perm_costs_money" msgid="4902470324142151116">"Cela peut engendrer des frais"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
<string name="usb_charging_notification_title" msgid="1595122345358177163">"Appareil en charge via USB"</string>
- <string name="usb_supplying_notification_title" msgid="4631045789893086181">"Rechargement via USB de l\'appareil connecté"</string>
+ <string name="usb_supplying_notification_title" msgid="4631045789893086181">"Recharge via USB de l\'appareil connecté"</string>
<string name="usb_mtp_notification_title" msgid="4238227258391151029">"Transfert de fichiers via USB activé"</string>
<string name="usb_ptp_notification_title" msgid="5425857879922006878">"PTP via USB activé"</string>
<string name="usb_tether_notification_title" msgid="3716143122035802501">"Partage de connexion via USB activé"</string>
<string name="usb_midi_notification_title" msgid="5356040379749154805">"MIDI via USB activé"</string>
<string name="usb_accessory_notification_title" msgid="1785694450621427730">"Accessoire USB connecté"</string>
<string name="usb_notification_message" msgid="3370903770828407960">"Appuyez ici pour plus d\'options."</string>
- <string name="usb_power_notification_message" msgid="4647527153291917218">"Rechargement de l\'appareil connecté. Appuyez ici pour plus d\'options."</string>
+ <string name="usb_power_notification_message" msgid="4647527153291917218">"Recharge de l\'appareil connecté. Appuyez ici pour plus d\'options."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"Accessoire audio analogique détecté"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"L\'appareil connecté n\'est pas compatible avec ce téléphone. Appuyez ici pour en savoir plus."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB activé"</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Correction des couleurs"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Le raccourci d\'accessibilité a activé <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Le raccourci d\'accessibilité a désactivé <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Utilisez à nouveau le raccourci d\'accessibilité pour démarrer la fonctionnalité d\'accessibilité actuelle"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Choisissez une fonctionnalité à utiliser lorsque vous appuyez sur le bouton d\'accessibilité :"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Pour changer des fonctionnalités, appuyez de manière prolongée sur le bouton d\'accessibilité."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Agrandissement"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index ba66adf..f644919 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Produciuse un problema ao rexistrar as chamadas por wifi co teu operador: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Chamadas por wifi de %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Chamadas por wifi de <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Chamada por WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Chamada por WLAN de <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wifi de <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Chamadas por wifi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi de <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desactivado"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wifi preferida"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Datos móbiles preferidos"</string>
@@ -298,8 +302,8 @@
<string name="permgroupdesc_phone" msgid="6234224354060641055">"facer e xestionar chamadas telefónicas"</string>
<string name="permgrouprequest_phone" msgid="9166979577750581037">"Queres permitir que a aplicación <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> realice e xestione chamadas telefónicas?"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Sensores corporais"</string>
- <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acceder aos datos do sensor sobre as túas constantes vitais"</string>
- <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Queres permitir que a aplicación <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda aos datos do sensor sobre as túas constantes vitais?"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acceder aos datos dos sensores sobre as túas constantes vitais"</string>
+ <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Queres permitir que a aplicación <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda aos datos dos sensores sobre as túas constantes vitais?"</string>
<string name="permgrouplab_aural" msgid="965607064083134896">"Música"</string>
<string name="permgroupdesc_aural" msgid="4870189506255958055">"acceder á música"</string>
<string name="permgrouprequest_aural" msgid="6787926123071735620">"Queres permitir que a aplicación <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> acceda á túa música?"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Non se recoñeceu"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Autenticouse a impresión dixital"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware de impresión dixital non dispoñible."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Non se pode almacenar a impresión dixital. Elimina unha impresión dixital existente."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Esgotouse o tempo de espera da impresión dixital. Téntao de novo."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Esgotouse o tempo de espera. Téntao de novo."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Non se puido almacenar a cara."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Cancelouse a operación relacionada coa cara"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Demasiados intentos. Téntao de novo máis tarde."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Demasiados intentos. Autenticación desactivada."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Téntao de novo."</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Corrección de cor"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atallo de accesibilidade activou <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O atallo de accesibilidade desactivou <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Para iniciar a función de accesibilidade actual, utiliza de novo o atallo de accesibilidade"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolle que función queres utilizar cando toques o botón Accesibilidade:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para cambiar as funcións, mantén premido o botón Accesibilidade."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliación"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 2b96f3f..4ea553c 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"તમારા કૅરિઅરમાં વાઇ-ફાઇ કૉલિંગ રજિસ્ટર કરવામાં સમસ્યા આવી: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s વાઇ-ફાઇ કૉલિંગ"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> વાઇ-ફાઇ કૉલિંગ"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN કૉલ"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN કૉલ"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> વાઇ-ફાઇ"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"વાઇ-ફાઇ કૉલિંગ | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"બંધ"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"વાઇ-ફાઇ પસંદ કર્યું"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"મોબાઇલને પસંદગી"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"ઓળખાયેલ નથી"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ફિંગરપ્રિન્ટ પ્રમાણિત કરી"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ફિંગરપ્રિન્ટ હાર્ડવેર ઉપલબ્ધ નથી."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ફિંગરપ્રિન્ટ સંગ્રહિત કરી શકાતી નથી. કૃપા કરીને અસ્તિત્વમાંની ફિંગરપ્રિન્ટ દૂર કરો."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"ફિંગરપ્રિન્ટનો સમય બાહ્ય થયો. ફરી પ્રયાસ કરો."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"ચહેરા માટેનો સમય સમાપ્ત થયો. ફરી પ્રયાસ કરો."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"ચહેરો સંગ્રહિત કરી શકાશે નહીં."</string>
<string name="face_error_canceled" msgid="283945501061931023">"ચહેરા સંબંધિત કાર્યવાહી રદ કરવામાં આવી છે."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"ઘણા બધા પ્રયત્નો. થોડા સમય પછી ફરી પ્રયાસ કરો."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"ઘણા બધા પ્રયત્નો. ચહેરાનું પ્રમાણીકરણ બંધ કરવામાં આવ્યું છે."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"ફરી પ્રયાસ કરો."</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"રંગ સુધારણા"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ઍક્સેસિબિલિટી શૉર્ટકટે <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ચાલુ કરી"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ઍક્સેસિબિલિટી શૉર્ટકટે <xliff:g id="SERVICE_NAME">%1$s</xliff:g> બંધ કરી"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"વર્તમાન ઍક્સેસિબિલિટી સુવિધાને શરૂ કરવા માટે ફરીથી ઍક્સેસિબિલિટી શૉર્ટકટનો ઉપયોગ કરો"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"જ્યારે તમે ઍક્સેસિબિલિટી બટન પર ટૅપ કરો, ત્યારે ઉપયોગ કરવાની સુવિધા પસંદ કરો:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"સુવિધાઓ બદલવા માટે, ઍક્સેસિબિલિટી બટન દબાવી રાખો."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"વિસ્તૃતીકરણ"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 6afe603..c24b0ae 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"वाई-फ़ाई कॉलिंग की सुविधा के लिए आपकी मोबाइल और इंटरनेट सेवा देने वाली कंपनी के साथ रजिस्टर करने से जुड़ी समस्या: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s वाई-फ़ाई कॉलिंग"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> वाई-फ़ाई कॉलिंग"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN कॉल"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN कॉल"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> वाई-फ़ाई"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"वाई-फ़ाई कॉलिंग | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"बंद"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"वाई-फ़ाई को प्राथमिकता"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"मोबाइल को प्राथमिकता"</string>
@@ -526,6 +530,10 @@
<!-- no translation found for biometric_not_recognized (5770511773560736082) -->
<skip />
<string name="fingerprint_authenticated" msgid="5309333983002526448">"फ़िंगरप्रिंट की पुष्टि हो गई"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"फ़िंगरप्रिंट हार्डवेयर उपलब्ध नहीं है."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"फ़िंगरप्रिंट को संग्रहित नहीं किया जा सका. कृपया कोई मौजूदा फ़िंगरप्रिंट निकालें."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"फ़िंगरप्रिंट का समय समाप्त हो गया. पुनः प्रयास करें."</string>
@@ -562,6 +570,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"चेहरे की पहचान का समय खत्म हुआ. फिर से कोशिश करें."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"चेहरा सेव करने की सीमा पूरी हो गई है."</string>
<string name="face_error_canceled" msgid="283945501061931023">"चेहरा पहचानने की कार्रवाई रद्द की गई."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"कई बार कोशिश की गई. बाद में कोशिश करें."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"कई बार कोशिश की. चेहरा पहचानने की सुविधा बंद हुई."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"फिर से कोशिश करें."</string>
@@ -1618,6 +1628,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"रंग में सुधार करने की सुविधा"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"सुलभता शॉर्टकट ने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को चालू किया"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"सुलभता शॉर्टकट ने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को बंद किया"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"मौजूदा सुलभता सुविधा शुरू करने के लिए \'सुलभता शॉर्टकट\' का फिर से इस्तेमाल करें"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"सुलभता बटन पर टैप करते समय इस्तेमाल की जाने वाली सुविधा चुनें:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"सुविधाओं में बदलाव करने के लिए, सुलभता बटन को दबाकर रखें."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"बड़ा करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index e7b6b5f..6a9d307 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -129,10 +129,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Poteškoća s registracijom Wi‑Fi poziva kod mobilnog operatera: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi pozivanje"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi pozivi"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Poziv putem WLAN-a"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> poziv putem WLAN-a"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi pozivi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Isključeno"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Prednost ima Wi-Fi mreža"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Za mobilne uređaje"</string>
@@ -527,6 +531,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Nije prepoznato"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Autentificirano otiskom prsta"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otisak prsta nije dostupan."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Otisak prsta nije pohranjen. Uklonite postojeći otisak prsta."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Isteklo je vrijeme čekanja za otisak prsta. Pokušajte ponovo."</string>
@@ -563,6 +571,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Isteklo je vrijeme čekanja za lice. Pokušajte opet"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Nije moguće pohraniti lice."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Otkazana je radnja s licem."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Previše pokušaja. Autentifikacija lica onemogućena"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Pokušajte ponovo."</string>
@@ -1640,6 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Korekcija boje"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Prečac pristupačnosti uključio je uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Prečac pristupačnosti isključio je uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Ponovo upotrijebite prečac pristupačnosti da biste pokrenuli trenutačnu značajku pristupačnosti"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Odaberite značajku koju ćete upotrebljavati kada dodirnete gumb Pristupačnost:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Da biste promijenili značajke, dodirnite i zadržite gumb Pristupačnost."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Povećavanje"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 3d9a35b..474c73a 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Hiba történt a Wi‑Fi-hívás szolgáltatónál való regisztrálása során: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi-hívás"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi-hívás"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-hívás"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN-hívás"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi-hívás | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Ki"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi előnyben részesítve"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferált: mobil"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Nem ismerhető fel"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Ujjlenyomat hitelesítve"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Az ujjlenyomathoz szükséges hardver nem érhető el."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Az ujjlenyomat nem tárolható. Távolítson el egy meglévő ujjlenyomatot."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Az ujjlenyomat-beolvasási műveletkor időtúllépés történt. Próbálkozzon újra."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Időtúllépés az arcbeolvasásnál. Próbálja újra."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Az arc nem tárolható."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Az arccal kapcsolatos művelet törölve."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Túl sok próbálkozás. Próbálja újra később."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Túl sok próbálkozás. Arcfelismerés letiltva."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Próbálkozzon újra."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Színkorrekció"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"A Kisegítő lehetőségek gyorsparancsa bekapcsolta a következő szolgáltatást: <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"A Kisegítő lehetőségek gyorsparancsa kikapcsolta a következő szolgáltatást: <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Használja újból a Kisegítő lehetőségek gyorsparancsát az aktuális kisegítő lehetőségek elindításához"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Válassza ki a Kisegítő lehetőségek gombra koppintáskor használni kívánt funkciót:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"A funkciók módosításához tartsa lenyomva a Kisegítő lehetőségek gombot."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Nagyítás"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 6a5f287..b9e6c62 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Wi‑Fi-ի միջոցով արվող զանգերը չհաջողվեց գրանցել ձեր օպերատորի մոտ՝ <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi զանգեր"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi-ի միջոցով զանգեր"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Զանգ WLAN ցանցով"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN ցանցով զանգեր"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Զանգեր Wi-Fi-ի միջոցով | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Անջատված է"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi, նախընտրելի"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Նախընտրելի է բջջային ցանցը"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Չհաջողվեց ճանաչել"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Մատնահետքը նույնականացվեց"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Մատնահետքի սարքն անհասանելի է:"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Հնարավոր չէ պահել մատնահետքը: Հեռացրեք առկա մատնահետքը:"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Մատնահետքի գրանցման ժամանակը սպառվել է: Փորձեք նորից:"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Ժամանակը սպառվել է: Նորից փորձեք:"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Դեմքը հնարավոր չէ պահել։"</string>
<string name="face_error_canceled" msgid="283945501061931023">"Դեմքի ճանաչումը չեղարկվել է։"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Չափից շատ փորձեր եք կատարել: Փորձեք ավելի ուշ:"</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Չափից շատ փորձեր եք կատարել: Դեմքի ճանաչման գործառույթն անջատվել է։"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Նորից փորձեք:"</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Գունաշտկում"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Մատչելիության դյուրանցումն միացրել է <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Մատչելիության դյուրանցումն անջատել է <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Հատուկ գործառույթների դյուրանցումը գործարկելու համար նորից օգտագործեք համապատասխան դյուրանցումը"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Ընտրեք որևէ գործառույթ, որը կօգտագործվի Հատուկ գործառույթներ կոճակին հպելու դեպքում՝"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Գործառույթները փոխելու համար հպեք և պահեք Հատուկ գործառույթներ կոճակը։"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Խոշորացում"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 6d1da48..8298a18 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Terjadi masalah saat mendaftarkan panggilan Wi‑Fi dengan operator Anda: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Panggilan Wi-Fi"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Panggilan Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Panggilan WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Panggilan WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Panggilan WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Nonaktif"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi dipilih"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Seluler dipilih"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Tidak dikenali"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Sidik jari diautentikasi"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware sidik jari tidak tersedia."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Sidik jari tidak dapat disimpan. Hapus sidik jari yang ada."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Waktu sidik jari habis. Coba lagi."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Waktu tunggu wajah habis. Harap coba lagi."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Wajah tidak dapat disimpan."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Pemrosesan wajah dibatalkan."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Terlalu banyak percobaan. Coba lagi nanti."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Terlalu sering dicoba. Autentikasi wajah dinonaktifkan."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Coba lagi."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Koreksi Warna"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pintasan Aksesibilitas mengaktifkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pintasan Aksesibilitas menonaktifkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gunakan Pintasan Aksesibilitas lagi untuk memulai fitur aksesibilitas saat ini"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pilih fitur yang akan digunakan saat menge-tap tombol Aksesibilitas:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Untuk mengubah fitur, sentuh & tahan tombol Aksesibilitas."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Pembesaran"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 4d7996f..2649a1a 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Vandamál kom upp við að skrá Wi‑Fi símtöl hjá símafyrirtækinu: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi símtöl"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi símtöl"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-símtal"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN-símtal"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi símtal | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Slökkt"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi í forgangi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Farsímakerfi í forgangi"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Þekktist ekki"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingrafar staðfest"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Fingrafarsvélbúnaður ekki til staðar."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Ekki er hægt að vista fingrafarið. Fjarlægðu eitthvert af fingraförunum sem fyrir eru."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tímamörk runnu út fyrir fingrafar. Reyndu aftur."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Tímamörk runnu út fyrir andlit. Reyndu aftur."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Ekki tókst að geyma andlit."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Hætt við andlitsgreiningu."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Of margar tilraunir. Reyndu aftur síðar."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Of margar tilraunir. Slökkt á andlitsgreiningu."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Reyndu aftur."</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Litaleiðrétting"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Flýtileið aðgengisstillingar kveikti á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Flýtileið aðgengisstillingar slökkti á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Notaðu flýtileið aðgengisstillingar aftur til að opna aðgengiseiginleika"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Veldu eiginleika sem á að nota þegar ýtt er á aðgengishnappinn:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Haltu fingri á aðgengishnappinum til að breyta eiginleikum."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Stækkun"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 44818a3..5c28097 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Si è verificato un problema con la registrazione delle chiamate Wi‑Fi con l\'operatore: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Chiamata Wi-Fi %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Chiamate Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Chiamata WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Chiamata WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Chiamate Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Non attiva"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Rete preferita: Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Rete preferita: dati mobili"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Non riconosciuto"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Impronta digitale autenticata"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware per l\'impronta digitale non disponibile."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Impossibile memorizzare l\'impronta digitale. Rimuovi un\'impronta esistente."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Timeout impronta digitale. Riprova."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Timeout operazione associata al volto. Riprova."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Il volto non può essere memorizzato."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Operazione associata al volto annullata."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Troppi tentativi. Riprova più tardi."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Troppi tentativi. Autenticazione disattivata."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Riprova."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Correzione del colore"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"La scorciatoia Accessibilità ha attivato <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"La scorciatoia Accessibilità ha disattivato <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Usa di nuovo la scorciatoia Accessibilità per avviare l\'attuale funzione di accessibilità"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Scegli una funzione da usare quando tocchi il pulsante Accessibilità:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Per cambiare le funzioni, tocca e tieni premuto il pulsante Accessibilità."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ingrandimento"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index fd5c2a1..5dd1617 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -130,10 +130,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"אירעה בעיה ברישום שיחות Wi-Fi אצל הספק שלך: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"שיחות Wi-Fi של %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"שיחות Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"שיחה ברשת אלחוטית"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"שיחת WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"שיחות WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"כבוי"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi מועדף"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"מצב מועדף: רשת סלולרית"</string>
@@ -530,6 +534,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"לא זוהתה"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"טביעת האצבע אומתה"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"החומרה בשביל טביעת אצבע אינה זמינה."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"לא ניתן לאחסן טביעת אצבע. הסר טביעת אצבע קיימת."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"חלף הזמן הקצוב לטביעת אצבע. נסה שוב."</string>
@@ -566,6 +574,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"חלף הזמן הקצוב לזיהוי הפנים. יש לנסות שוב."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"לא ניתן לשמור את הפנים."</string>
<string name="face_error_canceled" msgid="283945501061931023">"פעולת הפנים בוטלה."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"יותר מדי ניסיונות. יש לנסות שוב מאוחר יותר."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"יותר מדי ניסיונות. אימות הפנים הושבת."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"יש לנסות שוב."</string>
@@ -1228,13 +1238,13 @@
<string name="volume_call" msgid="3941680041282788711">"עוצמת קול בשיחה"</string>
<string name="volume_bluetooth_call" msgid="2002891926351151534">"עוצמת הקול בשיחה ב-Bluetooth"</string>
<string name="volume_alarm" msgid="1985191616042689100">"עוצמת קול של התראה"</string>
- <string name="volume_notification" msgid="2422265656744276715">"עוצמת קול של הודעות"</string>
+ <string name="volume_notification" msgid="2422265656744276715">"עוצמת הקול של ההתראות"</string>
<string name="volume_unknown" msgid="1400219669770445902">"עוצמת קול"</string>
<string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"עוצמת קול של Bluetooth"</string>
<string name="volume_icon_description_ringer" msgid="3326003847006162496">"עוצמת קול של רינגטון"</string>
<string name="volume_icon_description_incall" msgid="8890073218154543397">"עוצמת קול של שיחות"</string>
<string name="volume_icon_description_media" msgid="4217311719665194215">"עוצמת קול של מדיה"</string>
- <string name="volume_icon_description_notification" msgid="7044986546477282274">"עוצמת קול של הודעות"</string>
+ <string name="volume_icon_description_notification" msgid="7044986546477282274">"עוצמת הקול של ההתראות"</string>
<string name="ringtone_default" msgid="3789758980357696936">"רינגטון ברירת מחדל"</string>
<string name="ringtone_default_with_actual" msgid="1767304850491060581">"ברירת מחדל (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"ללא"</string>
@@ -1502,7 +1512,7 @@
<string name="sync_really_delete" msgid="2572600103122596243">"מחק את הפריטים"</string>
<string name="sync_undo_deletes" msgid="2941317360600338602">"בטל את פעולות המחיקה"</string>
<string name="sync_do_nothing" msgid="3743764740430821845">"אל תעשה דבר כרגע"</string>
- <string name="choose_account_label" msgid="5655203089746423927">"בחר חשבון"</string>
+ <string name="choose_account_label" msgid="5655203089746423927">"בחירת חשבון"</string>
<string name="add_account_label" msgid="2935267344849993553">"הוספת חשבון"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"הוספת חשבון"</string>
<string name="number_picker_increment_button" msgid="2412072272832284313">"הוסף"</string>
@@ -1664,6 +1674,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"תיקון צבעים"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> הופעל על-ידי קיצור הדרך לנגישות"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> הושבת על-ידי קיצור הדרך לנגישות"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"יש להשתמש שוב במקש הקיצור לנגישות כדי להפעיל את תכונת הנגישות הנוכחית"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"בחר תכונה שתופעל כשתלחץ על הלחצן \'נגישות\':"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"כדי להחליף תכונה, גע בלחצן \'נגישות\' והחזק אותו."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"הגדלה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 4915111..7b53ed4 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"携帯通信会社への Wi‑Fi 通話の登録中に問題が発生しました(<xliff:g id="CODE">%1$s</xliff:g>)"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Wi-Fi通話(%s)"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi 通話"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN 通話"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN 通話"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi 通話 | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"OFF"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi優先"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"モバイル優先"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"認識されませんでした"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"指紋認証を完了しました"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"指紋ハードウェアは使用できません。"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"指紋を保存できません。既存の指紋を削除してください。"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"指紋の読み取りがタイムアウトになりました。もう一度お試しください。"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"読み取りのタイムアウトです。もう一度お試しください。"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"顔の情報を保存できません。"</string>
<string name="face_error_canceled" msgid="283945501061931023">"顔の操作をキャンセルしました。"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"試行回数の上限です。後でもう一度お試しください。"</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"試行回数の上限です。顔認証は無効になりました。"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"もう一度お試しください。"</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"色補正"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ユーザー補助機能のショートカットにより <xliff:g id="SERVICE_NAME">%1$s</xliff:g> は ON になっています"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ユーザー補助機能のショートカットにより <xliff:g id="SERVICE_NAME">%1$s</xliff:g> は OFF になっています"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"現在のユーザー補助機能を開始するには、ユーザー補助機能のショートカットをもう一度使用してください"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"[ユーザー補助] ボタンをタップした場合に使用する機能を選択してください。"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"機能を変更するには、[ユーザー補助] ボタンを押し続けてください。"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"拡大"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 51a4c28..7226296 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Wi‑Fi დარეკვის თქვენს ოპერატორთან რეგისტრირებისას შეცდომა წარმოიქმნა: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s დარეკვა Wi-Fi-ს მეშვეობით"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi დარეკვა"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN ზარი"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN ზარი"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi დარეკვა | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"გამორთული"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"სასურველია Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"უპირატესობა მიენიჭოს მობილურს"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"არ არის ამოცნობილი"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"თითის ანაბეჭდი ავტორიზებულია"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"თითის ანაბეჭდის აპარატურა არ არის ხელმისაწვდომი."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"თითის ანაბეჭდის შენახვა ვერ ხერხდება. გთხოვთ, ამოშალოთ არსებული თითის ანაბეჭდი."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"თითის ანაბეჭდის ლოდინის დრო ამოიწურა. სცადეთ ხელახლა."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"სახის ამოცნობის დრო ამოიწურა. ცადეთ ხელახლა."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"სახის შენახვა ვერ მოხერხდა."</string>
<string name="face_error_canceled" msgid="283945501061931023">"სახის ამოცნობა გაუქმდა."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"დაფიქსირდა ბევრი მცდელობა. ცადეთ მოგვიანებით."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"დაფიქსირდა ბევრი მცდელობა. სახის ამოცნობა გაითიშა."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"ცადეთ ხელახლა."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"ფერთა კორექცია"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"მარტივი წვდომის მალსახმობმა ჩართო <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"მარტივი წვდომის მალსახმობმა გამორთო <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"მარტივი წვდომის ამჟამინდელი ფუნქციის გასაშვებად გამოიყენეთ მარტივი წვდომის მალსახმობი"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"აირჩიეთ მარტივი წვდომის ღილაკზე შეხებისას გამოსაყენებელი ფუნქცია:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ფუნქციების შესაცვლელად ხანგრძლივად შეეხეთ მარტივი წვდომის ღილაკს."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"გადიდება"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 18be1e6..457933e 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Оператордың Wi‑Fi қоңырауын тіркеу кезінде қате шықты: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi арқылы қоңырау шалу"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi қоңыраулары"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN қоңырауы"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN қоңырауы"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi қоңыраулары | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Өшірулі"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Қалаулы Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Таңдаулы мобильдік байланыс"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Танылмады"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Саусақ ізі аутентификацияланды"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Саусақ ізі жабдығы қолжетімді емес."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Саусақ ізін сақтау мүмкін емес. Бар саусақ ізін жойыңыз."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Саусақ ізін күту уақыты бітті. Әрекетті қайталаңыз."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Күту уақыты бітті. Әрекетті қайталаңыз."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Бетті сақтау мүмкін емес."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Бетті танудан бас тартылды."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Тым көп әрекет жасалды. Кейінірек қайталаңыз."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Тым көп әрекет жасалды. Бетті тану функциясы өшірілді."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Қайталап көріңіз."</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Түсті түзету"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Арнайы мүмкіндіктер таңбашасы <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін қосты"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Арнайы мүмкіндіктер таңбашасы <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін өшірді"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Арнайы мүмкіндіктер функциясын іске қосу үшін оның таңбашасын пайдаланыңыз"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"\"Арнайы мүмкіндіктер\" түймесін түрткенде пайдаланатын мүмкіндікті таңдаңыз:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Мүмкіндіктерді өзгерту үшін \"Арнайы мүмкіндіктер\" түймесін түртіп, ұстап тұрыңыз."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ұлғайту"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 091fa71..b3a3a01 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"មានបញ្ហាក្នុងការចុះឈ្មោះការហៅតាម Wi‑Fi ជាមួយក្រុមហ៊ុនសេវាទូរសព្ទរបស់អ្នក៖ <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"ការហៅតាមរយៈ Wi-Fi %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> ការហៅតាម Wi-Fi"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"ការហៅតាម WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> ការហៅតាម WLAN"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"ការហៅតាម WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"បិទ"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi ជាអាទិភាព"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ទិន្នន័យទូរសព្ទចល័តជាអាទិភាព"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"មិនអាចសម្គាល់បានទេ"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"បានផ្ទៀងផ្ទាត់ស្នាមម្រាមដៃ"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ផ្នែករឹងស្នាមម្រាមដៃមិនមានទេ។"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"មិនអាចផ្ទុកស្នាមម្រាមដៃទេ។ សូមយកស្នាមម្រាមដៃដែលមានស្រាប់ចេញ។"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"ការផ្តិតម្រាមដៃបានអស់ពេល។ សូមព្យាយាមម្តងទៀត។"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"ការសម្គាល់ផ្ទៃមុខបានអស់ម៉ោង។ សូមព្យាយាមម្ដងទៀត។"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"មិនអាចរក្សាទុកផ្ទៃមុខបានទេ។"</string>
<string name="face_error_canceled" msgid="283945501061931023">"បានបោះបង់ប្រតិបត្តិការចាប់ផ្ទៃមុខ។"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"ព្យាយាមចូលច្រើនពេកហើយ។ សូមព្យាយាមម្តងទៀតពេលក្រោយ។"</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"ព្យាយាមចូលច្រើនពេកហើយ។ បានបិទការផ្ទៀងផ្ទាត់ផ្ទៃមុខ។"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"សូមព្យាយាមម្ដងទៀត។"</string>
@@ -1618,6 +1628,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"ការកែពណ៌"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ផ្លូវកាត់ភាពងាយស្រួលបានបើក <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ផ្លូវកាត់ភាពងាយស្រួលបានបិទ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ប្រើផ្លូវកាត់ភាពងាយស្រួលម្ដងទៀត ដើម្បីចាប់ផ្ដើមមុខងារភាពងាយប្រើបច្ចុប្បន្ន"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ជ្រើសរើសមុខងារដែលត្រូវប្រើ នៅពេលដែលអ្នកចុចប៊ូតុងភាពងាយស្រួល៖"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ដើម្បីផ្លាស់ប្តូរមុខងារ សូមចុចប៊ូតុងភាពងាយស្រួលឲ្យជាប់។"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ការពង្រីក"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index e228d35..2dc0bb1 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"ನಿಮ್ಮ ವಾಹಕದೊಂದಿಗೆ ವೈ-ಫೈ ಕರೆ ಮಾಡುವಿಕೆ ಸಮಸ್ಯೆ ನೋಂದಾಯಿಸುವಿಕೆ: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s ವೈ-ಫೈ ಕರೆ ಮಾಡುವಿಕೆ"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> ವೈ-ಫೈ ಕರೆ ಮಾಡುವಿಕೆ"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN ಕರೆ"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN ಕರೆ"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> ವೈ-ಫೈ"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"ವೈಫೈ ಕರೆಮಾಡುವಿಕೆ | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"ಆಫ್"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ವೈ-ಫೈಗೆ ಆದ್ಯತೆ"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ಮೊಬೈಲ್ಗೆ ಆದ್ಯತೆ"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ಪ್ರಮಾಣೀಕರಣ ಮಾಡಲಾಗಿದೆ"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ಬೆರಳಚ್ಚು ಹಾರ್ಡ್ವೇರ್ ಲಭ್ಯವಿಲ್ಲ."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ಬೆರಳಚ್ಚು ಸಂಗ್ರಹಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಬೆರಳಚ್ಚು ತೆಗೆದುಹಾಕಿ."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"ಬೆರಳಚ್ಚು ಅವಧಿ ಮೀರಿದೆ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"ಮುಖ ಸಮಯದ ಅವಧಿಯನ್ನು ತಲುಪಿದೆ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"ಮುಖವನ್ನು ಸಂಗ್ರಹಿಸಲಾಗುವುದಿಲ್ಲ."</string>
<string name="face_error_canceled" msgid="283945501061931023">"ಮುಖದ ಕಾರ್ಯಚರಣೆಯನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"ಹಲವು ಬಾರಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"ಹಲವು ಪ್ರಯತ್ನ. ಮುಖದ ದೃಢೀಕರಣ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"ಬಣ್ಣ ತಿದ್ದುಪಡಿ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್ಕಟ್, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆನ್ ಮಾಡಿದೆ"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್ಕಟ್, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಫ್ ಮಾಡಿದೆ"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ಪ್ರಸ್ತುತ ಪ್ರವೇಶದ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಪ್ರಾರಂಭಿಸಲು ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ಪುನಃ ಬಳಸಿ"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ನೀವು ಪ್ರವೇಶಿಸುವಿಕೆ ಬಟನ್ ಟ್ಯಾಪ್ ಮಾಡಿದಾಗ ಬಳಸುವುದಕ್ಕಾಗಿ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಆರಿಸಿ:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಬದಲಾಯಿಸಲು, ಪ್ರವೇಶಿಸುವಿಕೆ ಬಟನ್ ಒತ್ತಿಹಿಡಿದುಕೊಳ್ಳಿ."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ಹಿಗ್ಗಿಸುವಿಕೆ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index d37a475..abed24c 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"이동통신사를 통해 Wi‑Fi 통화를 등록하는 중에 문제가 발생했습니다. 오류 코드: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi 통화"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi 통화"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN 통화"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN 통화"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi 통화 | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"꺼짐"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi를 기본으로 설정"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"모바일에 최적화됨"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"인식할 수 없음"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"지문이 인증됨"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"지문 인식 하드웨어를 사용할 수 없습니다."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"지문을 저장할 수 없습니다. 기존 지문을 삭제하세요."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"지문 인식 시간이 초과되었습니다. 다시 시도하세요."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"얼굴 인식 시간이 초과되었습니다. 다시 시도하세요."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"얼굴을 저장할 수 없습니다."</string>
<string name="face_error_canceled" msgid="283945501061931023">"얼굴 인식 작업이 취소되었습니다."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"시도 횟수가 너무 많습니다. 나중에 다시 시도하세요."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"시도 횟수가 너무 많아 얼굴 인증이 사용 중지되었습니다."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"다시 시도해 보세요."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"색상 보정"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"접근성 단축키로 인해 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 설정되었습니다."</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"접근성 단축키로 인해 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 중지되었습니다."</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"현재 접근성 기능을 시작하려면 접근성 단축키를 다시 사용하세요"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"접근성 버튼을 탭할 때 사용할 기능을 선택하세요."</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"기능을 변경하려면 접근성 버튼을 길게 터치하세요."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"확대"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index cf5f531..fb8a816 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Байланыш операторуңуз менен Wi-Fi аркылуу чалууну каттоодо ката кетти: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi Чалуу"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi аркылуу чалуу"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN аркылуу чалуу"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN аркылуу чалуу"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi аркылуу чалуу | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Өчүк"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi тандалган"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Тандалган мобилдик түзмөк"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Таанылган жок"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Манжа изинин аныктыгы текшерилди"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Манжа изинин аппараттык камсыздоосу жеткиликтүү эмес."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Манжа изин сактоо мүмкүн эмес. Учурдагы манжа изин алып салыңыз."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Манжа изин күтүү мөөнөтү бүттү. Кайра аракет кылыңыз."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Жүздүн аныктыгын текшерүүнү күтүү мөөнөтү бүттү. Кайра аракет кылыңыз."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Жүздү сактоо мүмкүн эмес."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Жүздүн аныктыгын текшерүү жокко чыгарылды."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Өтө көп жолу аракет жасадыңыз. Кийинчерээк кайра аракет кылыңыз."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Өтө көп жолу аракет жасадыңыз. Жүздүн аныктыгын текшерүү сенсору өчүрүлдү."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Кайра аракет кылыңыз."</string>
@@ -1618,6 +1628,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Түсүн тууралоо"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Атайын мүмкүнчүлүктөр кыска жолу <xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын күйгүздү"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Атайын мүмкүнчүлүктөр кыска жолу <xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын өчүрдү"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Учурдагы атайын мүмкүнчүлүктөр функциясын иштетүү үчүн кыска жолду кайра колдонуңуз"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Атайын мүмкүнчүлүктөр баскычын таптаганыңызда иштетиле турган функцияны тандаңыз:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Функцияларды өзгөртүү үчүн Атайын мүмкүнчүлүктөр баскычын басып, кармап туруңуз."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Чоңойтуу"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 7d8a4e2..8b6a052 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"ເກີດບັນຫາໃນການລົງທະບຽນການໂທ Wi‑Fi ກັບຜູ້ໃຫ້ບໍລິການຂອງທ່ານ: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"ການໂທ %s Wi-Fi"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi Calling"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN Call"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN Call"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi Calling | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"ປິດ"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ເລືອກໃຊ້ Wi-Fi ກ່ອນ"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ຕ້ອງການໃຊ້ມືຖື"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"ບໍ່ຮັບຮູ້"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ພິສູດຢືນຢັນລາຍນິ້ວມືແລ້ວ"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ບໍ່ມີຮາດແວລາຍນີ້ວມືໃຫ້ຢູ່."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ບໍ່ສາມາດເກັບຮັກສາລາຍນີ້ວມືໄວ້ໄດ້. ກະລຸນາເອົາລາຍນີ້ວມືທີ່ມີຢູ່ອອກໄປ."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"ເວລາລາຍນີ້ວມືບໍ່ເຂົ້າເຖິງໄດ້. ລອງໃໝ່ອີກ."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"ໝົດເວລາກວດໃບໜ້າແລ້ວ. ກະລຸນາລອງອີກຄັ້ງ."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"ບໍ່ສາມາດເກັບຮັກສາໃບໜ້າໄວ້ໄດ້."</string>
<string name="face_error_canceled" msgid="283945501061931023">"ຍົກເລີກການດຳເນີນການກັບໃບໜ້າແລ້ວ."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"ມີຄວາມພະຍາຍາມຫຼາຍຄັ້ງເກີນໄປ. ກະລຸນາລອງໃໝ່ໃນພາຍຫຼັງ."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"ມີຄວາມພະຍາຍາມຫຼາຍຄັ້ງເກີນໄປ. ປິດນຳໃຊ້ການກວດສອບຄວາມຖືກຕ້ອງດ້ວຍໃບໜ້າແລ້ວ."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"ລອງອີກຄັ້ງ."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"ການແກ້ໄຂຄ່າສີ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> on"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Accessibility Shortcut turned <xliff:g id="SERVICE_NAME">%1$s</xliff:g> off"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ໃຊ້ປຸ່ມລັດການຊ່ວຍເຂົ້າເຖິງອີກເທື່ອໜຶ່ງເພື່ອຊອກຫາຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງໃນປັດຈຸບັນ"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ເລືອກຄຸນສົມບັດທີ່ຈະໃຊ້ເມື່ອທ່ານແຕະປຸ່ມການຊ່ວຍເຂົ້າເຖິງ:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ເພື່ອປ່ຽນຄຸນສົມບັດ, ໃຫ້ແຕະປຸ່ມການຊ່ວຍເຂົ້າເຖິງຄ້າງໄວ້."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ການຂະຫຍາຍ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index a0015c3..7fc1c98 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -130,10 +130,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Kilo problema registruojant „Wi‑Fi“ skambinimą pas operatorių: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"„%s“ „Wi-Fi“ skambinimas"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> „Wi-Fi“ skambinimas"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN skambutis"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN skambutis"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> „Wi-Fi“"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"„Wi-Fi“ skambinimas | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> „VoWifi“"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Išjungta"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Pageidautinas „Wi-Fi“ ryšys"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Pirmenybė mobiliojo ryšio tinklui"</string>
@@ -530,6 +534,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Neatpažinta"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Kontrolinis kodas autentifikuotas"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Kontrolinio kodo aparatinė įranga nepasiekiama."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Negalima išsaugoti kontrolinio kodo. Pašalinkite esamą kontrolinį kodą."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Baigėsi kontrolinio kodo nustatymo skirtasis laikas. Bandykite dar kartą."</string>
@@ -566,6 +574,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Baigėsi veido atpaž. skirt. laik. Band. dar kartą."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Nepavyko išsaugoti veido duomenų."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Veido atpažinimo operacija atšaukta."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Per daug bandymų. Vėliau bandykite dar kartą."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Per daug bandymų. Veido autentifik. išjungtas."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Bandykite dar kartą."</string>
@@ -1664,6 +1674,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Spalvų taisymas"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pritaikymo neįgaliesiems sparčiuoju klavišu buvo įjungta „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pritaikymo neįgaliesiems sparčiuoju klavišu buvo išjungta „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Norėdami įjungti dabartinę pritaikymo neįgaliesiems funkciją, dar kartą naudokite spartųjį pritaikymo neįgaliesiems klavišą"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pasirinkite funkciją, kuri bus naudojama, kai paliesite pritaikymo neįgaliesiems mygtuką:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Jei norite pakeisti funkcijas, palieskite ir palaikykite pritaikymo neįgaliesiems mygtuką."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Didinimas"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index a1aebe1..60a32de 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -129,10 +129,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Reģistrējot Wi-Fi zvanus pie mobilo sakaru operatora, radās problēma: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi zvani"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi zvani"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN zvans"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN zvans"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi zvani | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Izslēgts"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Vēlams Wi-Fi tīkls"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Vēlams mobilo datu savienojums"</string>
@@ -527,6 +531,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Dati nav atpazīti"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Pirksta nospiedums tika autentificēts."</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Nospieduma aparatūra nav pieejama."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Pirkstu nospiedumu nevar saglabāt. Lūdzu, noņemiet esošu pirksta nospiedumu."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Pirkstu nospiedumu nolasīšanas aparatūras noildze. Mēģiniet vēlreiz."</string>
@@ -563,6 +571,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Sejas datu nolasīšanas noildze. Mēģiniet vēlreiz."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Sejas datus nevar saglabāt."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Darbība ar sejas datiem atcelta."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Pārāk daudz mēģinājumu. Vēlāk mēģiniet vēlreiz."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Par daudz mēģinājumu. Sejas atpazīšana atspējota."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Mēģiniet vēlreiz."</string>
@@ -1640,6 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Krāsu korekcija"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pieejamības saīsne aktivizēja lietotni <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pieejamības saīsne deaktivizēja lietotni <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Lai sāktu izmantot pašreizējo pieejamības funkciju, vēlreiz izmantojiet pieejamības saīsni."</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Izvēlieties funkciju, ko izmantot, kad pieskaraties pogai Pieejamība."</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Lai mainītu funkcijas, pieskarieties pogai Pieejamība un turiet to."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Palielinājums"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 0ab31b3..4ae6f31 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Проблем при регистрирањето на функцијата „Повици преку Wi‑Fi“ со операторот: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Повикување преку Wi-Fi"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Повици преку Wi-Fi на <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Повик преку WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Повик преку WLAN на <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi на <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Повици преку Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"Глас преку Wi-Fi на <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Исклучено"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Се претпочита Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Претпочитам мобилен интернет"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Непознат"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Отпечатокот е проверен"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хардвер за отпечаток од прст не е достапен."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Отпечатокот не може да се складира. Отстранете го постоечкиот отпечаток."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Се достигна времето на истекување на отпечатокот. Обидете се повторно."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Истече времето за проверка на лице. Повторен обид."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Лицето не може да се чува."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Операцијата со лице се откажа."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Премногу обиди. Обидете се повторно подоцна."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Премногу обиди. Проверката на лице е оневозможена."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Обидете се повторно."</string>
@@ -1619,6 +1629,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Корекција на бои"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Кратенката за пристапност ја вклучи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Кратенката за пристапност ја исклучи <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Повторно употребете ја кратенката за пристапност за да ја стартувате тековната функција за пристапност"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Изберете функција за користење кога ќе го допрете копчето за „Пристапност“."</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"За променување функции, допрете го и задржете го копчето за „Пристапност“."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Зголемување"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index eafd6a4..2cd83cc 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"നിങ്ങളുടെ കാരിയർ ഉപയോഗിച്ച് വൈഫൈ കോളിംഗ് രജിസ്റ്റർ ചെയ്യുന്നതിൽ പ്രശ്നം: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s വൈഫൈ കോളിംഗ്"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> വൈഫൈ കോളിംഗ്"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN കോൾ"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN കോൾ"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> വൈഫൈ"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"വൈഫൈ കോളിംഗ് | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> Voവൈഫൈ"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"ഓഫ്"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"വൈഫൈ തിരഞ്ഞെടുത്തിരിക്കുന്നു"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"മൊബൈൽ ഡാറ്റ ഉപയോഗിക്കാൻ താൽപ്പര്യപ്പെടുന്നു"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"തിരിച്ചറിഞ്ഞില്ല"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ഫിംഗർപ്രിന്റ് പരിശോധിച്ചുറപ്പിച്ചു"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ഫിംഗർപ്രിന്റ് ഹാർഡ്വെയർ ലഭ്യമല്ല."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"വിരലടയാളം സംഭരിക്കാനാവില്ല. നിലവിലുള്ള വിരലടയാളം നീക്കംചെയ്യുക."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"വിരലടയാളം നൽകേണ്ട സമയം കഴിഞ്ഞു. വീണ്ടും ശ്രമിക്കുക."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"മുഖം നൽകേണ്ട സമയം കഴിഞ്ഞു. വീണ്ടും ശ്രമിക്കുക."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"മുഖം സൂക്ഷിക്കാനാവില്ല."</string>
<string name="face_error_canceled" msgid="283945501061931023">"മുഖത്തിന്റെ പ്രവർത്തനം റദ്ദാക്കി."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"നിരവധി തവണ ശ്രമിച്ചു. പിന്നീട് വീണ്ടും ശ്രമിക്കുക."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"നിരവധി തവണ ശ്രമിച്ചു. മുഖം തിരിച്ചറിയൽ പ്രവർത്തനരഹിതമാക്കി."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"വീണ്ടും ശ്രമിക്കുക."</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"വർണ്ണം ക്രമീകരിക്കൽ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ഉപയോഗസഹായിക്കുള്ള കുറുക്കുവഴി <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓൺ ചെയ്തിരിക്കുന്നു"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ഉപയോഗസഹായിക്കുള്ള കുറുക്കുവഴി <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓഫ് ചെയ്തിരിക്കുന്നു"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"നിലവിലെ ഉപയോഗസഹായി ഫീച്ചർ ആരംഭിക്കാൻ വീണ്ടും ഉപയോഗസഹായി കുറുക്കുവഴി ഉപയോഗിക്കുക"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"നിങ്ങൾ ഉപയോഗസഹായി ബട്ടൺ ടാപ്പുചെയ്യുമ്പോൾ ഉപയോഗിക്കുന്നതിന് ഒരു ഫീച്ചർ തിരഞ്ഞെടുക്കുക:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ഫീച്ചറുകൾ മാറ്റുന്നതിന് ഉപയോഗസഹായി ബട്ടൺ സ്പർശിച്ചുപിടിക്കുക."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"മാഗ്നിഫിക്കേഷൻ"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 12e3186..35936ee 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Таны оператор компанийн Wi‑Fi дуудлагыг бүртгэхэд асуудал гарлаа: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi Дуудлага"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi дуудлага"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN дуудлага"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN дуудлага"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi дуудлага | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Идэвхгүй"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi давуу эрхтэй"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Мобайл давуу эрхтэй"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Таниагүй"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Хурууны хээг нотолсон"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хурууны хээний тоног төхөөрөмж бэлэн бус байна."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Хурууны хээг хадгалах боломжгүй байна. Одоо байгаа хурууны хээг арилгана уу."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Хурууны хээ оруулах хугацаа өнгөрсөн байна. Дахин оруулна уу."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Царай таниулах хугацаа дууслаа. Дахин оролдоно уу."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Царайг хадгалах боломжгүй байна."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Царайны үйл ажиллагааг цуцаллаа."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Хэт олон удаа оролдлоо. Дараа дахин оролдоно уу."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Хэт олон удаа оролдлоо. Царай танилтыг идэвхгүй болголоо."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Дахин оролдоно уу."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Өнгөний засвар"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Хүртээмжийн товчлол <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г асаасан"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Хүртээмжийн товчлол <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г унтраасан"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Одоогийн хүртээмжит онцлогийг эхлүүлэхийн тулд нэвтрэлтийн товчлолыг ашиглах"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Хүртээмжийн товчлуурыг товших үедээ ашиглах онцлогийг сонгоно уу:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Онцлогийг өөрчлөхийн тулд Хүртээмжийн товчлуурыг дараад хүлээнэ үү."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Томруулах"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index fe248c1..ec96ec1 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"तुमच्या या वाहकासह वाय-फाय कॉलिंग नोंदणी करताना समस्या आली आहे:<xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s वाय-फाय कॉलिंग"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> वाय-फाय कॉलिंग"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN कॉल"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN कॉल"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> वाय-फाय"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"वाय-फाय कॉलिंग | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"बंद"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"वाय-फाय अग्रमानांकित"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"प्राधान्य दिलेला मोबाइल"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"ओळखले नाही"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"फिंगरप्रिंट ऑथेंटिकेट केली आहे"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"फिंगरप्रिंट हार्डवेअर उपलब्ध नाही."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"फिंगरप्रिंट स्टोअर केले जाऊ शकत नाही. कृपया विद्यमान फिंगरप्रिंट काढा."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"फिंगरप्रिंट टाइमआउट झाले. पुन्हा प्रयत्न करा."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"चेहरा टाइमआउट झाला. पुन्हा प्रयत्न करा."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"चेहरा स्टोअर केला जाऊ शकत नाही."</string>
<string name="face_error_canceled" msgid="283945501061931023">"चेहरा ऑपरेशन रद्द केले गेले."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"खूप जास्त प्रयत्न केले. नंतर पुन्हा प्रयत्न करा."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"खूप जास्त प्रयत्न केले. चेहरा ऑथेंटिकेशन बंद केले गेले."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"पुन्हा प्रयत्न करा."</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"रंग सुधारणा"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"प्रवेशयोग्यता शॉर्टकटने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> चालू केली"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"प्रवेशयोग्यता शॉर्टकटने <xliff:g id="SERVICE_NAME">%1$s</xliff:g> बंद केली"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"सध्याचे अॅक्सेसिबिलिटी वैशिष्ट्य पुन्हा सुरू करण्यासाठी अॅक्सेसिबिलिटी शॉर्टकट वापरा"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"तुम्ही प्रवेशयोग्यता बटण दाबल्यावर वापरण्यासाठी वैशिष्ट्य निवडा:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"वैशिष्ट्ये बदलण्यासाठी, प्रवेशयोग्यता बटणाला स्पर्श करा आणि धरून ठेवा."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"मोठे करणे"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index a813a7b..7de8dc1 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Terdapat masalah semasa mendaftarkan panggilan Wi-Fi dengan pembawa anda: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Panggilan Wi-Fi"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Panggilan Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Panggilan WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Panggilan WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Panggilan Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Mati"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi diutamakan"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mudah alih diutamakan"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Tidak dikenali"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Cap jari disahkan"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Perkakasan cap jari tidak tersedia."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Cap jari tidak dapat disimpan. Sila alih keluar cap jari sedia ada."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tamat masa cap jari dicapai. Cuba lagi."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Tamat masa wajah dicapai. Cuba lagi."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Wajah tidak dapat disimpan."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Pengendalian wajah dibatalkan."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Terlalu banyak percubaan. Cuba sebentar lagi."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Terlalu banyak percubaan. Pengesahan wajah dilumpuhkan."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Cuba lagi."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Pembetulan Warna"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Pintasan kebolehaksesan menghidupkan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Pintasan Kebolehaksesan mematikan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gunakan Pintasan Kebolehaksesan sekali lagi untuk memulakan ciri kebolehaksesan semasa"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pilih ciri yang hendak digunakan apabila anda mengetik butang Kebolehaksesan:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Untuk menukar ciri, sentuh & tahan butang Kebolehaksesan."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Pembesaran"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 812ff75..9f107f8 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"သင်၏ ဝန်ဆောင်မှုပေးသူဖြင့် Wi‑Fi ခေါ်ဆိုမှုကို မှတ်ပုံတင်ရာတွင် ပြဿနာရှိနေသည်− <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi ခေါ်ဆိုမှု"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi ခေါ်ဆိုမှု"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN ခေါ်ဆိုမှု"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN ခေါ်ဆိုမှု"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi ခေါ်ဆိုမှု | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"ပိတ်ထားရသည်"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ဝိုင်ဖိုင်အား ပိုနှစ်သက်သော"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"မိုဘိုင်းကို အသုံးပြုလိုပါသည်"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"မသိပါ"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"လက်ဗွေကို အထောက်အထား စိစစ်ပြီးပါပြီ"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"လက်ဗွေရာ ဟာ့ဒ်ဝဲ မရနိုင်ပါ။"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"လက်ဗွေရာ သိုလှောင်၍မရပါ။ ကျေးဇူးပြု၍ ရှိပြီးလက်ဗွေရာအား ဖယ်ရှားပါ။"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"လက်ဗွေရာအချိန်ကုန် သွားပါသည်။ ထပ်မံကြိုးစားပါ။"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"မျက်နှာ သက်တမ်းကုန်သွားပါပြီ။ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"မျက်နှာကို သိမ်း၍မရပါ။"</string>
<string name="face_error_canceled" msgid="283945501061931023">"မျက်နှာ ဆောင်ရွက်ခြင်းကို ပယ်ဖျက်လိုက်ပါပြီ။"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"အကြိမ်များစွာ စမ်းပြီးပါပြီ။ နောက်မှထပ်စမ်းပါ။"</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"အကြိမ်များစွာ စမ်းပြီးပါပြီ။ ပိတ်လိုက်ပါပြီ။"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"ထပ်စမ်းကြည့်ပါ။"</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"အရောင်ပြင်ဆင်ခြင်း"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်သည် <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို ဖွင့်လိုက်ပါသည်"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်သည် <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို ပိတ်လိုက်ပါသည်"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"လက်ရှိ အသုံးလွယ်ရေး ဝန်ဆောင်မှုကို စတင်ရန် အသုံးလွယ်ရေး ဖြတ်လမ်းလင့်ခ်ကို သုံးပါ"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"အများသုံးစွဲနိုင်မှု ခလုတ်ကို တို့သည့်အခါ အသုံးပြုမည့် ဝန်ဆောင်မှုကို ရွေးချယ်ပါ−"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ဝန်ဆောင်မှုများကို ပြောင်းလဲရန် အများသုံးစွဲနိုင်မှု ခလုတ်ကို တို့၍ ထိထားပါ။"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ချဲ့ခြင်း"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 439b0de..d315aca 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Problem med å registrere Wi-Fi-anrop med operatøren din: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi-anrop"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi-anrop"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-anrop"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN-anrop"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi-anrop | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Av"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi er foretrukket"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Først-på-mobil"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Ikke gjenkjent"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingeravtrykket er godkjent"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Maskinvare for fingeravtrykk er ikke tilgjengelig."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingeravtrykket kan ikke lagres. Fjern et eksisterende fingeravtrykk."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tidsavbrudd for fingeravtrykk er nådd. Prøv på nytt."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Tidsavbrudd for ansikt er nådd. Prøv igjen."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Ansiktet kan ikke lagres."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Ansikt-operasjonen ble avbrutt."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"For mange forsøk. Prøv igjen senere."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"For mange forsøk. Ansiktsautentisering er slått av."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Prøv igjen."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Fargekorrigering"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Snarveien for tilgjengelighet slo på <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Snarveien for tilgjengelighet slo av <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Bruk tilgjengelighetssnarveien igjen for å starte den nåværende tilgjengelighetsfunksjonen"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Velg en funksjon du vil bruke når du trykker på Tilgjengelighet-knappen:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"For å endre funksjoner, trykk på og hold inne Tilgjengelighet-knappen."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Forstørring"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index d45e28b..c67a871 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"तपाईंको सेवा प्रदायकमार्फत Wi-Fi कलिङ सुविधा दर्ता गर्ने क्रममा देखिएको समस्या: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi कलिङ"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi कलिङ"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN कल"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN कल"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wifi कलिङ | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"निष्क्रिय"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi मनपराइयो"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"रूचाइएको मोबाइल"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"पहिचान भएन"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"फिंगरप्रिन्ट प्रमाणीकरण गरियो"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"औँठाछाप हार्डवेयर उपलब्ध छैन।"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"औँठाछाप भण्डारण गर्न सकिँदैन। कृपया अवस्थित औठाछाप हटाउनुहोस्।"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"औँठाछापको समय सकिएको छ। फेरि प्रयास गर्नुहोस्।"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"अनुहारको समय सकिएको छ। फेरि प्रयास गर्नुहोस्।"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"अनुहार भण्डारण गर्न सकिँदैन।"</string>
<string name="face_error_canceled" msgid="283945501061931023">"अनुहार पहिचान रद्द गरियो।"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"धेरैपटक प्रयासहरू भए। पछि फेरि प्रयास गर्नुहोस्।"</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"अत्यधिक धेरैपटक गलत प्रयासहरू भए। अनुहार प्रमाणिकरणलाई असक्षम पारियो।"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"फेरि प्रयास गर्नुहोस्।"</string>
@@ -1622,6 +1632,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"रङ सच्याउने सुविधा"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"पहुँचको सर्टकटले <xliff:g id="SERVICE_NAME">%1$s</xliff:g> लाई सक्रिय पार्यो"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"पहुँचको सर्टकटले <xliff:g id="SERVICE_NAME">%1$s</xliff:g> लाई निष्क्रिय पार्यो"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"हालको पहुँचसम्बन्धी सुविधा प्रयोग गर्न फेरि पहुँचसम्बन्धी सर्टकट प्रयोग गर्नुहोस्"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"तपाईंले पहुँच सम्बन्धी बटनलाई ट्याप गर्दा प्रयोग गर्नुपर्ने सुविधा रोज्नुहोस्:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"सुविधाहरूलाई बदल्न, पहुँच सम्बन्धी बटनलाई छोएर थिची राख्नुहोस्।"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"म्याग्निफिकेसन"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index df152b2..345d9d4 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -79,7 +79,7 @@
<string name="CLIRPermanent" msgid="3377371145926835671">"U kunt de instelling voor de beller-ID niet wijzigen."</string>
<string name="RestrictedOnDataTitle" msgid="5221736429761078014">"Geen service voor mobiele data"</string>
<string name="RestrictedOnEmergencyTitle" msgid="6855466023161191166">"Noodoproepen niet beschikbaar"</string>
- <string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Geen service voor spraakoproepen"</string>
+ <string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Geen belservice"</string>
<string name="RestrictedOnAllVoiceTitle" msgid="8037246983606545202">"Geen spraakservice of noodoproepen"</string>
<string name="RestrictedStateContent" msgid="6538703255570997248">"Tijdelijk uitgeschakeld door je provider"</string>
<string name="RestrictedStateContentMsimTemplate" msgid="673416791370248176">"Tijdelijk uitgeschakeld door je provider voor sim <xliff:g id="SIMNUMBER">%d</xliff:g>"</string>
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Probleem bij registratie van Bellen via wifi bij je provider: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Bellen via wifi van %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Bellen via wifi van <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Bellen via WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Bellen via WLAN van <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wifi van <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Bellen via wifi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi van <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Uit"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Voorkeur voor wifi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Voorkeur voor mobiel"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Niet herkend"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Vingerafdruk geverifieerd"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware voor vingerafdruk niet beschikbaar."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Vingerafdruk kan niet worden opgeslagen. Verwijder een bestaande vingerafdruk."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Time-out bereikt voor vingerafdruk. Probeer het opnieuw."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Time-out voor gezicht bereikt. Probeer opnieuw."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Gezicht kan niet worden opgeslagen."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Bewerking voor gezichtsherkenning geannuleerd."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Te veel pogingen. Probeer het later opnieuw."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Te veel pogingen. Gezichtsherkenning inactief."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Probeer het opnieuw."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Kleurcorrectie"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"\'Snelle link voor toegankelijkheid\' heeft <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ingeschakeld"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"\'Snelle link voor toegankelijkheid\' heeft <xliff:g id="SERVICE_NAME">%1$s</xliff:g> uitgeschakeld"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gebruik de snelkoppeling voor toegankelijkheid nogmaals om de huidige toegankelijkheidsfunctie te starten"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Kies een functie om te gebruiken wanneer je op de knop Toegankelijkheid tikt:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Als je functies wilt wijzigen, tik je op de knop Toegankelijkheid en houd je deze vast."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Vergroting"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 78566da..3e4260f 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"ଆପଣଙ୍କ କେରିଅର୍ ସହିତ ୱାଇ-ଫାଇ କଲ୍ କରିବା ପାଇଁ ପଞ୍ଜୀକରଣ କରିବାରେ ସମସ୍ୟା: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s ୱାଇ-ଫାଇ କଲିଙ୍ଗ"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> ୱାଇ-ଫାଇ କଲିଂ"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN କଲ୍"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN କଲ୍"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> ୱାଇ-ଫାଇ"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"ୱାଇଫାଇ କଲିଂ | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"ଅଫ୍"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ପସନ୍ଦ କରାଯାଇଥିବା ୱାଇ-ଫାଇ"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ପସନ୍ଦର ମୋବାଇଲ୍"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"ଚିହ୍ନଟ ହେଲାନାହିଁ"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ପ୍ରମାଣୀକୃତ ହେଲା"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ହାର୍ଡୱେର୍ ଉପଲବ୍ଧ ନାହିଁ।"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ଆଙ୍ଗୁଠି ଚିହ୍ନ ଷ୍ଟୋର୍ କରାଯାଇପାରିବ ନାହିଁ। ଦୟାକରି ପୂର୍ବରୁ ଥିବା ଆଙ୍ଗୁଠି ଚିହ୍ନକୁ ବାହାର କରିଦିଅନ୍ତୁ।"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"ଆଙ୍ଗୁଠି ଚିହ୍ନର ସମୟ ଶେଷ ହେଲା । ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"ଫେସ୍ର ସମୟସୀମା ସରିଗଲା। ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"ଫେସ୍ ମେମୋରୀରେ ଷ୍ଟୋର୍ କରାଯାଇପାରିବ ନାହିଁ।"</string>
<string name="face_error_canceled" msgid="283945501061931023">"ଫେସ୍ର ଅପରେଶନ୍ କ୍ୟାନ୍ସଲ୍ ହୋଇଗଲା"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"ବାରମ୍ବାର ଚେଷ୍ଟା। ପରେ ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"ବାରମ୍ବାର ଚେଷ୍ଟା। ଫେସ୍ ପ୍ରମାଣୀକରଣ ଅକ୍ଷମ କରାଗଲା।"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"ରଙ୍ଗ ସଂଶୋଧନ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ଆକ୍ସେସିବିଲିଟୀ ଶର୍ଟକଟ୍ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ଅନ୍ କରାଯାଇଛି"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ଆକ୍ସେସିବିଲିଟୀ ଶର୍ଟକଟ୍ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ଅଫ୍ କରାଯାଇଛି"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ବର୍ତ୍ତମାନର ଆକ୍ସେସିବିଲିଟୀ ବୈଶିଷ୍ଟ୍ୟ ଆରମ୍ଭ କରିବାକୁ ପୁଣି ଆକ୍ସେସିବିଲିଟୀ ସର୍ଟ୍କର୍ଟ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ଆପଣ ଆକ୍ସେସବିଲିଟି ବଟନ୍ ଟାପ୍ କରିବା ବେଳେ ଏକ ବୈଶିଷ୍ଟ୍ୟ ବ୍ୟବହାର କରିବାକୁ ବାଛନ୍ତୁ:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ବୈଶିଷ୍ଟ୍ୟ ବଦଳାଇବାକୁ, ଆକ୍ସେସବିଲିଟି ବଟନ୍ ସ୍ପର୍ଶ କରନ୍ତୁ ଓ ଧରିରଖନ୍ତୁ।"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ମ୍ୟାଗ୍ନିଫିକେସନ୍"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index bb38c88..bdcf2fe 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"ਤੁਹਾਡੇ ਕੈਰੀਅਰ ਨਾਲ ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ ਨੂੰ ਰਜਿਸਟਰ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ ਆਈ: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN ਕਾਲ"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN ਕਾਲ"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> ਵਾਈ-ਫਾਈ"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"ਬੰਦ"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ਤਰਜੀਹੀ ਵਾਈ-ਫਾਈ"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ਮੋਬਾਈਲ ਨੂੰ ਤਰਜੀਹ ਹੈ"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਪ੍ਰਮਾਣਿਤ ਹੋਇਆ"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਹਾਰਡਵੇਅਰ ਉਪਲਬਧ ਨਹੀਂ।"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸਟੋਰ ਨਹੀਂ ਕੀਤਾ ਸਕਦਾ। ਕਿਰਪਾ ਕਰਕੇ ਇੱਕ ਮੌਜੂਦਾ ਫਿੰਗਰਪ੍ਰਿੰਟ ਹਟਾਓ।"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਾ ਸਮਾਂ ਸਮਾਪਤ ਹੋ ਗਿਆ ਹੈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"ਚਿਹਰਾ ਪਛਾਣਨ ਦਾ ਸਮਾਂ ਸਮਾਪਤ ਹੋਇਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"ਚਿਹਰੇ ਦੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਟੋਰ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।"</string>
<string name="face_error_canceled" msgid="283945501061931023">"ਚਿਹਰਾ ਪਛਾਣਨ ਦੀ ਪ੍ਰਕਿਰਿਆ ਰੱਦ ਕੀਤੀ ਗਈ।"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"ਹੱਦੋਂ ਵੱਧ ਕੋਸ਼ਿਸ਼ਾਂ। ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"ਹੱਦੋਂ ਵੱਧ ਕੋਸ਼ਿਸ਼ਾਂ। ਚਿਹਰਾ ਪ੍ਰਮਾਣੀਕਰਨ ਬੰਦ ਹੈ।"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"ਰੰਗ ਸੁਧਾਈ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਨੇ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਚਾਲੂ ਕੀਤਾ"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਨੇ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਬੰਦ ਕੀਤਾ"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ਮੌਜੂਦਾ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਲਈ \'ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ\' ਦੀ ਦੁਬਾਰਾ ਵਰਤੋਂ ਕਰੋ"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਪਹੁੰਚਯੋਗਤਾ ਬਟਨ ਨੂੰ ਟੈਪ ਕੀਤੇ ਜਾਣ \'ਤੇ ਵਰਤਣ ਲਈ ਕੋਈ ਵਿਸ਼ੇਸ਼ਤਾ ਚੁਣੋ:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬਦਲਣ ਲਈ, ਪਹੁੰਚਯੋਗਤਾ ਬਟਨ ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾਈ ਰੱਖੋ।"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"ਵੱਡਦਰਸ਼ੀਕਰਨ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index d59b138..3e08d50 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -130,10 +130,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Podczas rejestrowania połączeń przez Wi-Fi u operatora wystąpił problem: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Połączenia przez Wi-Fi (%s)"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g>, połączenia przez Wi-Fi"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Połączenie przez WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g>, połączenie przez WLAN"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g>, Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Połączenia przez Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g>, VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Wył."</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Preferuj Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferowane komórkowe"</string>
@@ -530,6 +534,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Nie rozpoznano"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Uwierzytelniono odciskiem palca"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Czytnik linii papilarnych nie jest dostępny."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Nie można zapisać odcisku palca. Usuń istniejący odcisk palca."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Osiągnięto limit czasu odczytu linii papilarnych. Spróbuj ponownie."</string>
@@ -566,6 +574,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Upłynął limit czasu analizy twarzy. Spróbuj ponownie."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Nie można zapisać informacji o twarzy."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Analiza twarzy została anulowana."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Zbyt wiele prób. Spróbuj ponownie później."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Zbyt wiele prób. Wyłączono uwierzytelnianie za pomocą twarzy."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Spróbuj ponownie."</string>
@@ -1664,6 +1674,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Korekcja kolorów"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Skrót ułatwień dostępu wyłączył usługę <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Skrót ułatwień dostępu wyłączył usługę <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Użyj ponownie skrótu ułatwień dostępu, by uruchomić bieżące ułatwienie dostępu"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Wybierz funkcję używaną po kliknięciu przycisku ułatwień dostępu."</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Aby zmienić funkcje, kliknij i przytrzymaj przycisk ułatwień dostępu."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Powiększenie"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 48302a0..d604aab 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Ocorreu um problema ao registrar a chamada no Wi‑Fi junto à sua operadora: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s chamada Wi-Fi"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Chamada no Wi-Fi de <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Chamada por WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Chamada por WLAN de <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi de <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Chamada no Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi de <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desativado"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferido"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferência pela rede móvel"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Não reconhecido"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Impressão digital autenticada"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware de impressão digital não disponível."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Não foi possível armazenar a impressão digital. Remova uma impressão digital já existente."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tempo máximo para captura da impressão digital atingido. Tente novamente."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Tempo máx. p/ captura facial atingido. Tente novamente."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Não é possível armazenar um rosto."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Operação facial cancelada."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Excesso de tentativas. Tente novamente mais tarde."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Excesso de tentativas. Autenticação facial desat."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Tente novamente."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Correção de cor"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atalho de acessibilidade ativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O atalho de acessibilidade desativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use o atalho de acessibilidade novamente para iniciar o recurso de acessibilidade atual"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolha um recurso a ser usado ao tocar no botão Acessibilidade:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para alterar os recursos, mantenha o botão Acessibilidade pressionado."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliação"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 3f02828..cde63d5 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Ocorreu um problema ao registar a funcionalidade Chamadas Wi-Fi junto do seu operador: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Chamadas por Wi-Fi da %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Chamadas Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Chamada WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Chamada WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Chamadas Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desativado"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Rede Wi-Fi preferida"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferência pela rede móvel"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Não reconhecido."</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"A impressão digital foi autenticada."</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware de impressão digital não disponível."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Não é possível armazenar a impressão digital. Remova uma impressão digital existente."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Foi atingido o limite de tempo da impressão digital. Tente novamente."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Limite de tempo de rosto atingido. Tente novamente."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Não é possível armazenar o rosto."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Operação de rosto cancelada."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Demasiadas tentativas. Tente novamente mais tarde."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Demasiadas tentativas. Autenticação facial desativada."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Tente novamente."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Correção da cor"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O Atalho de acessibilidade ativou o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O Atalho de acessibilidade desativou o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Utilize novamente o atalho de acessibilidade para iniciar a funcionalidade de acessibilidade atual."</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolha uma funcionalidade para utilizar quando tocar no botão Acessibilidade:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para alterar as funcionalidades, toque sem soltar no botão Acessibilidade."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliação"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 48302a0..d604aab 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Ocorreu um problema ao registrar a chamada no Wi‑Fi junto à sua operadora: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s chamada Wi-Fi"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Chamada no Wi-Fi de <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Chamada por WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Chamada por WLAN de <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi de <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Chamada no Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi de <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desativado"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferido"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferência pela rede móvel"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Não reconhecido"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Impressão digital autenticada"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware de impressão digital não disponível."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Não foi possível armazenar a impressão digital. Remova uma impressão digital já existente."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tempo máximo para captura da impressão digital atingido. Tente novamente."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Tempo máx. p/ captura facial atingido. Tente novamente."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Não é possível armazenar um rosto."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Operação facial cancelada."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Excesso de tentativas. Tente novamente mais tarde."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Excesso de tentativas. Autenticação facial desat."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Tente novamente."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Correção de cor"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"O atalho de acessibilidade ativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"O atalho de acessibilidade desativou o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Use o atalho de acessibilidade novamente para iniciar o recurso de acessibilidade atual"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Escolha um recurso a ser usado ao tocar no botão Acessibilidade:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Para alterar os recursos, mantenha o botão Acessibilidade pressionado."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ampliação"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 1c95559..add43b8 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -129,10 +129,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"A apărut o problemă la înregistrarea apelării prin Wi‑Fi la operatorul dvs.: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Apelare prin Wi-Fi %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Apelare prin Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Apel WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Apel WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Apelare prin Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Dezactivată"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Se preferă conexiunea Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Se preferă datele mobile"</string>
@@ -527,6 +531,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Nu este recunoscut"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Amprentă autentificată"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware-ul pentru amprentă nu este disponibil."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Amprenta nu poate fi stocată. Eliminați o amprentă existentă."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Timpul pentru amprentare a expirat. Încercați din nou."</string>
@@ -563,6 +571,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Timpul pentru reunoaștere facială a expirat. Încercați din nou."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Chipul nu poate fi stocat."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Operațiunea privind chipul a fost anulată."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Prea multe încercări. Reîncercați mai târziu."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Prea multe încercări. Autentificarea facială este dezactivată."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Încercați din nou."</string>
@@ -1640,6 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Corecția culorii"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Comanda rapidă de accesibilitate a activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Comanda rapidă de accesibilitate a dezactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Folosiți din nou comanda rapidă Accesibilitate pentru a porni funcția de accesibilitate prezentă"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Alegeți o funcție pe care să o folosiți când atingeți butonul Accesibilitate:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Pentru a schimba funcțiile, atingeți lung butonul Accesibilitate."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Mărire"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index c14bce4..3a4ed82 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -130,10 +130,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Ошибка подключения функции \"Звонки по Wi-Fi\" через вашего оператора: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Звонки по Wi-Fi (%s)"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Звонки по Wi-Fi"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Вызов WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> Вызов WLAN"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Звонки по Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Отключено"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Приоритет Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Приоритет мобильного Интернета"</string>
@@ -530,6 +534,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Не распознано"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Отпечаток пальца проверен"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Сканер недоступен"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Чтобы сохранить новый отпечаток, удалите существующий."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Превышено время ожидания. Повторите попытку."</string>
@@ -566,6 +574,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Превышено время ожидания. Повторите попытку."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Невозможно сохранить распознанное лицо"</string>
<string name="face_error_canceled" msgid="283945501061931023">"Распознавание отменено"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Слишком много попыток. Повторите позже."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Слишком много попыток. Сканер отключен."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Попробуйте ещё раз"</string>
@@ -1664,6 +1674,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Коррекция цвета"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Сервис <xliff:g id="SERVICE_NAME">%1$s</xliff:g> включен"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Сервис <xliff:g id="SERVICE_NAME">%1$s</xliff:g> отключен"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Чтобы активировать выбранные специальные возможности, воспользуйтесь быстрым включением ещё раз"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Выберите функцию, которая запускается при нажатии кнопки специальных возможностей:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Чтобы изменить функцию, удерживайте кнопку специальных возможностей."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Увеличение"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 0f353f2..17ead66 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"ඔබගේ වාහකය සමඟ Wi-Fi ඇමතුම් ලියාපදිංචි කිරීම නිකුත් කරන්න: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi අමතමින්"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi ඇමතුම්"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN ඇමතුම"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN ඇමතුම්"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi ඇමතුම් | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"ක්රියාවිරහිතයි"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi වඩා කැමතියි"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ජංගම කැමතියි"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"හඳුනා නොගන්නා ලදී"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ඇඟිලි සලකුණ සත්යාපනය කරන ලදී"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ඇඟිලි සලකුණු දෘඪාංගය ලද නොහැකිය."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ඇඟිලි සලකුණ ගබඩා කළ නොහැක. දැනට පවතින ඇඟිලි සලකුණක් ඉවත් කරන්න."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"ඇඟිලි සලකුණු කාල නිමාව ළඟා විය. නැවත උත්සාහ කරන්න."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"මුහුණු කාල නිමාව ළඟා විය. නැවත උත්සාහ කරන්න."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"මුහුණ ගබඩා කළ නොහැක."</string>
<string name="face_error_canceled" msgid="283945501061931023">"මුහුණු මෙහෙයුම අවලංගු කරන ලදී."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"උත්සාහයන් ඉතා වැඩි ගණනකි. පසුව නැවත උත්සාහ කරන්න."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"උත්සාහයන් ඉතා වැඩි ගණනකි. මුහුණු සත්යාපනය අබල කරන ලදී."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"නැවත උත්සාහ කරන්න."</string>
@@ -1618,6 +1628,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"වර්ණ නිවැරදි කිරීම"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ප්රවේශ්යතා කෙටි මග <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්රියාත්මක කරන ලදී"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ප්රවේශ්යතා කෙටි මග <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්රියාවිරහිත කරන ලදී"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"වර්තමාන ප්රවේශ්යතා විශේෂංගය ආරම්භ කිරීම සඳහා ප්රවේශ්යතා කෙටි මග භාවිතා කරන්න"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ඔබ ප්රවේශ්යතා බොත්තම තට්ටු කරන විට භාවිතා කිරීමට අංගයක් තෝරාගන්න:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"අංග වෙනස් කිරීමට ප්රවේශ්යතා බොත්තම ස්පර්ශ කර අල්ලා ගෙන සිටින්න."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"විශාලනය"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 3109702..cb44b74 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -130,10 +130,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Pri registrácii volania cez Wi‑Fi u operátora nastala chyba <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Volanie siete Wi‑Fi %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> volanie cez Wi-Fi"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Volanie cez WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> volanie cez WLAN"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Volanie cez WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Vypnuté"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Preferovať Wi‑Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferovať mobilné spojenie"</string>
@@ -530,6 +534,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Nerozpoznané"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Odtlačok bol overený"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardvér na snímanie odtlačku prsta nie je k dispozícii"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Odtlačok prsta nie je možné uložiť. Odstráňte existujúci odtlačok."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Časový limit rozpoznania odtlačku vypršal. Skúste to znova."</string>
@@ -566,6 +574,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Limit rozpoznania tváre vypršal. Skúste to znova."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Tvár sa nedá uchovať."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Operácia týkajúca sa tváre bola zrušená"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Príliš veľa pokusov. Skúste to znova neskôr."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Príliš veľa pokusov. Overenie tváre je zakázané."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Skúste to znova."</string>
@@ -1664,6 +1674,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Úprava farieb"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Skratka dostupnosti zapla službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Skratka dostupnosti vypla službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Znova použite skratku dostupnosti, čím sprístupníte aktuálnu funkciu dostupnosti"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Klepnutím na tlačidlo dostupnosti vyberte požadovanú funkciu:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Ak chcete zmeniť funkcie, klepnite na tlačidlo dostupnosti a podržte ho"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Priblíženie"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 4575d00..039bbaa 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -130,10 +130,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Težava pri registriranju klicanja prek Wi-Fi-ja pri operaterju: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Klicanje prek Wi-Fi-ja (%s)"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Klicanje prek Wi-Fi-ja operaterja <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Klic prek omrežja WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Klic prek omrežja WLAN operaterja <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi operaterja <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Klicanje prek WiFi-ja | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"Govor prek Wi-Fi-ja operaterja <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Izklopljeno"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Prednostno Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Prednostno mobilno"</string>
@@ -530,6 +534,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Ni prepoznano"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Pristnost prstnega odtisa je preverjena"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Strojna oprema za prstne odtise ni na voljo."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Prstnega odtisa ni mogoče shraniti. Odstranite obstoječi prstni odtis."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Dosežena časovna omejitev za prstni odtis. Poskusite znova."</string>
@@ -566,6 +574,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Dosežena časovna omejitev za obraz. Poskusite znova."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Obraza ni mogoče shraniti."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Dejanje z obrazom je bilo preklicano."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Preveč poskusov. Poskusite znova pozneje."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Preveč poskusov. Preverjanje pristnosti obraza je onemogočeno."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Poskusite znova."</string>
@@ -1664,6 +1674,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Popravljanje barv"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Bližnjica funkcij za ljudi s posebnimi potrebami je vklopila <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Bližnjica funkcij za ljudi s posebnimi potrebami je izklopila <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Če želite zagnati trenutno funkcijo za ljudi s posebnimi potrebami, znova uporabite bližnjico funkcij za ljudi s posebnimi potrebami"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Izberite funkcijo, ki jo želite uporabljati, ko se dotaknete gumba »Dostopnost«:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Če želite spremeniti funkcije, se dotaknite gumba »Dostopnost« in ga pridržite."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Povečava"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 1149421..ee0960b 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Problem gjatë regjistrimit të telefonatave me Wi‑Fi me operatorin tënd celular: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Telefonatat me Wi-Fi nga %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Telefonatë me Wi-Fi në <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Telefonatë me WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Telefonatë me WLAN në <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi në <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Telefonatë me Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi në <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Çaktivizuar"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Preferohet Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Preferohet rrjeti celular"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Nuk njihet"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Gjurma e gishtit u vërtetua"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardueri i gjurmës së gishtit nuk mundësohet."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Gjurma e gishtit nuk mund të ruhet. Hiq një gjurmë gishti ekzistuese."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Koha e veprimit për gjurmën e gishtit skadoi. Provo përsëri."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Mbaroi afati për fytyrën. Provo sërish."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Fytyra nuk mund të ruhet."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Veprimi me fytyrën u anulua."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Shumë përpjekje. Provo sërish më vonë."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Shumë përpjekje. Vërtetimi për fytyrën joaktiv."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Provo sërish."</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Korrigjimi i ngjyrës"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Shkurtorja e qasshmërisë e aktivizoi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Shkurtorja e qasshmërisë e çaktivizoi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Përdor përsëri \"Shkurtoren e qasshmërisë\" për të nisur funksionin aktual të qasshmërisë"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Zgjidh një funksion për ta përdorur kur troket butonin e \"Qasshmërisë\":"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Për të ndryshuar funksionet, prek dhe mbaj butonin e \"Qasshmërisë\"."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Zmadhimi"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 7536531..6ff3a78 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -129,10 +129,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Проблем у вези са регистровањем позивања преко Wi‑Fi-ја код мобилног оператера: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Wi-Fi позивање преко оператера %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> позивање преко Wi-Fi-ја"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN позив"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN позив"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Позивање преко Wi-Fi-ја | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Искључено"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Предност има Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Желим мобилне податке"</string>
@@ -527,6 +531,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Није препознато"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Отисак прста је потврђен"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хардвер за отиске прстију није доступан."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Није могуће сачувати отисак прста. Уклоните неки од постојећих отисака прстију."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Временско ограничење за отисак прста је истекло. Пробајте поново."</string>
@@ -563,6 +571,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Истекло је време за проверу лица. Пробајте поново."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Није могуће сачувати лице."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Обрада лица је отказана."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Превише покушаја. Пробајте поново касније."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Више покушаја. Потврда идентитета је онемогућена."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Пробајте поново."</string>
@@ -1640,6 +1650,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Корекција боја"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Пречица за приступачност је укључила услугу <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Пречица за приступачност је искључила услугу <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Употребите поново пречицу за приступачност да бисте покренули актуелну функцију приступачности"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Изаберите функцију која ће се користити када додирнете дугме за приступачност:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Притисните и задржите дугме за приступачност да бисте мењали функције."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Увећање"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 31bb349..20969d3 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Följande fel uppstod när Wi-Fi-samtal skulle registreras hos operatören: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi-samtal"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Wi-Fi-samtal via <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN-samtal"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"WLAN-samtal via <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi via <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi-samtal | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi via <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Av"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi i första hand"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Använd mobildata"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Identifierades inte"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Fingeravtrycket har autentiserats"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Det finns ingen maskinvara för fingeravtryck."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Fingeravtrycket kan inte lagras. Ta bort ett befintligt fingeravtryck."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tidsgränsen för fingeravtrycket har uppnåtts. Försök igen."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Tidsgränsen för ansikte har nåtts. Försök igen."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Det gick inte att lagra ansiktet."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Ansiktsåtgärden har avbrutits."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Du har gjort för många försök. Försök igen senare."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"För många försök. Ansiktsautentisering inaktiverad"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Försök igen."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Färgkorrigering"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktiverades av Aktivera tillgänglighet snabbt"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> inaktiverades av Aktivera tillgänglighet snabbt"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Använd Aktivera tillgänglighet snabbt en gång till om du vill aktivera tillgänglighetsfunktionen i fråga"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Välj en funktion som ska användas när du trycker på tillgänglighetsknappen:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Tryck länge på tillgänglighetsknappen för att ändra funktioner."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Förstoring"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 3d26224..ce81bc7 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -128,8 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Tatizo limetokea wakati wa kuisajili huduma ya kupiga simu kupitia Wi‑Fi kwa mtoa huduma wako: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <!-- String.format failed for translation -->
- <!-- no translation found for wfcSpnFormats:0 (6830082633573257149) -->
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g>Kupiga simu Kupitia Wi-Fi"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Simu ya WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> Simu ya WLAN"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi ya <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Kupiga Simu kupitia WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi ya <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Imezimwa"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi inapedelewa"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mtandao wa simu unapendelewa"</string>
@@ -522,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Hayatambuliki"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Imethibitisha alama ya kidole"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Maunzi ya kitambulisho hayapatikani."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Kitambulisho hakiwezi kuhifadhiwa. Tafadhali ondoa kitambulisho kilichopo."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Muda wa kitambulisho umekwisha. Jaribu tena."</string>
@@ -558,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Muda wa kutambua uso umeisha. Jaribu tena."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Huwezi kuhifadhi uso."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Utendaji wa kitambulisho umeghairiwa."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Umejaribu mara nyingi mno. Jaribu tena baadaye."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Umejaribu mara nyingi mno. Kitambuzi cha uso kimezimwa."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Jaribu tena."</string>
@@ -1614,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Usahihishaji wa rangi"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Njia ya mkato ya zana za walio na matatizo ya kuona au kusikia imewasha <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Njia ya mkato ya zana za walio na matatizo ya kuona au kusikia imezima <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Tumia njia ya Mkato wa Zana za walio na matatizo ya kuona au kusikia tena ili kuanzisha kipengele kilichopo cha walio na matatizo ya kuona au kusikia"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Chagua kipengele utakachotumia, ukigonga Kitufe cha zana za walio na matatizo ya kuona au kusikia."</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Ili kubadilisha vipengele, gusa na ushikile Kitufe cha zana za walio na matatizo ya kuona au kusikia."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ukuzaji"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 35592a6..9683e4c 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"உங்கள் மொபைல் நிறுவனத்துடன் வைஃபை அழைப்பைப் பதிவுசெய்வதில் சிக்கல்: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s வைஃபை அழைப்பு"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> வைஃபை அழைப்பு"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN அழைப்பு"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN அழைப்பு"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> வைஃபை"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"வைஃபை அழைப்பு | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"ஆஃப்"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"வைஃபைக்கு முன்னுரிமை"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"மொபைல் தரவிற்கு முன்னுரிமை"</string>
@@ -514,8 +518,7 @@
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"உங்களின் படத் தொகுப்பை மாற்ற ஆப்ஸை அனுமதிக்கும்."</string>
<string name="permlab_mediaLocation" msgid="8675148183726247864">"மீடியா தொகுப்பிலிருந்து இடங்களை அறிதல்"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"உங்களின் மீடியா தொகுப்பிலிருந்து இடங்களை அறிந்துகொள்ள ஆப்ஸை அனுமதிக்கும்."</string>
- <!-- no translation found for biometric_error_hw_unavailable (645781226537551036) -->
- <skip />
+ <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"பயோமெட்ரிக் வன்பொருள் இல்லை"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"கைரேகையை ஓரளவுதான் கண்டறிய முடிந்தது. மீண்டும் முயலவும்."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"கைரேகையைச் செயலாக்க முடியவில்லை. மீண்டும் முயலவும்."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"கைரேகை உணர்வியில் தூசி உள்ளது. சுத்தம் செய்து, முயலவும்."</string>
@@ -523,9 +526,12 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"விரலை மிகவும் மெதுவாக நகர்த்திவிட்டீர்கள். மீண்டும் முயற்சிக்கவும்."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <!-- no translation found for biometric_not_recognized (5770511773560736082) -->
- <skip />
+ <string name="biometric_not_recognized" msgid="5770511773560736082">"அடையாளங்காணபடவில்லை"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"கைரேகை அங்கீகரிக்கப்பட்டது"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"கைரேகை வன்பொருள் இல்லை."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"கைரேகையைச் சேமிக்க முடியவில்லை. ஏற்கனவே உள்ள கைரேகையை அகற்றவும்."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"கைரேகைக்கான நேரம் முடிந்தது. மீண்டும் முயலவும்."</string>
@@ -562,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"முகப் பதிவிற்கான நேரம் முடிந்தது. மீண்டும் முயல்க."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"முகத்தைச் சேமிக்க இயலாது."</string>
<string name="face_error_canceled" msgid="283945501061931023">"முக அங்கீகாரச் செயல்பாடு ரத்துசெய்யப்பட்டது."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"பலமுறை முயன்றுவிட்டீர்கள். பிறகு முயலவும்."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"பலமுறை தோல்வி. முக அங்கீகாரம் முடக்கப்பட்டது."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"மீண்டும் முயலவும்."</string>
@@ -1619,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"வண்ணத் திருத்தம்"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"அணுகல்தன்மைக் குறுக்குவழியானது <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐ இயக்கியது"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"அணுகல்தன்மைக் குறுக்குவழியானது <xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐ முடக்கியது"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"தற்போதுள்ள அணுகல்தன்மை அம்சத்தை மீண்டும் தொடங்க ’அணுகல்தன்மை ஷார்ட்கட்டைப்’ பயன்படுத்தவும்"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"அணுகல்தன்மைப் பொத்தானைத் தட்டி, பயன்படுத்துவதற்கான அம்சத்தைத் தேர்ந்தெடுக்கவும்:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"அம்சங்களை மாற்ற, அணுகல்தன்மைப் பொத்தானைத் தொட்டுப் பிடித்திருக்கவும்."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"பெரிதாக்கல்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 2027d33..9757720 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"మీ క్యారియర్తో Wi‑Fi కాలింగ్ని నమోదు చేయడంలో సమస్య: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi కాలింగ్"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi కాలింగ్"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN కాల్"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN కాల్"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi కాలింగ్ | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"ఆఫ్లో ఉంది"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fiకి ప్రాధాన్యత"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"మొబైల్కి ప్రాధాన్యత ఇవ్వబడింది"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"గుర్తించలేదు"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"వేలిముద్ర ప్రమాణీకరించబడింది"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"వేలిముద్ర హార్డ్వేర్ అందుబాటులో లేదు."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"వేలిముద్రను నిల్వ చేయడం సాధ్యపడదు. దయచేసి ఇప్పటికే ఉన్న వేలిముద్రను తీసివేయండి."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"వేలిముద్ర గడువు సమయం చేరుకుంది. మళ్లీ ప్రయత్నించండి."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"ముఖ గడువు సమయం చేరుకుంది. మళ్లీ ప్రయత్నించండి."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"ముఖం నిల్వ చేయబడదు."</string>
<string name="face_error_canceled" msgid="283945501061931023">"ముఖ కార్యకలాపం రద్దయింది."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"చాలా ఎక్కువ ప్రయత్నాలు చేసారు. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"చాలా ఎక్కువ ప్రయత్నాలు చేసారు. ముఖ ప్రమాణీకరణ నిలిపివేయబడింది."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"మళ్లీ ప్రయత్నించండి."</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"రంగు సవరణ"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"యాక్సెస్ సామర్థ్య షార్ట్కట్ ద్వారా <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆన్ చేయబడింది"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"యాక్సెస్ సామర్థ్య షార్ట్కట్ ద్వారా <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆఫ్ చేయబడింది"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ప్రస్తుత యాక్సెస్ సౌలభ్య ఫీచర్ను ఉపయోగించడానికి యాక్సెసిబిలిటీ షార్ట్కట్ను మళ్లీ ప్రారంభించండి"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"యాక్సెస్ సామర్థ్య బటన్ను మీరు నొక్కినప్పుడు ఉపయోగించాల్సిన ఒక ఫీచర్ను ఎంచుకోండి:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ఫీచర్లను మార్చడానికి, యాక్సెస్ సామర్థ్య బటన్ను నొక్కి & పట్టుకోండి."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"మాగ్నిఫికేషన్"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 84fd018..89202ca 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"เกิดปัญหาในการลงทะเบียนการโทรผ่าน Wi‑Fi กับผู้ให้บริการของคุณ: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"กำลังเรียก Wi-Fi ของ %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"การโทรผ่าน Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"การโทรผ่าน WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"การโทรผ่าน WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"การโทรผ่าน Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"ปิด"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ต้องการใช้ Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ต้องการใช้อินเทอร์เน็ตมือถือ"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"ไม่รู้จัก"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"ตรวจสอบสิทธิ์ลายนิ้วมือแล้ว"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ฮาร์ดแวร์ลายนิ้วมือไม่พร้อมใช้งาน"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"ไม่สามารถเก็บลายนิ้วมือได้ โปรดนำลายนิ้วมือที่มีอยู่ออก"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"หมดเวลาใช้ลายนิ้วมือแล้ว โปรดลองอีกครั้ง"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"หมดเวลาใช้ใบหน้าแล้ว โปรดลองอีกครั้ง"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"จัดเก็บข้อมูลใบหน้าไม่ได้"</string>
<string name="face_error_canceled" msgid="283945501061931023">"ยกเลิกการดำเนินการกับใบหน้าแล้ว"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"ดำเนินการหลายครั้งเกินไป ลองอีกครั้งในภายหลัง"</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"ดำเนินการหลายครั้งเกินไป ปิดใช้การตรวจสอบสิทธิ์ด้วยใบหน้าแล้ว"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"ลองอีกครั้ง"</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"การปรับแก้สี"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ทางลัดการเข้าถึงเปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ทางลัดการเข้าถึงปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"ใช้ทางลัดการช่วยเหลือพิเศษอีกครั้งเพื่อเริ่มฟีเจอร์การช่วยเหลือพิเศษปัจจุบัน"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"เลือกฟีเจอร์ที่จะใช้เมื่อคุณแตะปุ่ม \"การเข้าถึงพิเศษ\":"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"หากต้องการเปลี่ยนฟีเจอร์ ให้แตะปุ่ม \"การเข้าถึงพิเศษ\" ค้างไว้"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"การขยาย"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 49318cf..983b53f 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Nagkaroon ng isyu sa pagrehistro ng pagtawag gamit ang Wi‑Fi sa iyong carrier: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Pagtawag sa Pamamagitan ng Wi-Fi ng %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Pagtawag Gamit ang Wi-Fi ng <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Pagtawag Gamit ang WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Pagtawag Gamit ang WLAN ng <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi ng <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Pagtawag Gamit ang Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi ng <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Naka-off"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Mas gusto ang Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mas gusto ang mobile"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Hindi nakilala"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Na-authenticate ang fingerprint"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hindi available ang hardware na ginagamitan ng fingerprint."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Hindi maiimbak ang fingerprint. Mangyaring mag-alis ng umiiral nang fingerprint."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Nag-time out ang fingerprint. Subukang muli."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Nag-time out ang mukha. Subukang muli."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Hindi ma-store ang mukha."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Nakansela ang operation kaugnay ng mukha."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Masyadong maraming pagsubok. Subukang muli mamaya."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Sobrang pagsubok. Bawal na: facial authentication."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Subukang muli."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Pagwawasto ng Kulay"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Na-on ng Shortcut sa Accessibility ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Na-off ng Shortcut sa Accessibility ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Gamiting muli ang Shortcut sa Pagiging Naa-access para simulan ang kasalukuyang feature ng pagiging naa-access"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Pumili ng feature na gagamitin kapag na-tap mo ang button ng Pagiging Naa-access:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Upang baguhin ang mga feature, pindutin nang matagal ang button ng Pagiging Naa-access."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Pag-magnify"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index c6d18ec..0315276 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Kablosuz çağrının operatörünüze kaydı sırasında hata oluştu: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Kablosuz Çağrı"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Kablosuz Çağrı"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN Üzerinden Çağrı"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN Üzerinden Çağrı"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Kablosuz"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Kablosuz Çağrı | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Kapalı"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Kablosuz bağlantı tercihli"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobil tercihli"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Tanınmadı"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Parmak izi kimlik doğrulaması yapıldı"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Parmak izi donanımı kullanılamıyor."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Parmak izi depolanamıyor. Lütfen mevcut parmak izlerinden birini kaldırın."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Parmak izi için zaman aşımı oluştu. Tekrar deneyin."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Yüz için zaman aşımı oluştu. Tekrar deneyin."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Yüz kaydedilemiyor."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Yüz işlemi iptal edildi."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Çok fazla deneme yapıldı. Daha sonra tekrar deneyin."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Çok fazla deneme yapıldı. Yüz kimlik doğrulaması devre dışı bırakıldı."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Tekrar deneyin."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Renk Düzeltme"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Erişilebilirlik Kısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini açtı"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Erişilebilirlik Kısayolu <xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini kapattı"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Geçerli erişilebilirlik özelliğini başlatmak için Erişilebilirlik Kısayolu\'nu tekrar kullanın"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Erişilebilirlik düğmesine dokunduğunuzda kullanmak üzere bir özellik seçin:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Özellikleri değiştirmek için Erişilebilirlik düğmesine dokunup basılı tutun."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Büyütme"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 6e6dd9a..88e2475 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -130,10 +130,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Проблема з реєстрацією дзвінків через Wi‑Fi у вашого оператора: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Дзвінок через Wi-Fi від оператора %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Виклики <xliff:g id="SPN">%s</xliff:g> через Wi-Fi"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Виклик через WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Виклик <xliff:g id="SPN">%s</xliff:g> через WLAN"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> через Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Виклики через Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> через VoWi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Вимкнено"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi за умовчанням"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Мобільна мережа за умовчанням"</string>
@@ -530,6 +534,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Не розпізнано"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Відбиток автентифіковано"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Апаратне забезпечення для сканування відбитка недоступне."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Не вдалося зберегти відбиток. Видаліть наявний відбиток."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Час очікування відбитка минув. Повторіть спробу."</string>
@@ -566,6 +574,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Час очікування обличчя минув. Повторіть спробу."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Не вдається зберегти обличчя."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Дію з обличчям скасовано."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Забагато спроб. Повторіть пізніше."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Забагато спроб. Автентифікацію обличчя вимкнено."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Повторіть спробу."</string>
@@ -1664,6 +1674,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Корекція кольорів"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Ярлик спеціальних можливостей увімкнув <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Ярлик спеціальних можливостей вимкнув <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Щоб запустити поточну функцію спеціальних можливостей, знову скористайтеся відповідним ярликом"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Виберіть функцію для кнопки спеціальних можливостей:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Щоб змінити функцію, натисніть і втримуйте кнопку спеціальних можливостей."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Збільшення"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 2a2ca62..6e98ebb 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"آپ کے کیریئر کے ساتھ Wi‑Fi کالنگ رجسٹر کرنے میں مسئلہ درپیش ہے: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi کالنگ"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi کالنگ"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN کال"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN کال"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi کالنگ | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"آف"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi ترجیحی"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"موبائل ترجیحی"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"تسلیم شدہ نہیں ہے"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"فنگر پرنٹ کی تصدیق ہو گئی"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"فنگر پرنٹ ہارڈ ویئر دستیاب نہیں ہے۔"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"فنگر پرنٹ اسٹور نہیں کیا جا سکتا ہے۔ براہ کرم ایک موجودہ فنگر پرنٹ ہٹائیں۔"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"فنگر پرنٹ کی میعاد ختم ہوگئی۔ دوبارہ کوشش کریں۔"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"چہرہ پہچانے کی میعاد ختم ہو گئی۔ دوبارہ کوشش کریں۔"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"چہرے کو اسٹور نہیں کیا جا سکتا۔"</string>
<string name="face_error_canceled" msgid="283945501061931023">"چہرے پر ہونے والی کارروائی منسوخ ہو گئی۔"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"کافی زیادہ کوششیں کی گئیں۔ دوبارہ کوشش کریں۔"</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"کافی زیادہ کوششیں کی گئیں۔ چہرے کی توثیق منسوخ ہو گئی۔"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"دوبارہ کوشش کریں۔"</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"رنگ کی تصحیح"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"ایکسیسبیلٹی شارٹ کٹ نے <xliff:g id="SERVICE_NAME">%1$s</xliff:g> کو آن کر دیا"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"ایکسیسبیلٹی شارٹ کٹ نے <xliff:g id="SERVICE_NAME">%1$s</xliff:g> کو آف کر دیا"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"موجودہ ایکسیسبیلٹی خصوصیت کو شروع کرنے کیلئے دوبارہ ایکسیسبیلٹی شارٹ کٹ استعمال کریں"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ایکسیسبیلٹی بٹن پر تھپتھپانے وقت استعمال کرنے کیلئے ایک خصوصیت چنیں:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"خصوصیات تبدیل کرنے کیلئے، ایکسیسبیلٹی بٹن ٹچ کریں اور دبائے رکھیں۔"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"میگنیفکیشن"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 7ffc7e7..15671d1 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Aloqa operatoringiz orqali Wi-Fi chaqiruv funksiyasinini ulashda xato: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi qo‘ng‘iroqlar"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi chaqiruv"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN chaqiruv"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN chaqiruv"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi chaqiruv | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"O‘chiq"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi afzalligi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Mobil internet afzalligi"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Aniqlanmadi"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Barmoq izi tekshirildi"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Barmoq izi skaneri ish holatida emas."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Barmoq izini saqlab bo‘lmadi. Mavjud barmoq izlaridan birini o‘chirib tashlang."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Barmoq izini aniqlash vaqti tugab qoldi. Qayta urinib ko‘ring."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Yuzni aniqlash vaqti tugadi. Qaytadan urining."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Aniqlangan yuz saqlanmadi."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Yuzni aniqlash bekor qilindi."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Juda ko‘p urinildi. Keyinroq qaytadan urining."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Juda ko‘p urinildi. Skaner faolsizlantirildi."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Qaytadan urining."</string>
@@ -1617,6 +1627,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Rangni tuzatish"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmati yoqildi"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmati o‘chirib qo‘yildi"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Joriy maxsus imkoniyatlar funksiyasini boshlash uchun tezkor ishga tushirishdan qayta foydalaning"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Maxsus imkoniyatlar tugmasi bosilganda ishga tushadigan funksiyani tanlang:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Funksiyalarni o‘zgartirish uchun Maxsus imkoniyatlar tugmasini bosib turing."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Kattalashtirish"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index a5f458b..00ebbbc 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Sự cố khi đăng ký dịch vụ gọi qua Wi‑Fi với nhà mạng của bạn: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"Gọi điện qua Wi-Fi %s"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"Gọi qua Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Cuộc gọi qua WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"Cuộc gọi qua WLAN <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"Wi-Fi <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Gọi qua Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"VoWifi <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Tắt"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Ưu tiên Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Ưu tiên dữ liệu di động"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Không nhận dạng được"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Đã xác thực vân tay"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Phần cứng vân tay không khả dụng."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Không thể lưu vân tay. Vui lòng xóa vân tay hiện có."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Đã hết thời gian chờ vân tay. Hãy thử lại."</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Đã hết thời gian chờ khuôn mặt. Hãy thử lại."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Không thể lưu khuôn mặt."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Đã hủy thao tác dùng khuôn mặt."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Bạn đã thử quá nhiều lần. Hãy thử lại sau."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Đã thử quá nhiều lần. Đã tắt xác thực khuôn mặt."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Hãy thử lại."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Sửa màu"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Đã bật phím tắt trợ năng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Đã tắt phím tắt trợ năng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Sử dụng lại Phím tắt hỗ trợ tiếp cận để bắt đầu tính năng hỗ trợ tiếp cận hiện tại"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Chọn tính năng sẽ sử dụng khi bạn nhấn nút Trợ năng:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Để thay đổi các tính năng, hãy chạm và giữ nút Trợ năng."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Phóng to"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 966a5a5..e60afa7 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"向您的运营商注册 WLAN 通话时遇到问题:<xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s WLAN 通话功能"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> WLAN 通话"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN 通话"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN 通话"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> WLAN"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WLAN 通话 | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"关闭"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"首选 WLAN"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"首选移动数据网络"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"无法识别"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"已验证指纹"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"指纹硬件无法使用。"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"无法存储指纹。请移除一个现有的指纹。"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"指纹录入操作超时,请重试。"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"面孔处理操作超时,请重试。"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"无法存储面孔。"</string>
<string name="face_error_canceled" msgid="283945501061931023">"面孔处理操作已取消。"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"尝试次数过多,请稍后重试。"</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"尝试次数过多,系统已停用人脸身份验证功能。"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"请重试。"</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"色彩校正"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"无障碍快捷方式已开启<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"无障碍快捷方式已关闭<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"再次使用无障碍快捷方式即可启动目前设置的无障碍功能"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"选择按下“无障碍”按钮时要使用的功能:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"要更改指定的功能,请触摸并按住“无障碍”按钮。"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"放大功能"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 87eb41f..cb93c61 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"向您的流動網絡供應商註冊 Wi-Fi 通話時發生問題:<xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi 通話"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi 通話"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN 通話"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN 通話"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"WiFi 通話 | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"關閉"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"首選 Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"流動數據優先"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"未能識別"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"驗證咗指紋"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"無法使用指紋軟件。"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"指紋無法儲存。請移除現有指紋。"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"指紋已逾時。請再試一次。"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"臉孔操作已逾時,請再試一次。"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"無法儲存臉孔。"</string>
<string name="face_error_canceled" msgid="283945501061931023">"臉孔操作已取消。"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"嘗試次數過多,請稍後再試。"</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"嘗試次數過多,臉孔驗證已停用。"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"請再試一次。"</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"色彩校正"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"無障礙功能快速鍵已啟用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"無障礙功能快速鍵已停用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"再用一次無障礙功能捷徑,就可以啟用宜家設定咗嘅無障礙功能"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"請選擇輕按「無障礙功能」按鈕時使用的功能:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"如要變更功能,可按住「無障礙功能」按鈕。"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"放大"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index bd36ed6..9c3d75b 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"向你的電信業者註冊 Wi‑Fi 通話時發生問題:<xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s Wi-Fi 通話"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi 通話"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"WLAN 通話"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> WLAN 通話"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Wi-Fi 通話 | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"關閉"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi 優先"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"行動網路優先"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"無法辨識"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"指紋驗證成功"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"指紋硬體無法使用。"</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"無法儲存指紋,請先移除現有指紋。"</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"指紋處理作業逾時,請再試一次。"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"臉孔處理作業逾時,請再試一次。"</string>
<string name="face_error_no_space" msgid="8224993703466381314">"無法儲存臉孔。"</string>
<string name="face_error_canceled" msgid="283945501061931023">"臉孔處理作業已取消。"</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"嘗試次數過多,請稍後再試。"</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"嘗試次數過多,臉孔驗證功能已停用。"</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"請再試一次。"</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"色彩校正"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"協助工具捷徑啟用了「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"協助工具捷徑停用了「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"再次使用協助工具捷徑即可啟動目前設定的無障礙功能"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"輕觸 [協助工具] 按鈕後,選擇你想使用的功能:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"如要變更指派的功能,請按住 [協助工具] 按鈕。"</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"放大"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index fd6614c..07c05aa 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -128,10 +128,14 @@
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7372514042696663278">"Inkinga yokubhalisa ukushaya kwe-Wi-Fi ngenkampani yakho yenethiwekhi: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
- <string-array name="wfcSpnFormats">
- <item msgid="6830082633573257149">"%s"</item>
- <item msgid="4397097370387921767">"%s ukushaya kwe-Wi-Fi"</item>
- </string-array>
+ <!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
+ <skip />
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="136001023263502280">"<xliff:g id="SPN">%s</xliff:g> ukushaya kwe-Wi-Fi"</string>
+ <string name="wfcSpnFormat_wlan_call" msgid="2533371081782489793">"Ikholi ye-WLAN"</string>
+ <string name="wfcSpnFormat_spn_wlan_call" msgid="2315240198303197168">"<xliff:g id="SPN">%s</xliff:g> ikholi ye-WLAN"</string>
+ <string name="wfcSpnFormat_spn_wifi" msgid="6546481665561961938">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="1726178784338466265">"Ukushaya kwe-WiFi | <xliff:g id="SPN">%s</xliff:g>"</string>
+ <string name="wfcSpnFormat_spn_vowifi" msgid="4444638298656953681">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"Valiwe"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Kuncanyelwa i-Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"Kuncanyelwa iselula"</string>
@@ -524,6 +528,10 @@
</string-array>
<string name="biometric_not_recognized" msgid="5770511773560736082">"Akwaziwa"</string>
<string name="fingerprint_authenticated" msgid="5309333983002526448">"Isingxivizo somunwe sigunyaziwe"</string>
+ <!-- no translation found for face_authenticated_no_confirmation_required (4018680978348659031) -->
+ <skip />
+ <!-- no translation found for face_authenticated_confirmation_required (8778347003507633610) -->
+ <skip />
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Izingxenyekazi zekhompuyutha zezingxivizo zeminwe azitholakali."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Izigxivizo zeminwe azikwazi ukugcinwa. Sicela ususe izigxivizo zeminwe ezikhona."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Kufinyelelwe isikhathi sokuvala sezigxivizo zeminwe. Zama futhi"</string>
@@ -560,6 +568,8 @@
<string name="face_error_timeout" msgid="4014326147867150054">"Kufinyelelwe kusikhathi sokuvala sobuso. Zama futhi."</string>
<string name="face_error_no_space" msgid="8224993703466381314">"Ubuso abukwazi ukugcinwa."</string>
<string name="face_error_canceled" msgid="283945501061931023">"Umsebenzi wobuso ukhanselwe."</string>
+ <!-- no translation found for face_error_user_canceled (8943921120862164539) -->
+ <skip />
<string name="face_error_lockout" msgid="3407426963155388504">"Imizamo eminingi kakhulu. Zama futhi emuva kwesikhathi."</string>
<string name="face_error_lockout_permanent" msgid="8198354656746088890">"Imizamo eminingi kakhulu. Ukufakazela ubuqiniso kobuso kukhutshaziwe."</string>
<string name="face_error_unable_to_process" msgid="238761109287767270">"Zama futhi."</string>
@@ -1616,6 +1626,7 @@
<string name="color_correction_feature_name" msgid="6779391426096954933">"Ukulungiswa kombala"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Isinqamuleli sokufinyelela sivule i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Isinqamuleli sokufinyelela sivale i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="accessibility_shortcut_spoken_feedback" msgid="6143872712930414829">"Sebenzisa isinqamuleli sokufinyelela futhi ukuze uqale isici samanje sokufinyelela"</string>
<string name="accessibility_button_prompt_text" msgid="4234556536456854251">"Khetha isici ozosisebenzisa uma uthepha inkinobho yokufinyelela:"</string>
<string name="accessibility_button_instructional_text" msgid="6942300463612999993">"Ukuze ushintshe izici, thinta uphinde ubambe inkinobho yokufinyelela."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"Ukukhuliswa"</string>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 64620f3..6d0127a4 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1439,6 +1439,10 @@
<string name="biometric_not_recognized">Not recognized</string>
<!-- Accessibility message announced when a fingerprint has been authenticated [CHAR LIMIT=NONE] -->
<string name="fingerprint_authenticated">Fingerprint authenticated</string>
+ <!-- Accessibility message announced when a face has been authenticated [CHAR LIMIT=NONE] -->
+ <string name="face_authenticated_no_confirmation_required">Face authenticated</string>
+ <!-- Accessibility message announced when a face has been authenticated, but requires the user to press the confirm button [CHAR LIMIT=NONE] -->
+ <string name="face_authenticated_confirmation_required">Face authenticated, please press confirm</string>
<!-- Error message shown when the fingerprint hardware can't be accessed -->
<string name="fingerprint_error_hw_not_available">Fingerprint hardware not available.</string>
@@ -1516,6 +1520,8 @@
<string name="face_error_no_space">Face can\u2019t be stored.</string>
<!-- Generic error message shown when the face operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user. [CHAR LIMIT=50] -->
<string name="face_error_canceled">Face operation canceled.</string>
+ <!-- Generic error message shown when the face authentication operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=50] -->
+ <string name="face_error_user_canceled">Face authentication canceled by user.</string>
<!-- Generic error message shown when the face operation fails because too many attempts have been made. [CHAR LIMIT=50] -->
<string name="face_error_lockout">Too many attempts. Try again later.</string>
<!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=50] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7b8eced..cf85986 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2429,6 +2429,7 @@
<java-symbol type="string" name="face_error_timeout" />
<java-symbol type="array" name="face_error_vendor" />
<java-symbol type="string" name="face_error_canceled" />
+ <java-symbol type="string" name="face_error_user_canceled" />
<java-symbol type="string" name="face_error_lockout" />
<java-symbol type="string" name="face_error_lockout_permanent" />
<java-symbol type="string" name="face_error_not_enrolled" />
@@ -2446,6 +2447,8 @@
<java-symbol type="string" name="face_acquired_not_detected" />
<java-symbol type="array" name="face_acquired_vendor" />
<java-symbol type="string" name="face_name_template" />
+ <java-symbol type="string" name="face_authenticated_no_confirmation_required" />
+ <java-symbol type="string" name="face_authenticated_confirmation_required" />
<!-- Face config -->
<java-symbol type="integer" name="config_faceMaxTemplatesPerUser" />
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 7bed1ac..6ce66bd 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -187,7 +187,7 @@
* {@link OnHeaderDecodedListener OnHeaderDecodedListener} and once with an
* implementation of {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}
* that calls {@link #setTargetSize} with smaller dimensions. One {@code Source}
- * even used simultaneously in multiple threads.</p>
+ * can even be used simultaneously in multiple threads.</p>
*/
public static abstract class Source {
private Source() {}
diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp
index a03b317..06e937a 100644
--- a/libs/hwui/CanvasTransform.cpp
+++ b/libs/hwui/CanvasTransform.cpp
@@ -79,7 +79,6 @@
info.fColors = _colorStorage.data();
info.fColorOffsets = _offsetStorage.data();
SkShader::GradientType type = paint.getShader()->asAGradient(&info);
- ALOGW_IF(type, "Found gradient of type = %d", type);
if (info.fColorCount <= 10) {
switch (type) {
@@ -108,6 +107,22 @@
}
}
+static BitmapPalette paletteForColorHSV(SkColor color) {
+ float hsv[3];
+ SkColorToHSV(color, hsv);
+ return hsv[2] >= .5f ? BitmapPalette::Light : BitmapPalette::Dark;
+}
+
+static BitmapPalette filterPalette(const SkPaint* paint, BitmapPalette palette) {
+ if (palette == BitmapPalette::Unknown || !paint || !paint->getColorFilter()) {
+ return palette;
+ }
+
+ SkColor color = palette == BitmapPalette::Light ? SK_ColorWHITE : SK_ColorBLACK;
+ color = paint->getColorFilter()->filterColor(color);
+ return paletteForColorHSV(color);
+}
+
bool transformPaint(ColorTransform transform, SkPaint* paint) {
// TODO
applyColorTransform(transform, *paint);
@@ -115,6 +130,7 @@
}
bool transformPaint(ColorTransform transform, SkPaint* paint, BitmapPalette palette) {
+ palette = filterPalette(paint, palette);
bool shouldInvert = false;
if (palette == BitmapPalette::Light && transform == ColorTransform::Dark) {
shouldInvert = true;
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 837d546..b772e5b 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -29,12 +29,16 @@
, mGLContextAttached(false)
, mUpdateTexImage(false)
, mLayer(nullptr) {
- renderState.registerDeferredLayerUpdater(this);
+ renderState.registerContextCallback(this);
}
DeferredLayerUpdater::~DeferredLayerUpdater() {
setTransform(nullptr);
- mRenderState.unregisterDeferredLayerUpdater(this);
+ mRenderState.removeContextCallback(this);
+ destroyLayer();
+}
+
+void DeferredLayerUpdater::onContextDestroyed() {
destroyLayer();
}
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 4c323b8..b2c5131 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -27,6 +27,7 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#include "renderstate/RenderState.h"
#include "surfacetexture/SurfaceTexture.h"
#include "Layer.h"
#include "Rect.h"
@@ -38,7 +39,7 @@
// Container to hold the properties a layer should be set to at the start
// of a render pass
-class DeferredLayerUpdater : public VirtualLightRefBase {
+class DeferredLayerUpdater : public VirtualLightRefBase, public IGpuContextCallback {
public:
// Note that DeferredLayerUpdater assumes it is taking ownership of the layer
// and will not call incrementRef on it as a result.
@@ -98,6 +99,9 @@
void destroyLayer();
+protected:
+ void onContextDestroyed() override;
+
private:
RenderState& mRenderState;
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index f61c156..04cf611 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -49,4 +49,5 @@
X(DrawPoints)
X(DrawVertices)
X(DrawAtlas)
-X(DrawShadowRec)
\ No newline at end of file
+X(DrawShadowRec)
+X(DrawVectorDrawable)
\ No newline at end of file
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 5f54c02..c30af84 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -16,6 +16,8 @@
#include "RecordingCanvas.h"
+#include "VectorDrawable.h"
+
#include "SkCanvas.h"
#include "SkData.h"
#include "SkDrawShadowInfo.h"
@@ -498,6 +500,27 @@
SkDrawShadowRec fRec;
void draw(SkCanvas* c, const SkMatrix&) const { c->private_draw_shadow_rec(fPath, fRec); }
};
+
+struct DrawVectorDrawable final : Op {
+ static const auto kType = Type::DrawVectorDrawable;
+ DrawVectorDrawable(VectorDrawableRoot* tree)
+ : mRoot(tree)
+ , mBounds(tree->stagingProperties().getBounds())
+ , palette(tree->computePalette()) {
+ // Recording, so use staging properties
+ tree->getPaintFor(&paint, tree->stagingProperties());
+ }
+
+ void draw(SkCanvas* canvas, const SkMatrix&) const {
+ mRoot->draw(canvas, mBounds, paint);
+ }
+
+ sp<VectorDrawableRoot> mRoot;
+ SkRect mBounds;
+ SkPaint paint;
+ BitmapPalette palette;
+};
+
}
template <typename T, typename... Args>
@@ -698,6 +721,9 @@
void DisplayListData::drawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
this->push<DrawShadowRec>(0, path, rec);
}
+void DisplayListData::drawVectorDrawable(VectorDrawableRoot* tree) {
+ this->push<DrawVectorDrawable>(0, tree);
+}
typedef void (*draw_fn)(const void*, SkCanvas*, const SkMatrix&);
typedef void (*void_fn)(const void*);
@@ -962,5 +988,9 @@
fDL->drawShadowRec(path, rec);
}
+void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
+ fDL->drawVectorDrawable(tree);
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index eecf51c..80c80ca 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -120,6 +120,7 @@
void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
SkBlendMode, const SkRect*, const SkPaint*);
void drawShadowRec(const SkPath&, const SkDrawShadowRec&);
+ void drawVectorDrawable(VectorDrawableRoot* tree);
template <typename T, typename... Args>
void* push(size_t, Args&&...);
@@ -205,6 +206,8 @@
SkBlendMode, const SkRect*, const SkPaint*) override;
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
+ void drawVectorDrawable(VectorDrawableRoot* tree);
+
private:
typedef SkCanvasVirtualEnforcer<SkNoDrawCanvas> INHERITED;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 9cfaa6a..d9a7cc3 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -160,7 +160,7 @@
CC_UNLIKELY(properties().getWidth() == 0) || CC_UNLIKELY(properties().getHeight() == 0) ||
CC_UNLIKELY(!properties().fitsOnLayer())) {
if (CC_UNLIKELY(hasLayer())) {
- renderthread::CanvasContext::destroyLayer(this);
+ this->setLayerSurface(nullptr);
}
return;
}
@@ -327,7 +327,7 @@
void RenderNode::destroyHardwareResources(TreeInfo* info) {
if (hasLayer()) {
- renderthread::CanvasContext::destroyLayer(this);
+ this->setLayerSurface(nullptr);
}
setStagingDisplayList(nullptr);
@@ -337,7 +337,7 @@
void RenderNode::destroyLayers() {
if (hasLayer()) {
- renderthread::CanvasContext::destroyLayer(this);
+ this->setLayerSurface(nullptr);
}
if (mDisplayList) {
mDisplayList->updateChildren([](RenderNode* child) { child->destroyLayers(); });
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 9f82d0f..dbbe9f3 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -458,29 +458,22 @@
mStagingCache.dirty = false;
}
- SkPaint tmpPaint;
- SkPaint* paint = updatePaint(&tmpPaint, &mStagingProperties);
+ SkPaint paint;
+ getPaintFor(&paint, mStagingProperties);
outCanvas->drawBitmap(*mStagingCache.bitmap, 0, 0, mStagingCache.bitmap->width(),
mStagingCache.bitmap->height(), mStagingProperties.getBounds().left(),
mStagingProperties.getBounds().top(),
mStagingProperties.getBounds().right(),
- mStagingProperties.getBounds().bottom(), paint);
+ mStagingProperties.getBounds().bottom(), &paint);
}
-SkPaint* Tree::getPaint() {
- return updatePaint(&mPaint, &mProperties);
-}
-
-// Update the given paint with alpha and color filter. Return nullptr if no color filter is
-// specified and root alpha is 1. Otherwise, return updated paint.
-SkPaint* Tree::updatePaint(SkPaint* outPaint, TreeProperties* prop) {
+void Tree::getPaintFor(SkPaint* outPaint, const TreeProperties &prop) const {
// HWUI always draws VD with bilinear filtering.
outPaint->setFilterQuality(kLow_SkFilterQuality);
- if (prop->getRootAlpha() < 1.0f || prop->getColorFilter() != nullptr) {
- outPaint->setColorFilter(sk_ref_sp(prop->getColorFilter()));
- outPaint->setAlpha(prop->getRootAlpha() * 255);
+ if (prop.getRootAlpha() < 1.0f || prop.getColorFilter() != nullptr) {
+ outPaint->setColorFilter(sk_ref_sp(prop.getColorFilter()));
+ outPaint->setAlpha(prop.getRootAlpha() * 255);
}
- return outPaint;
}
Bitmap& Tree::getBitmapUpdateIfDirty() {
@@ -553,11 +546,15 @@
mAtlasKey = INVALID_ATLAS_KEY;
}
-void Tree::draw(SkCanvas* canvas, const SkRect& bounds) {
+void Tree::draw(SkCanvas* canvas, const SkRect& bounds, const SkPaint& inPaint) {
+ // Update the paint for any animatable properties
+ SkPaint paint = inPaint;
+ paint.setAlpha(mProperties.getRootAlpha() * 255);
+
SkRect src;
sk_sp<SkSurface> vdSurface = mCache.getSurface(&src);
if (vdSurface) {
- canvas->drawImageRect(vdSurface->makeImageSnapshot().get(), src, bounds, getPaint(),
+ canvas->drawImageRect(vdSurface->makeImageSnapshot().get(), src, bounds, &paint,
SkCanvas::kFast_SrcRectConstraint);
} else {
// Handle the case when VectorDrawableAtlas has been destroyed, because of memory pressure.
@@ -570,7 +567,7 @@
int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight), bounds,
- getPaint(), SkCanvas::kFast_SrcRectConstraint);
+ &paint, SkCanvas::kFast_SrcRectConstraint);
mCache.clear();
markDirty();
}
@@ -620,6 +617,80 @@
}
}
+class MinMaxAverage {
+public:
+ void add(float sample) {
+ if (mCount == 0) {
+ mMin = sample;
+ mMax = sample;
+ } else {
+ mMin = std::min(mMin, sample);
+ mMax = std::max(mMax, sample);
+ }
+ mTotal += sample;
+ mCount++;
+ }
+
+ float average() { return mTotal / mCount; }
+
+ float min() { return mMin; }
+
+ float max() { return mMax; }
+
+ float delta() { return mMax - mMin; }
+
+private:
+ float mMin = 0.0f;
+ float mMax = 0.0f;
+ float mTotal = 0.0f;
+ int mCount = 0;
+};
+
+BitmapPalette Tree::computePalette() {
+ // TODO Cache this and share the code with Bitmap.cpp
+
+ ATRACE_CALL();
+
+ // TODO: This calculation of converting to HSV & tracking min/max is probably overkill
+ // Experiment with something simpler since we just want to figure out if it's "color-ful"
+ // and then the average perceptual lightness.
+
+ MinMaxAverage hue, saturation, value;
+ int sampledCount = 0;
+
+ // Sample a grid of 100 pixels to get an overall estimation of the colors in play
+ mRootNode->forEachFillColor([&](SkColor color) {
+ if (SkColorGetA(color) < 75) {
+ return;
+ }
+ sampledCount++;
+ float hsv[3];
+ SkColorToHSV(color, hsv);
+ hue.add(hsv[0]);
+ saturation.add(hsv[1]);
+ value.add(hsv[2]);
+ });
+
+ if (sampledCount == 0) {
+ ALOGV("VectorDrawable is mostly translucent");
+ return BitmapPalette::Unknown;
+ }
+
+ ALOGV("samples = %d, hue [min = %f, max = %f, avg = %f]; saturation [min = %f, max = %f, avg = "
+ "%f]; value [min = %f, max = %f, avg = %f]",
+ sampledCount, hue.min(), hue.max(), hue.average(), saturation.min(), saturation.max(),
+ saturation.average(), value.min(), value.max(), value.average());
+
+ if (hue.delta() <= 20 && saturation.delta() <= .1f) {
+ if (value.average() >= .5f) {
+ return BitmapPalette::Light;
+ } else {
+ return BitmapPalette::Dark;
+ }
+ }
+ return BitmapPalette::Unknown;
+}
+
}; // namespace VectorDrawable
}; // namespace uirenderer
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index af0ae05..9c0bb16 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -120,6 +120,8 @@
virtual void syncProperties() = 0;
virtual void setAntiAlias(bool aa) = 0;
+ virtual void forEachFillColor(const std::function<void(SkColor)>& func) const { }
+
protected:
std::string mName;
PropertyChangedListener* mPropertyChangedListener = nullptr;
@@ -349,6 +351,9 @@
}
}
virtual void setAntiAlias(bool aa) { mAntiAlias = aa; }
+ void forEachFillColor(const std::function<void(SkColor)>& func) const override {
+ func(mStagingProperties.getFillColor());
+ }
protected:
const SkPath& getUpdatedPath(bool useStagingData, SkPath* tempStagingPath) override;
@@ -480,6 +485,12 @@
}
}
+ void forEachFillColor(const std::function<void(SkColor)>& func) const override {
+ for (auto& child : mChildren) {
+ child->forEachFillColor(func);
+ }
+ }
+
private:
GroupProperties mProperties = GroupProperties(this);
GroupProperties mStagingProperties = GroupProperties(this);
@@ -495,8 +506,8 @@
// Copy properties from the tree and use the give node as the root node
Tree(const Tree* copy, Group* rootNode) : Tree(rootNode) {
- mStagingProperties.syncAnimatableProperties(*copy->stagingProperties());
- mStagingProperties.syncNonAnimatableProperties(*copy->stagingProperties());
+ mStagingProperties.syncAnimatableProperties(copy->stagingProperties());
+ mStagingProperties.syncNonAnimatableProperties(copy->stagingProperties());
}
// Draws the VD onto a bitmap cache, then the bitmap cache will be rendered onto the input
// canvas. Returns the number of pixels needed for the bitmap cache.
@@ -506,7 +517,6 @@
Bitmap& getBitmapUpdateIfDirty();
void setAllowCaching(bool allowCaching) { mAllowCaching = allowCaching; }
- SkPaint* getPaint();
void syncProperties() {
if (mStagingProperties.mNonAnimatablePropertiesDirty) {
mCache.dirty |= (mProperties.mNonAnimatableProperties.viewportWidth !=
@@ -618,7 +628,7 @@
};
void onPropertyChanged(TreeProperties* prop);
TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
- const TreeProperties* stagingProperties() const { return &mStagingProperties; }
+ const TreeProperties& stagingProperties() const { return mStagingProperties; }
// This should only be called from animations on RT
TreeProperties* mutateProperties() { return &mProperties; }
@@ -636,7 +646,10 @@
* Draws VD cache into a canvas. This should always be called from RT and it works with Skia
* pipelines only.
*/
- void draw(SkCanvas* canvas, const SkRect& bounds);
+ void draw(SkCanvas* canvas, const SkRect& bounds, const SkPaint& paint);
+
+ void getPaintFor(SkPaint* outPaint, const TreeProperties &props) const;
+ BitmapPalette computePalette();
/**
* Draws VD into a GPU backed surface.
@@ -680,7 +693,6 @@
skiapipeline::AtlasKey mAtlasKey = INVALID_ATLAS_KEY;
};
- SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
bool allocateBitmapIfNeeded(Cache& cache, int width, int height);
bool canReuseBitmap(Bitmap*, int width, int height);
void updateBitmapCache(Bitmap& outCache, bool useStagingData);
@@ -696,8 +708,6 @@
TreeProperties mProperties = TreeProperties(this);
TreeProperties mStagingProperties = TreeProperties(this);
- SkPaint mPaint;
-
Cache mStagingCache;
Cache mCache;
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h
index 8a44b8b..f0aa35a 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.h
+++ b/libs/hwui/hwui/AnimatedImageDrawable.h
@@ -106,7 +106,7 @@
Snapshot decodeNextFrame();
Snapshot reset();
- size_t byteSize() const { return sizeof(this) + mBytesUsed; }
+ size_t byteSize() const { return sizeof(*this) + mBytesUsed; }
protected:
virtual void onDraw(SkCanvas* canvas) override;
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 6556a64..9c28453 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -230,8 +230,6 @@
mPixelStorage.hardware.buffer = nullptr;
break;
}
-
- android::uirenderer::renderthread::RenderProxy::onBitmapDestroyed(getStableID());
}
bool Bitmap::hasHardwareMipMap() const {
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 170335d..43d457a 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -34,6 +34,8 @@
Hardware,
};
+// TODO: Find a better home for this. It's here because hwui/Bitmap is exported and CanvasTransform
+// isn't, but cleanup should be done
enum class BitmapPalette {
Unknown,
Light,
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 3b1ebd6..e8bf492 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -21,6 +21,7 @@
#include "SkiaPipeline.h"
#include "SkiaProfileRenderer.h"
#include "hwui/Bitmap.h"
+#include "private/hwui/DrawGlInfo.h"
#include "renderstate/RenderState.h"
#include "renderthread/EglManager.h"
#include "renderthread/Frame.h"
@@ -43,7 +44,13 @@
namespace skiapipeline {
SkiaOpenGLPipeline::SkiaOpenGLPipeline(RenderThread& thread)
- : SkiaPipeline(thread), mEglManager(thread.eglManager()) {}
+ : SkiaPipeline(thread), mEglManager(thread.eglManager()) {
+ thread.renderState().registerContextCallback(this);
+}
+
+SkiaOpenGLPipeline::~SkiaOpenGLPipeline() {
+ mRenderThread.renderState().removeContextCallback(this);
+}
MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() {
// TODO: Figure out why this workaround is needed, see b/13913604
@@ -135,6 +142,13 @@
return new DeferredLayerUpdater(mRenderThread.renderState());
}
+void SkiaOpenGLPipeline::onContextDestroyed() {
+ if (mEglSurface != EGL_NO_SURFACE) {
+ mEglManager.destroySurface(mEglSurface);
+ mEglSurface = EGL_NO_SURFACE;
+ }
+}
+
void SkiaOpenGLPipeline::onStop() {
if (mEglManager.isCurrent(mEglSurface)) {
mEglManager.makeCurrent(EGL_NO_SURFACE);
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index fbdf313..086a760 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -18,6 +18,8 @@
#include "SkiaPipeline.h"
+#include "renderstate/RenderState.h"
+
namespace android {
class Bitmap;
@@ -25,10 +27,10 @@
namespace uirenderer {
namespace skiapipeline {
-class SkiaOpenGLPipeline : public SkiaPipeline {
+class SkiaOpenGLPipeline : public SkiaPipeline, public IGpuContextCallback {
public:
SkiaOpenGLPipeline(renderthread::RenderThread& thread);
- virtual ~SkiaOpenGLPipeline() {}
+ virtual ~SkiaOpenGLPipeline();
renderthread::MakeCurrentResult makeCurrent() override;
renderthread::Frame getFrame() override;
@@ -50,6 +52,9 @@
static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
+protected:
+ void onContextDestroyed() override;
+
private:
renderthread::EglManager& mEglManager;
EGLSurface mEglSurface = EGL_NO_SURFACE;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 7f8abb8..2dfe7c7 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -200,10 +200,6 @@
return false;
}
-void SkiaPipeline::destroyLayer(RenderNode* node) {
- node->setLayerSurface(nullptr);
-}
-
void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
GrContext* context = thread.getGrContext();
if (context) {
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index b78dea1..ee9158c 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -54,8 +54,6 @@
std::vector<VectorDrawableRoot*>* getVectorDrawables() { return &mVectorDrawables; }
- static void destroyLayer(RenderNode* node);
-
static void prepareToDraw(const renderthread::RenderThread& thread, Bitmap* bitmap);
void renderLayersImpl(const LayerUpdateQueue& layers, bool opaque);
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 3042006e..fac07d7 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -130,25 +130,8 @@
drawDrawable(functorDrawable);
}
-class VectorDrawable : public SkDrawable {
-public:
- VectorDrawable(VectorDrawableRoot* tree)
- : mRoot(tree)
- , mBounds(tree->stagingProperties()->getBounds()) {}
-
-protected:
- virtual SkRect onGetBounds() override { return mBounds; }
- virtual void onDraw(SkCanvas* canvas) override {
- mRoot->draw(canvas, mBounds);
- }
-
-private:
- sp<VectorDrawableRoot> mRoot;
- SkRect mBounds;
-};
-
void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
- drawDrawable(mDisplayList->allocateDrawable<VectorDrawable>(tree));
+ mRecorder.drawVectorDrawable(tree);
mDisplayList->mVectorDrawables.push_back(tree);
}
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index b524bcb..fad9440 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -14,91 +14,28 @@
* limitations under the License.
*/
#include "renderstate/RenderState.h"
-#include <GpuMemoryTracker.h>
-#include "DeferredLayerUpdater.h"
-#include "Snapshot.h"
-#include "renderthread/CanvasContext.h"
-#include "renderthread/EglManager.h"
-#include "utils/GLUtils.h"
-
-#include <algorithm>
-
-#include <ui/ColorSpace.h>
+#include "renderthread/RenderThread.h"
+#include "GpuMemoryTracker.h"
namespace android {
namespace uirenderer {
-RenderState::RenderState(renderthread::RenderThread& thread)
- : mRenderThread(thread), mViewportWidth(0), mViewportHeight(0), mFramebuffer(0) {
+RenderState::RenderState(renderthread::RenderThread& thread) : mRenderThread(thread) {
mThreadId = pthread_self();
}
-RenderState::~RenderState() {
-}
-
void RenderState::onContextCreated() {
GpuMemoryTracker::onGpuContextCreated();
}
void RenderState::onContextDestroyed() {
- destroyLayersInUpdater();
+ for(auto callback : mContextCallbacks) {
+ callback->onContextDestroyed();
+ }
GpuMemoryTracker::onGpuContextDestroyed();
}
-GrContext* RenderState::getGrContext() const {
- return mRenderThread.getGrContext();
-}
-
-void RenderState::onBitmapDestroyed(uint32_t pixelRefId) {
- // DEAD CODE
-}
-
-void RenderState::setViewport(GLsizei width, GLsizei height) {
- mViewportWidth = width;
- mViewportHeight = height;
- glViewport(0, 0, mViewportWidth, mViewportHeight);
-}
-
-void RenderState::getViewport(GLsizei* outWidth, GLsizei* outHeight) {
- *outWidth = mViewportWidth;
- *outHeight = mViewportHeight;
-}
-
-void RenderState::bindFramebuffer(GLuint fbo) {
- if (mFramebuffer != fbo) {
- mFramebuffer = fbo;
- glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
- }
-}
-
-GLuint RenderState::createFramebuffer() {
- GLuint ret;
- glGenFramebuffers(1, &ret);
- return ret;
-}
-
-void RenderState::deleteFramebuffer(GLuint fbo) {
- if (mFramebuffer == fbo) {
- // GL defines that deleting the currently bound FBO rebinds FBO 0.
- // Reflect this in our cached value.
- mFramebuffer = 0;
- }
- glDeleteFramebuffers(1, &fbo);
-}
-
-void RenderState::debugOverdraw(bool enable, bool clear) {
- // DEAD CODE
-}
-
-static void destroyLayerInUpdater(DeferredLayerUpdater* layerUpdater) {
- layerUpdater->destroyLayer();
-}
-
-void RenderState::destroyLayersInUpdater() {
- std::for_each(mActiveLayerUpdaters.begin(), mActiveLayerUpdaters.end(), destroyLayerInUpdater);
-}
-
void RenderState::postDecStrong(VirtualLightRefBase* object) {
if (pthread_equal(mThreadId, pthread_self())) {
object->decStrong(nullptr);
@@ -111,13 +48,5 @@
// Render
///////////////////////////////////////////////////////////////////////////////
-void RenderState::dump() {
- // DEAD CODE
-}
-
-renderthread::RenderThread& RenderState::getRenderThread() {
- return mRenderThread;
-}
-
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index f39aa4b..ff5d02f 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -18,29 +18,26 @@
#include "utils/Macros.h"
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <private/hwui/DrawGlInfo.h>
-#include <ui/Region.h>
-#include <utils/Functor.h>
-#include <utils/Mutex.h>
#include <utils/RefBase.h>
#include <set>
-class GrContext;
-
namespace android {
namespace uirenderer {
class Layer;
-class DeferredLayerUpdater;
namespace renderthread {
class CacheManager;
-class CanvasContext;
class RenderThread;
}
+class IGpuContextCallback {
+public:
+ virtual void onContextDestroyed() = 0;
+protected:
+ virtual ~IGpuContextCallback() {}
+};
+
// wrapper of Caches for users to migrate to.
class RenderState {
PREVENT_COPY_AND_ASSIGN(RenderState);
@@ -48,66 +45,30 @@
friend class renderthread::CacheManager;
public:
- void onContextCreated();
- void onContextDestroyed();
-
- void onBitmapDestroyed(uint32_t pixelRefId);
-
- void setViewport(GLsizei width, GLsizei height);
- void getViewport(GLsizei* outWidth, GLsizei* outHeight);
-
- void bindFramebuffer(GLuint fbo);
- GLuint getFramebuffer() { return mFramebuffer; }
- GLuint createFramebuffer();
- void deleteFramebuffer(GLuint fbo);
-
- void debugOverdraw(bool enable, bool clear);
+ void registerContextCallback(IGpuContextCallback* cb) { mContextCallbacks.insert(cb); }
+ void removeContextCallback(IGpuContextCallback* cb) { mContextCallbacks.erase(cb); }
void registerLayer(Layer* layer) { mActiveLayers.insert(layer); }
void unregisterLayer(Layer* layer) { mActiveLayers.erase(layer); }
- void registerCanvasContext(renderthread::CanvasContext* context) {
- mRegisteredContexts.insert(context);
- }
-
- void unregisterCanvasContext(renderthread::CanvasContext* context) {
- mRegisteredContexts.erase(context);
- }
-
- void registerDeferredLayerUpdater(DeferredLayerUpdater* layerUpdater) {
- mActiveLayerUpdaters.insert(layerUpdater);
- }
-
- void unregisterDeferredLayerUpdater(DeferredLayerUpdater* layerUpdater) {
- mActiveLayerUpdaters.erase(layerUpdater);
- }
-
// TODO: This system is a little clunky feeling, this could use some
// more thinking...
void postDecStrong(VirtualLightRefBase* object);
- GrContext* getGrContext() const;
-
- void dump();
-
- renderthread::RenderThread& getRenderThread();
+ renderthread::RenderThread& getRenderThread() const { return mRenderThread; }
private:
- void destroyLayersInUpdater();
-
explicit RenderState(renderthread::RenderThread& thread);
- ~RenderState();
+ ~RenderState() {}
+
+ // Context notifications are only to be triggered by renderthread::RenderThread
+ void onContextCreated();
+ void onContextDestroyed();
+
+ std::set<IGpuContextCallback*> mContextCallbacks;
+ std::set<Layer*> mActiveLayers;
renderthread::RenderThread& mRenderThread;
-
- std::set<Layer*> mActiveLayers;
- std::set<DeferredLayerUpdater*> mActiveLayerUpdaters;
- std::set<renderthread::CanvasContext*> mRegisteredContexts;
-
- GLsizei mViewportWidth;
- GLsizei mViewportHeight;
- GLuint mFramebuffer;
-
pthread_t mThreadId;
};
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index ea6a851..c8c394a 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -27,7 +27,6 @@
#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "pipeline/skia/SkiaPipeline.h"
#include "pipeline/skia/SkiaVulkanPipeline.h"
-#include "renderstate/RenderState.h"
#include "utils/GLUtils.h"
#include "utils/TimeUtils.h"
#include "../Properties.h"
@@ -76,10 +75,6 @@
return nullptr;
}
-void CanvasContext::destroyLayer(RenderNode* node) {
- skiapipeline::SkiaPipeline::destroyLayer(node);
-}
-
void CanvasContext::invokeFunctor(const RenderThread& thread, Functor* functor) {
ATRACE_CALL();
auto renderType = Properties::getRenderPipelineType();
@@ -113,13 +108,11 @@
, mRenderPipeline(std::move(renderPipeline)) {
rootRenderNode->makeRoot();
mRenderNodes.emplace_back(rootRenderNode);
- mRenderThread.renderState().registerCanvasContext(this);
mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
}
CanvasContext::~CanvasContext() {
destroy();
- mRenderThread.renderState().unregisterCanvasContext(this);
for (auto& node : mRenderNodes) {
node->clearRoot();
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 8448788..2315cb9 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -96,12 +96,6 @@
*/
void unpinImages() { mRenderPipeline->unpinImages(); }
- /**
- * Destroy any layers that have been attached to the provided RenderNode removing
- * any state that may have been set during createOrUpdateLayer().
- */
- static void destroyLayer(RenderNode* node);
-
static void invokeFunctor(const RenderThread& thread, Functor* functor);
static void prepareToDraw(const RenderThread& thread, Bitmap* bitmap);
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 7a5348a..6106e24 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -345,13 +345,6 @@
}
}
-void RenderProxy::onBitmapDestroyed(uint32_t pixelRefId) {
- if (!RenderThread::hasInstance()) return;
- RenderThread& thread = RenderThread::getInstance();
- thread.queue().post(
- [&thread, pixelRefId]() { thread.renderState().onBitmapDestroyed(pixelRefId); });
-}
-
void RenderProxy::disableVsync() {
Properties::disableVsync = true;
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 969ad00..d22f56e 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -127,8 +127,6 @@
static int copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap);
- static void onBitmapDestroyed(uint32_t pixelRefId);
-
ANDROID_API static void disableVsync();
static void repackVectorDrawableAtlas();
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index a5dcc72..207673c1 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -177,7 +177,6 @@
return;
}
mEglManager->initialize();
- renderState().onContextCreated();
#ifdef HWUI_GLES_WRAP_ENABLED
debug::GlesDriver* driver = debug::GlesDriver::get();
@@ -201,7 +200,6 @@
void RenderThread::destroyGlContext() {
if (mEglManager->hasEglContext()) {
setGrContext(nullptr);
- renderState().onContextDestroyed();
mEglManager->destroy();
}
}
@@ -243,10 +241,12 @@
void RenderThread::setGrContext(sk_sp<GrContext> context) {
mCacheManager->reset(context);
if (mGrContext) {
+ mRenderState->onContextDestroyed();
mGrContext->releaseResourcesAndAbandonContext();
}
mGrContext = std::move(context);
if (mGrContext) {
+ mRenderState->onContextCreated();
DeviceInfo::setMaxTextureSize(mGrContext->maxRenderTargetSize());
}
}
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 4881172..e60d43e 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -39,7 +39,6 @@
VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {}
void VulkanManager::destroy() {
- mRenderThread.renderState().onContextDestroyed();
mRenderThread.setGrContext(nullptr);
if (VK_NULL_HANDLE != mCommandPool) {
@@ -401,8 +400,6 @@
if (Properties::enablePartialUpdates && Properties::useBufferAge) {
mSwapBehavior = SwapBehavior::BufferAge;
}
-
- mRenderThread.renderState().onContextCreated();
}
// Returns the next BackbufferInfo to use for the next draw. The function will make sure all
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index c35f512..a00b8db 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -24,6 +24,7 @@
#include <Snapshot.h>
#include <hwui/Bitmap.h>
#include <pipeline/skia/SkiaRecordingCanvas.h>
+#include <private/hwui/DrawGlInfo.h>
#include <renderstate/RenderState.h>
#include <renderthread/RenderThread.h>
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 5e5d134..680fcb3 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -382,3 +382,13 @@
SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
EXPECT_EQ(1, surface->canvas()->mDrawCounter);
}
+
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) {
+ auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
+ EXPECT_FALSE(pipeline->isSurfaceReady());
+ EXPECT_TRUE(pipeline->setSurface((Surface*)0x01, SwapBehavior::kSwap_default, ColorMode::Legacy));
+ EXPECT_TRUE(pipeline->isSurfaceReady());
+ renderThread.destroyGlContext();
+ EXPECT_FALSE(pipeline->isSurfaceReady());
+}
+
diff --git a/location/java/android/location/Address.java b/location/java/android/location/Address.java
index 335ad5e..83f05c2 100644
--- a/location/java/android/location/Address.java
+++ b/location/java/android/location/Address.java
@@ -363,7 +363,7 @@
* or null if it is unknown.
*
* @throws IllegalStateException if this Address has not been assigned
- * a latitude.
+ * a phone number.
*/
public String getPhone() {
return mPhone;
diff --git a/packages/CaptivePortalLogin/res/values-de/strings.xml b/packages/CaptivePortalLogin/res/values-de/strings.xml
index e64fb76..d8f7be9 100644
--- a/packages/CaptivePortalLogin/res/values-de/strings.xml
+++ b/packages/CaptivePortalLogin/res/values-de/strings.xml
@@ -7,6 +7,6 @@
<string name="action_bar_label" msgid="917235635415966620">"Im Netzwerk anmelden"</string>
<string name="action_bar_title" msgid="5645564790486983117">"In %1$s anmelden"</string>
<string name="ssl_error_warning" msgid="6653188881418638872">"Im Netzwerk, zu dem du eine Verbindung herstellen möchtest, liegen Sicherheitsprobleme vor."</string>
- <string name="ssl_error_example" msgid="647898534624078900">"Beispiel: Die Log-in-Seite gehört möglicherweise nicht zur angezeigten Organisation."</string>
+ <string name="ssl_error_example" msgid="647898534624078900">"Beispiel: Die Log-in-Seite gehört eventuell nicht zur angezeigten Organisation."</string>
<string name="ssl_error_continue" msgid="6492718244923937110">"Trotzdem in einem Browser fortfahren"</string>
</resources>
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 149de13..0ba37ae 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -130,6 +130,22 @@
mProbeSpec = null;
}
+ mNetworkCallback = new NetworkCallback() {
+ @Override
+ public void onLost(Network lostNetwork) {
+ // If the network disappears while the app is up, exit.
+ if (mNetwork.equals(lostNetwork)) done(Result.UNWANTED);
+ }
+ };
+ mCm.registerNetworkCallback(new NetworkRequest.Builder().build(), mNetworkCallback);
+
+ // If the network has disappeared, exit.
+ final NetworkCapabilities networkCapabilities = mCm.getNetworkCapabilities(mNetwork);
+ if (networkCapabilities == null) {
+ finishAndRemoveTask();
+ return;
+ }
+
// Also initializes proxy system properties.
mNetwork = mNetwork.getPrivateDnsBypassingCopy();
mCm.bindProcessToNetwork(mNetwork);
@@ -139,24 +155,6 @@
// setContentView initializes the WebView logic which in turn reads the system properties.
setContentView(R.layout.activity_captive_portal_login);
- // Exit app if Network disappears.
- final NetworkCapabilities networkCapabilities = mCm.getNetworkCapabilities(mNetwork);
- if (networkCapabilities == null) {
- finishAndRemoveTask();
- return;
- }
- mNetworkCallback = new NetworkCallback() {
- @Override
- public void onLost(Network lostNetwork) {
- if (mNetwork.equals(lostNetwork)) done(Result.UNWANTED);
- }
- };
- final NetworkRequest.Builder builder = new NetworkRequest.Builder();
- for (int transportType : networkCapabilities.getTransportTypes()) {
- builder.addTransportType(transportType);
- }
- mCm.registerNetworkCallback(builder.build(), mNetworkCallback);
-
getActionBar().setDisplayShowHomeEnabled(false);
getActionBar().setElevation(0); // remove shadow
getActionBar().setTitle(getHeaderTitle());
diff --git a/packages/CarrierDefaultApp/res/values-de/strings.xml b/packages/CarrierDefaultApp/res/values-de/strings.xml
index 927b8f0..95639ad 100644
--- a/packages/CarrierDefaultApp/res/values-de/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-de/strings.xml
@@ -12,6 +12,6 @@
<string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Status der mobilen Datennutzung"</string>
<string name="action_bar_label" msgid="4290345990334377177">"Bei Mobilfunknetz anmelden"</string>
<string name="ssl_error_warning" msgid="3127935140338254180">"Im Netzwerk, zu dem du eine Verbindung herstellen möchtest, liegen Sicherheitsprobleme vor."</string>
- <string name="ssl_error_example" msgid="6188711843183058764">"Beispiel: Die Log-in-Seite gehört möglicherweise nicht zur angezeigten Organisation."</string>
+ <string name="ssl_error_example" msgid="6188711843183058764">"Beispiel: Die Log-in-Seite gehört eventuell nicht zur angezeigten Organisation."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Trotzdem in einem Browser fortfahren"</string>
</resources>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
index deb6163..9f38d48 100755
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
@@ -137,6 +137,7 @@
UID_UNKNOWN);
params.installerPackageName =
getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME);
+ params.installReason = PackageManager.INSTALL_REASON_USER;
File file = new File(mPackageURI.getPath());
try {
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index c02e3c7..e46ff15 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -103,7 +103,7 @@
<item msgid="3199660090246166812">"Querformat"</item>
</string-array>
<string name="print_write_error_message" msgid="5787642615179572543">"Fehler beim Schreiben in Datei"</string>
- <string name="print_error_default_message" msgid="8602678405502922346">"Fehler. Bitte versuche es erneut."</string>
+ <string name="print_error_default_message" msgid="8602678405502922346">"Fehler. Bitte versuche es noch einmal."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Erneut versuchen"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Dieser Drucker ist momentan nicht verfügbar."</string>
<string name="print_cannot_load_page" msgid="6179560924492912009">"Vorschau kann nicht angezeigt werden"</string>
diff --git a/packages/SettingsLib/HelpUtils/res/values-ml/strings.xml b/packages/SettingsLib/HelpUtils/res/values-ml/strings.xml
index d2a7452..731257e 100644
--- a/packages/SettingsLib/HelpUtils/res/values-ml/strings.xml
+++ b/packages/SettingsLib/HelpUtils/res/values-ml/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="help_feedback_label" msgid="4550436169116444686">"സഹായം & ഫീഡ്ബാക്ക്"</string>
+ <string name="help_feedback_label" msgid="4550436169116444686">"സഹായവും ഫീഡ്ബാക്കും"</string>
</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-af/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-af/strings.xml
new file mode 100644
index 0000000..dced02c
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-af/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Geaktiveer deur administrateur"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Gedeaktiveer deur administrateur"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-am/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-am/strings.xml
new file mode 100644
index 0000000..d13be0c
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-am/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"በአስተዳዳሪ ነቅቷል"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"በአስተዳዳሪ ተሰናክሏል"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ar/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ar/strings.xml
new file mode 100644
index 0000000..15c0010
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ar/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"فعَّل المشرف هذا الإعداد."</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"أوقف المشرف هذا الإعداد."</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-as/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-as/strings.xml
new file mode 100644
index 0000000..7a3b8e4
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-as/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"প্ৰশাসকে সক্ষম কৰিছে"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"প্ৰশাসকে অক্ষম কৰিছে"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-az/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-az/strings.xml
new file mode 100644
index 0000000..d1434bd
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-az/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Admin tərəfindən aktiv edildi"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Admin tərəfindən deaktiv edildi"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..ee61192
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Administrator je omogućio"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Administrator je onemogućio"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-be/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-be/strings.xml
new file mode 100644
index 0000000..2d13d45
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-be/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Уключана адміністратарам"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Адключана адміністратарам"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-bg/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-bg/strings.xml
new file mode 100644
index 0000000..361910c
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-bg/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Активирано от администратора"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Деактивирано от администратора"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-bn/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-bn/strings.xml
new file mode 100644
index 0000000..7609166
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-bn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"অ্যাডমিন চালু করেছেন"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"অ্যাডমিন বন্ধ করেছেন"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-bs/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-bs/strings.xml
new file mode 100644
index 0000000..9704095
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-bs/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Omogućio administrator"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Onemogućio administrator"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ca/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ca/strings.xml
new file mode 100644
index 0000000..5569664
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ca/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Activat per l\'administrador"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Desactivat per l\'administrador"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-cs/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-cs/strings.xml
new file mode 100644
index 0000000..f8120aa
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-cs/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Zapnuto administrátorem"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Vypnuto administrátorem"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml
new file mode 100644
index 0000000..d75f27b
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Aktiveret af administratoren"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Deaktiveret af administratoren"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-de/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-de/strings.xml
new file mode 100644
index 0000000..3ef46d9
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-de/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Vom Administrator aktiviert"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Vom Administrator deaktiviert"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-el/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-el/strings.xml
new file mode 100644
index 0000000..643686e
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-el/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Ενεργοποιήθηκε από τον διαχειριστή"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Απενεργοποιήθηκε από τον διαχειριστή"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rAU/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..69c0bc3
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rAU/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Enabled by admin"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Disabled by admin"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rCA/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..69c0bc3
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rCA/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Enabled by admin"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Disabled by admin"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rGB/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..69c0bc3
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rGB/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Enabled by admin"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Disabled by admin"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rIN/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..69c0bc3
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rIN/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Enabled by admin"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Disabled by admin"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-en-rXC/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..f329a76
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-en-rXC/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Enabled by admin"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Disabled by admin"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-es-rUS/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..451ea35
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-es-rUS/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"El administrador habilitó la opción"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"El administrador inhabilitó la opción"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-es/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-es/strings.xml
new file mode 100644
index 0000000..3407d13
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-es/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Habilitada por el administrador"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Inhabilitada por el administrador"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-et/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-et/strings.xml
new file mode 100644
index 0000000..98bad62
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-et/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Administraatori lubatud"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Administraatori keelatud"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml
new file mode 100644
index 0000000..1641a31
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Administratzaileak gaitu egin du"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Administratzaileak desgaitu egin du"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml
new file mode 100644
index 0000000..f4c8334
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"فعالشده توسط سرپرست"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"غیرفعالشده توسط سرپرست"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-fi/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-fi/strings.xml
new file mode 100644
index 0000000..dd62c1a
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-fi/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Järjestelmänvalvojan sallima"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Järjestelmänvalvojan estämä"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-fr-rCA/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..85ec907
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-fr-rCA/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Activé par l\'administrateur"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Désactivé par l\'administrateur"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-fr/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-fr/strings.xml
new file mode 100644
index 0000000..85ec907
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-fr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Activé par l\'administrateur"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Désactivé par l\'administrateur"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-gl/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-gl/strings.xml
new file mode 100644
index 0000000..0d67cc2
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-gl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Opción activada polo administrador"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Opción desactivada polo administrador"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-gu/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-gu/strings.xml
new file mode 100644
index 0000000..076c1be
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-gu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"વ્યવસ્થાપકે ચાલુ કરેલ"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"વ્યવસ્થાપકે બંધ કરેલ"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml
new file mode 100644
index 0000000..75d103f
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"एडमिन की ओर से चालू किया गया"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"एडमिन की ओर से बंद किया गया"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-hr/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-hr/strings.xml
new file mode 100644
index 0000000..9704095
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-hr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Omogućio administrator"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Onemogućio administrator"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-hu/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-hu/strings.xml
new file mode 100644
index 0000000..be1cb97
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-hu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"A rendszergazda bekapcsolta"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"A rendszergazda kikapcsolta"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-hy/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-hy/strings.xml
new file mode 100644
index 0000000..78dab28
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-hy/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Միացված է ադմինիստրատորի կողմից"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Անջատվել է ադմինիստրատորի կողմից"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-in/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-in/strings.xml
new file mode 100644
index 0000000..824ddde
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-in/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Diaktifkan oleh admin"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Dinonaktifkan oleh admin"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-is/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-is/strings.xml
new file mode 100644
index 0000000..0707a67
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-is/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Gert virkt af kerfisstjóra"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Gert óvirkt af kerfisstjóra"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-it/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-it/strings.xml
new file mode 100644
index 0000000..084a47b
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-it/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Attivata dall\'amministratore"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Disattivata dall\'amministratore"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-iw/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-iw/strings.xml
new file mode 100644
index 0000000..fca5986
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-iw/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"מופעל על ידי מנהל המכשיר"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"הושבת על ידי מנהל המכשיר"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ja/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ja/strings.xml
new file mode 100644
index 0000000..1c077b6
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ja/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"管理者が有効にしました"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"管理者が無効にしました"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ka/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ka/strings.xml
new file mode 100644
index 0000000..9ecf6b3
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ka/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"ჩართულია ადმინისტრატორის მიერ"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"გათიშულია ადმინისტრატორის მიერ"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-kk/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-kk/strings.xml
new file mode 100644
index 0000000..552e02e
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-kk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Әкімші қосқан"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Әкімші өшірген"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-km/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-km/strings.xml
new file mode 100644
index 0000000..aff5d30
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-km/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"បើកដោយអ្នកគ្រប់គ្រង"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"បិទដោយអ្នកគ្រប់គ្រង"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-kn/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-kn/strings.xml
new file mode 100644
index 0000000..99bd4d5
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-kn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"ನಿರ್ವಾಹಕರು ಸಕ್ರಿಯಗೊಳಿಸಿದ್ದಾರೆ"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"ನಿರ್ವಾಹಕರು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿದ್ದಾರೆ"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ko/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ko/strings.xml
new file mode 100644
index 0000000..d7b0b44
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ko/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"관리자가 사용 설정함"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"관리자가 사용 중지함"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ky/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ky/strings.xml
new file mode 100644
index 0000000..df3b559
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ky/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Администратор иштетип койгон"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Администратор өчүрүп койгон"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-lo/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-lo/strings.xml
new file mode 100644
index 0000000..fca6d1b
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-lo/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"ເປີດນຳໃຊ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບ"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"ຖືກຜູ້ເບິ່ງແຍງລະບົບປິດໄວ້"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-lt/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-lt/strings.xml
new file mode 100644
index 0000000..0bd27bc
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-lt/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Įgalino administratorius"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Išjungė administratorius"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-lv/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-lv/strings.xml
new file mode 100644
index 0000000..9c5f693
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-lv/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Iespējoja administrators"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Atspējoja administrators"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-mk/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-mk/strings.xml
new file mode 100644
index 0000000..b0fb0a8
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-mk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Овозможено од администраторот"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Оневозможено од администраторот"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ml/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ml/strings.xml
new file mode 100644
index 0000000..dd9c229
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ml/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"അഡ്മിൻ പ്രവർത്തനക്ഷമമാക്കി"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"അഡ്മിൻ പ്രവർത്തനരഹിതമാക്കി"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-mn/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-mn/strings.xml
new file mode 100644
index 0000000..d32c2ca
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-mn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Админ идэвхжүүлсэн"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Админ цуцалсан"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-mr/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-mr/strings.xml
new file mode 100644
index 0000000..06fdf6f
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-mr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"प्रशासकाने सुरू केलेले"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"प्रशासकाने बंद केलेले"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ms/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ms/strings.xml
new file mode 100644
index 0000000..aabfb7c
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ms/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Didayakan oleh pentadbir"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Dilumpuhkan oleh pentadbir"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-my/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-my/strings.xml
new file mode 100644
index 0000000..daa4614
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-my/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"စီမံခန့်ခွဲသူက ဖွင့်ထားသည်"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"စီမံခန့်ခွဲသူက ပိတ်ထားသည်"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-nb/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-nb/strings.xml
new file mode 100644
index 0000000..becbb91
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-nb/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Aktivert av administratoren"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Deaktivert av administratoren"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ne/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ne/strings.xml
new file mode 100644
index 0000000..63ef646
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ne/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"प्रशासकद्वारा सक्षम पारिएको"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"प्रशासकद्वारा असक्षम पारिएको"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-nl/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-nl/strings.xml
new file mode 100644
index 0000000..5d7a85e
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-nl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Ingeschakeld door beheerder"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Uitgeschakeld door beheerder"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml
new file mode 100644
index 0000000..fee0d39
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"ବ୍ୟବସ୍ଥାପକଙ୍କ ଦ୍ୱାରା ସକ୍ଷମ କରାଯାଇଛି"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"ବ୍ୟବସ୍ଥାପକଙ୍କ ଦ୍ଵାରା ଅକ୍ଷମ କରାଯାଇଛି"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pa/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pa/strings.xml
new file mode 100644
index 0000000..2765cabd
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pa/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pl/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pl/strings.xml
new file mode 100644
index 0000000..d9e06b6
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Włączone przez administratora"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Wyłączone przez administratora"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rBR/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..1ad4b6b
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rBR/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Ativado pelo administrador"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Desativado pelo administrador"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..f86a73f
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Ativada pelo administrador"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Desativada pelo administrador"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pt/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pt/strings.xml
new file mode 100644
index 0000000..1ad4b6b
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pt/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Ativado pelo administrador"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Desativado pelo administrador"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ro/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ro/strings.xml
new file mode 100644
index 0000000..ff8c2aa
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ro/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Activat de administrator"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Dezactivat de administrator"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ru/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ru/strings.xml
new file mode 100644
index 0000000..d4dfb1c
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ru/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Включено администратором"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Отключено администратором"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-si/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-si/strings.xml
new file mode 100644
index 0000000..7c8520b
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-si/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"පරිපාලක විසින් සබල කර ඇත"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"ඔබගේ පරිපාලක විසින් අබල කර ඇත"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sk/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sk/strings.xml
new file mode 100644
index 0000000..7a9c1cc
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Povolené správcom"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Zakázané správcom"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sl/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sl/strings.xml
new file mode 100644
index 0000000..4926641
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Omogočil skrbnik"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Onemogočil skrbnik"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sq/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sq/strings.xml
new file mode 100644
index 0000000..5f9dc59
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sq/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Aktivizuar nga administratori"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Çaktivizuar nga administratori"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sr/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sr/strings.xml
new file mode 100644
index 0000000..2d1ac54
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Администратор је омогућио"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Администратор је онемогућио"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sv/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sv/strings.xml
new file mode 100644
index 0000000..6af3776
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sv/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Aktiverad av administratör"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Inaktiverad av administratören"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-sw/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-sw/strings.xml
new file mode 100644
index 0000000..08526f8
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-sw/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Imewashwa na msimamizi"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Imezimwa na msimamizi"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ta/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ta/strings.xml
new file mode 100644
index 0000000..405fb7c
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ta/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"நிர்வாகி இயக்கியுள்ளார்"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"நிர்வாகி முடக்கியுள்ளார்"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml
new file mode 100644
index 0000000..462f02e
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"నిర్వాహకులు ప్రారంభించారు"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"నిర్వాహకులు నిలిపివేసారు"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-th/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-th/strings.xml
new file mode 100644
index 0000000..e654ba1
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-th/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"เปิดใช้โดยผู้ดูแลระบบ"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"ปิดใช้โดยผู้ดูแลระบบ"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-tl/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-tl/strings.xml
new file mode 100644
index 0000000..f80cefa
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-tl/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Na-enable ng admin"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Na-disable ng admin"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-tr/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-tr/strings.xml
new file mode 100644
index 0000000..9dd4713
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-tr/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Yönetici tarafından etkinleştirildi"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Yönetici tarafından devre dışı bırakıldı"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-uk/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-uk/strings.xml
new file mode 100644
index 0000000..5096921
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-uk/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Увімкнено адміністратором"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Вимкнено адміністратором"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-ur/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-ur/strings.xml
new file mode 100644
index 0000000..7e70936
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-ur/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"منتظم کی طرف سے فعال کردہ"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"منتظم کی طرف سے غیر فعال کردہ"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-uz/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-uz/strings.xml
new file mode 100644
index 0000000..a402af6
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-uz/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Administrator tomonidan yoqilgan"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Administrator tomonidan faolsizlantirilgan"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml
new file mode 100644
index 0000000..dd993df
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Do quản trị viên bật"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Bị quản trị viên tắt"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rCN/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..2aab9ac
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rCN/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"已被管理员启用"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"已被管理员停用"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rHK/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..cb3163a
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rHK/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"已由管理員啟用"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"已由管理員停用"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rTW/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..cb3163a
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-zh-rTW/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"已由管理員啟用"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"已由管理員停用"</string>
+</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-zu/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-zu/strings.xml
new file mode 100644
index 0000000..313c9eb
--- /dev/null
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-zu/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="enabled_by_admin" msgid="7797093432952898000">"Kunikwe amandla umlawuli"</string>
+ <string name="disabled_by_admin" msgid="1910810467107358241">"Kukhutshazwe umlawuli"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index aa96444..b77d4e5 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Ingeprop; kan nie op die oomblik laai nie"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Vol"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Beheer deur administrateur"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Geaktiveer deur administrateur"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Gedeaktiveer deur administrateur"</string>
<string name="disabled" msgid="9206776641295849915">"Gedeaktiveer"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Toegelaat"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Nie toegelaat nie"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 452206c..836ec80 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"ተሰክቷል፣ አሁን ኃይል መሙላት አይቻልም"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ሙሉነው"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"በአስተዳዳሪ ቁጥጥር የተደረገበት"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"በአስተዳዳሪ ነቅቷል"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"በአስተዳዳሪ ተሰናክሏል"</string>
<string name="disabled" msgid="9206776641295849915">"ቦዝኗል"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"ይፈቀዳል"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"አይፈቀድም"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index e67e1ec..5c11db1 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"تم التوصيل، ولكن يتعذّر الشحن الآن"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ممتلئة"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"إعدادات يتحكم فيها المشرف"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"تم تفعيل الإعداد بواسطة المشرف"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"تم إيقاف الإعداد بواسطة المشرف"</string>
<string name="disabled" msgid="9206776641295849915">"غير مفعّل"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"مسموح به"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"غير مسموح به"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 7311661..ddd17daf 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"প্লাগ কৰি থোৱা হৈছে, এই মুহূৰ্তত চ্চাৰ্জ কৰিব নোৱাৰি"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"পূৰ্ণ"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"এডমিনৰ দ্বাৰা নিয়ন্ত্ৰিত"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"প্ৰশাসকে সক্ষম কৰিছে"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"এডমিনে অক্ষম কৰিছে ৰাখিছে"</string>
<string name="disabled" msgid="9206776641295849915">"নিষ্ক্ৰিয়"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"অনুমতি দিয়া হৈছে"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"অনুমতি দিয়া হোৱা নাই"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 750bf5d..a6e484f 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Cihaz hazırda batareya yığa bilmir"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Tam"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Admin tərəfindən nəzarət olunur"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Admin tərəfindən aktiv edildi"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Admin tərəfindən deaktiv edildi"</string>
<string name="disabled" msgid="9206776641295849915">"Deaktiv"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"İcazə verilib"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"İcazə verilməyib"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index cd8096c..a446845 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Priključeno je, ali punjenje trenutno nije moguće"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Puna"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontroliše administrator"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Omogućio je administrator"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Administrator je onemogućio"</string>
<string name="disabled" msgid="9206776641295849915">"Onemogućeno"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Dozvoljeno"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Nije dozvoljeno"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 072913a..d56db13 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Падключана да сеткі сілкавання, зарадзіць зараз немагчыма"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Поўная"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Кантралюецца адміністратарам"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Уключана адміністратарам"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Адключана адміністратарам"</string>
<string name="disabled" msgid="9206776641295849915">"Адключанае"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Дазволена"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Забаронена"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index a5ce523..c1bc31c 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Включена в захранването, в момента не се зарежда"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Пълна"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролира се от администратор"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Активирано от администратора"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Деактивирано от администратора"</string>
<string name="disabled" msgid="9206776641295849915">"Деактивирано"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Има разрешение"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Няма разрешение"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index c053771..1550c00 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"প্লাগ-ইন করা হয়েছে কিন্তু এখনই চার্জ করা যাবে না"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"পূর্ণ"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"প্রশাসকের দ্বারা নিয়ন্ত্রিত"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"প্রশাসক দ্বারা সক্ষম করা হয়েছে"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"প্রশাসক দ্বারা অক্ষম করা হয়েছে"</string>
<string name="disabled" msgid="9206776641295849915">"অক্ষম হয়েছে"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"অনুমোদিত"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"অনুমোদিত নয়"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 764bc19..460e7cf 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Priključen, trenutno se ne može puniti"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Puna"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Pod kontrolom administratora"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Omogućio administrator"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Onemogućio administrator"</string>
<string name="disabled" msgid="9206776641295849915">"Onemogućeno"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Dozvoljeno"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Nije dozvoljeno"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 8309c41a..72dd8cf 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"El dispositiu està endollat però en aquests moments no es pot carregar"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Plena"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlat per l\'administrador"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Activada per l\'administrador"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Desactivada per l\'administrador"</string>
<string name="disabled" msgid="9206776641295849915">"Desactivat"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Amb permís"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Sense permís"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index bd8bc2b..de02245 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Zapojeno, ale nelze nabíjet"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Nabitá"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Spravováno administrátorem"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Zapnuto administrátorem"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Zakázáno administrátorem"</string>
<string name="disabled" msgid="9206776641295849915">"Deaktivováno"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Povoleno"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Není povoleno"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index ab81346..34608d3 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Enheden er tilsluttet en strømkilde. Det er ikke muligt at oplade på nuværende tidspunkt."</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Fuldt"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolleret af administratoren"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Aktiveret af administratoren"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Deaktiveret af administratoren"</string>
<string name="disabled" msgid="9206776641295849915">"Deaktiveret"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Tilladt"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Ikke tilladt"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 2432a10..79965d2 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -348,7 +348,7 @@
<string name="runningservices_settings_summary" msgid="854608995821032748">"Momentan ausgeführte Dienste anzeigen und steuern"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-Implementierung"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView-Implementierung festlegen"</string>
- <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Diese Auswahl ist nicht mehr gültig. Versuche es erneut."</string>
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Diese Auswahl ist nicht mehr gültig. Bitte versuche es noch einmal."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Zu Dateiverschlüsselung wechseln"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Wechseln…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Dateiverschlüsselung wird bereits verwendet."</string>
@@ -379,12 +379,12 @@
<string name="power_remaining_less_than_duration" msgid="5751885147712659423">"Weniger als <xliff:g id="THRESHOLD">%1$s</xliff:g> verbleibend (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_more_than_subtext" msgid="3176771815132876675">"Mehr als <xliff:g id="TIME_REMAINING">%1$s</xliff:g> verbleibend (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_only_more_than_subtext" msgid="8931654680569617380">"Mehr als <xliff:g id="TIME_REMAINING">%1$s</xliff:g> verbleibend"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="1181059207608751924">"Smartphone wird möglicherweise bald ausgeschaltet"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="2606370266981054691">"Tablet wird möglicherweise bald ausgeschaltet"</string>
- <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="2918084807716859985">"Gerät wird möglicherweise bald ausgeschaltet"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="3090926004324573908">"Smartphone wird möglicherweise bald ausgeschaltet (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7466484148515796216">"Tablet wird möglicherweise bald ausgeschaltet (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
- <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="603933521600231649">"Gerät wird möglicherweise bald ausgeschaltet (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
+ <string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="1181059207608751924">"Smartphone wird eventuell bald ausgeschaltet"</string>
+ <string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="2606370266981054691">"Tablet wird eventuell bald ausgeschaltet"</string>
+ <string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="2918084807716859985">"Gerät wird eventuell bald ausgeschaltet"</string>
+ <string name="power_remaining_duration_shutdown_imminent" product="default" msgid="3090926004324573908">"Smartphone wird eventuell bald ausgeschaltet (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
+ <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7466484148515796216">"Tablet wird eventuell bald ausgeschaltet (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
+ <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="603933521600231649">"Gerät wird eventuell bald ausgeschaltet (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> bis zur vollständigen Aufladung"</string>
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> bis vollständig geladen"</string>
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Angeschlossen, kann derzeit nicht geladen werden"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Voll"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Durch den Administrator verwaltet"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Vom Administrator aktiviert"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Vom Administrator deaktiviert"</string>
<string name="disabled" msgid="9206776641295849915">"Deaktiviert"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Zulässig"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Nicht zulässig"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 6f2889c..b9ea843 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Συνδέθηκε, δεν είναι δυνατή η φόρτιση αυτήν τη στιγμή"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Πλήρης"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Ελέγχονται από το διαχειριστή"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Ενεργοποιήθηκε από τον διαχειριστή"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Απενεργοποιήθηκε από τον διαχειριστή"</string>
<string name="disabled" msgid="9206776641295849915">"Απενεργοποιημένο"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Επιτρέπεται"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Δεν επιτρέπεται"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 154aa7d..1a7d7c5 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge right now"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Enabled by admin"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Disabled by admin"</string>
<string name="disabled" msgid="9206776641295849915">"Disabled"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Allowed"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Not allowed"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 154aa7d..1a7d7c5 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge right now"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Enabled by admin"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Disabled by admin"</string>
<string name="disabled" msgid="9206776641295849915">"Disabled"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Allowed"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Not allowed"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 154aa7d..1a7d7c5 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge right now"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Enabled by admin"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Disabled by admin"</string>
<string name="disabled" msgid="9206776641295849915">"Disabled"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Allowed"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Not allowed"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 154aa7d..1a7d7c5 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge right now"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Enabled by admin"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Disabled by admin"</string>
<string name="disabled" msgid="9206776641295849915">"Disabled"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Allowed"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Not allowed"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index e9746c0..2bfd5b1 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge right now"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Enabled by admin"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Disabled by admin"</string>
<string name="disabled" msgid="9206776641295849915">"Disabled"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Allowed"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Not allowed"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 706e1d3..790c0d3 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Conectado. No se puede cargar en este momento"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Cargado"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada por el administrador"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"El administrador habilitó esta opción"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"El administrador inhabilitó esta opción"</string>
<string name="disabled" msgid="9206776641295849915">"Inhabilitada"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Permitida"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"No permitida"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index f9eddd9..1dec85d 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Se ha conectado, pero no se puede cargar en este momento"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Completa"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada por el administrador"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Habilitada por el administrador"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Inhabilitado por el administrador"</string>
<string name="disabled" msgid="9206776641295849915">"Inhabilitada"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Autorizadas"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"No autorizadas"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index ac31880..406e15d 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Vooluvõrgus, praegu ei saa laadida"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Täis"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Juhib administraator"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Administraatori lubatud"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Administraatori keelatud"</string>
<string name="disabled" msgid="9206776641295849915">"Keelatud"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Lubatud"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Pole lubatud"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 2eee948..bd4724e 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Konektatuta dago. Ezin da kargatu une honetan."</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Beteta"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Administratzaileak kontrolatzen du"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Administratzaileak gaitu du"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Administratzaileak desgaitu du"</string>
<string name="disabled" msgid="9206776641295849915">"Desgaituta"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Baimena dauka"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Ez dauka baimenik"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 6efd4fe..45b8ac7 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"به برق وصل شده است، درحالحاضر شارژ نمیشود"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"پر"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"توسط سرپرست سیستم کنترل میشود"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"فعالشده توسط سرپرست"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"غیرفعالشده توسط سرپرست"</string>
<string name="disabled" msgid="9206776641295849915">"غیر فعال شد"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"مجاز"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"مجاز نیست"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 4d64e81..23c63b1 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Kytketty virtalähteeseen, lataaminen ei onnistu"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Täynnä"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Järjestelmänvalvoja hallinnoi tätä asetusta."</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Järjestelmänvalvojan käyttöön ottama"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Järjestelmänvalvojan estämä"</string>
<string name="disabled" msgid="9206776641295849915">"Pois käytöstä"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Sallittu"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Ei sallittu"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 8e813ea..ad99000 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"L\'appareil est branché, mais il ne peut pas être chargé pour le moment"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Pleine"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Contrôlé par l\'administrateur"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Activé par l\'administrateur"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Désactivé par l\'administrateur"</string>
<string name="disabled" msgid="9206776641295849915">"Désactivée"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Autorisée"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Non autorisée"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index baf8ed0..c23db25 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Appareil branché, mais impossible de le charger pour le moment"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"pleine"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Contrôlé par l\'administrateur"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Activé par l\'administrateur"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Désactivé par l\'administrateur"</string>
<string name="disabled" msgid="9206776641295849915">"Désactivée"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Autorisé"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Non autorisé"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index dc22b25..46532e9 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Conectouse, pero non se pode cargar neste momento"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Completa"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Opción controlada polo administrador"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Activado polo administrador"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Desactivado polo administrador"</string>
<string name="disabled" msgid="9206776641295849915">"Desactivada"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Permitida"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Non permitida"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 7943d51..6a74490 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"પ્લગ ઇન કરેલ, હમણાં ચાર્જ કરી શકતા નથી"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"પૂર્ણ"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"વ્યવસ્થાપક દ્વારા નિયંત્રિત"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"વ્યવસ્થાપકે સક્ષમ કરેલ"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"વ્યવસ્થાપકે અક્ષમ કરેલ"</string>
<string name="disabled" msgid="9206776641295849915">"અક્ષમ કર્યો"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"મંજૂરી છે"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"મંજૂરી નથી"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 3ec7e58..3859092 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"प्लग इन है, अभी चार्ज नहीं हो सकती"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"पूरी"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"इसका नियंत्रण एडमिन के पास है"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"व्यवस्थापक ने सक्षम किया है"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"व्यवस्थापक ने अक्षम किया है"</string>
<string name="disabled" msgid="9206776641295849915">"बंद किया गया"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"अनुमति है"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"अनुमति नहीं है"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index ce8e6ec..5270531 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Uključen, trenutačno se ne može puniti"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Puna"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolira administrator"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Omogućio administrator"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Onemogućio administrator"</string>
<string name="disabled" msgid="9206776641295849915">"Onemogućeno"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Dopušteno"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Nije dopušteno"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 1c79199..ad897f8 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Csatlakoztatva, jelenleg nem tölt"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Feltöltve"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Rendszergazda által irányítva"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"A rendszergazda bekapcsolta"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"A rendszergazda kikapcsolta"</string>
<string name="disabled" msgid="9206776641295849915">"Letiltva"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Engedélyezett"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Nem engedélyezett"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 84ee039..82755f9 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Միացված է հոսանքի աղբյուրին, սակայն այս պահին չի կարող լիցքավորվել"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Լիցքավորված է"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Վերահսկվում է ադմինիստրատորի կողմից"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Միացված է ադմինիստրատորի կողմից"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Անջատվել է ադմինիստրատորի կողմից"</string>
<string name="disabled" msgid="9206776641295849915">"Կասեցված է"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Թույլատրված է"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Արգելված է"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 9356c85..961f892 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Tercolok, tidak dapat mengisi baterai sekarang"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Penuh"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Dikontrol oleh admin"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Diaktifkan oleh admin"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Dinonaktifkan oleh admin"</string>
<string name="disabled" msgid="9206776641295849915">"Dinonaktifkan"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Diizinkan"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Tidak diizinkan"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index ca5e1f5..759b7ba 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Í sambandi, ekki hægt að hlaða eins og er"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Fullhlaðin"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Stjórnað af kerfisstjóra"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Gert virkt af kerfisstjóra"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Gert óvirkt af kerfisstjóra"</string>
<string name="disabled" msgid="9206776641295849915">"Óvirkt"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Heimilað"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Ekki heimilað"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 88a5bb8..bd41e28 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Collegato alla corrente. Impossibile caricare al momento"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Carica"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Gestita dall\'amministratore"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Attivata dall\'amministratore"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Disattivata dall\'amministratore"</string>
<string name="disabled" msgid="9206776641295849915">"Disattivato"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Consentite"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Non consentite"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index cec35cf..5a11e72 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"המכשיר מחובר, אבל לא ניתן לטעון עכשיו"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"מלא"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"נמצא בשליטת מנהל מערכת"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"מופעל על ידי מנהל המכשיר"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"הושבת על ידי מנהל המכשיר"</string>
<string name="disabled" msgid="9206776641295849915">"מושבת"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"מורשה"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"לא מורשה"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 9cfdadc..f6b81ed 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"接続されていますが、現在、充電できません"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"フル"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"管理者により管理されています"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"管理者により有効にされています"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"管理者により無効にされています"</string>
<string name="disabled" msgid="9206776641295849915">"無効"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"許可"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"許可しない"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 1083025..d5f5408 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"მიერთებულია, დატენვა ამჟამად ვერ ხერხდება"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ბატარეა დატენილია"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"იმართება ადმინისტრატორის მიერ"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"ჩართულია ადმინისტრატორის მიერ"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"გათიშულია ადმინისტრატორის მიერ"</string>
<string name="disabled" msgid="9206776641295849915">"გამორთული"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"დაშვებულია"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"დაუშვებელია"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index a122d91..c3fbfcd 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Қосылған, зарядталмайды"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Толы"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Әкімші басқарады"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Әкімші қосқан"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Әкімші өшірген"</string>
<string name="disabled" msgid="9206776641295849915">"Өшірілген"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Рұқсат етілген"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Рұқсат етілмеген"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 7ffd766..8e73f81 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"ដោតសាកថ្មរួចហើយ ប៉ុន្តែសាកថ្មមិនចូលទេឥឡូវនេះ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ពេញ"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"គ្រប់គ្រងដោយអ្នកគ្រប់គ្រង"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"បើកដោយអ្នកគ្រប់គ្រង"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"បិទដោយអ្នកគ្រប់គ្រង"</string>
<string name="disabled" msgid="9206776641295849915">"បិទ"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"បានអនុញ្ញាត"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"មិនអនុញ្ញាតទេ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index e12cbd2..ce225ea 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"ಪ್ಲಗ್ ಇನ್ ಮಾಡಲಾಗಿದೆ, ಇದೀಗ ಚಾರ್ಜ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ಭರ್ತಿ"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ನಿರ್ವಾಹಕರ ಮೂಲಕ ನಿಯಂತ್ರಿಸಲಾಗಿದೆ"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"ನಿರ್ವಾಹಕರು ಸಕ್ರಿಯಗೊಳಿಸಿದ್ದಾರೆ"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"ನಿರ್ವಾಹಕರು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿದ್ದಾರೆ"</string>
<string name="disabled" msgid="9206776641295849915">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"ಅನುಮತಿಸಲಾಗಿದೆ"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index d29bd65..b47471b 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"전원이 연결되었지만 현재 충전할 수 없음"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"충전 완료"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"관리자가 제어"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"관리자가 사용 설정함"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"관리자가 사용 중지함"</string>
<string name="disabled" msgid="9206776641295849915">"사용 안함"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"허용됨"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"허용되지 않음"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 56b5da1..9853dac 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Сайылып турат, учурда кубаттоо мүмкүн эмес"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Толук"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Администратор тарабынан көзөмөлдөнөт"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Администратор иштетип койгон"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Администратор өчүрүп койгон"</string>
<string name="disabled" msgid="9206776641295849915">"Өчүрүлгөн"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Уруксат берилген"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Тыюу салынган"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index eb27f02..1816515 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"ສຽບສາຍແລ້ວ, ບໍ່ສາມາດສາກໄດ້ໃນຕອນນີ້"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ເຕັມ"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ຄວບຄຸມໂດຍຜູ້ເບິ່ງແຍງ"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"ຜູ້ເບິ່ງແຍງລະບົບເປີດໃຫ້ໃຊ້ແລ້ວ"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"ຖືກຜູ້ເບິ່ງແຍງລະບົບປິດໄວ້"</string>
<string name="disabled" msgid="9206776641295849915">"ປິດການນຳໃຊ້"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"ອະນຸຍາດແລ້ວ"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"ບໍ່ອະນຸຍາດແລ້ວ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 44b532b..e6a8e1c 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Įjungta į maitinimo lizdą, bet šiuo metu įkrauti neįmanoma"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Visiškai įkrautas"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Valdo administratorius"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Įgalino administratorius"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Išjungė administratorius"</string>
<string name="disabled" msgid="9206776641295849915">"Neleidžiama"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Leidžiama"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Neleidžiama"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index ba87d07..b55afc0 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Pievienots, taču pašlaik nevar veikt uzlādi"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Pilns"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolē administrators"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Iespējoja administrators"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Atspējoja administrators"</string>
<string name="disabled" msgid="9206776641295849915">"Atspējots"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Atļauts"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Nav atļauts"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 0c5c94a..e28c8ee 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Приклучен е, но батеријата не може да се полни во моментов"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Полна"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролирано од администраторот"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Овозможено од администраторот"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Оневозможено од администраторот"</string>
<string name="disabled" msgid="9206776641295849915">"Оневозможено"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Дозволено"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Не е дозволено"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 1a208e62..6860398 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"പ്ലഗ് ഇൻ ചെയ്തു, ഇപ്പോൾ ചാർജ് ചെയ്യാനാവില്ല"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"നിറഞ്ഞു"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"അഡ്മിൻ നിയന്ത്രിക്കുന്നത്"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"അഡ്മിൻ പ്രവർത്തനക്ഷമമാക്കി"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"അഡ്മിൻ പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="disabled" msgid="9206776641295849915">"പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"അനുവദനീയം"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"അനുവദിച്ചിട്ടില്ല"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 809e82e..ba6d601 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Залгаастай тул одоо цэнэглэх боломжгүй"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Дүүрэн"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Админ удирдсан"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Админ идэвхжүүлсэн"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Админ цуцалсан"</string>
<string name="disabled" msgid="9206776641295849915">"Идэвхгүйжүүлсэн"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Зөвшөөрсөн"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Зөвшөөрөөгүй"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index dfa6d2f..a5d230a 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"प्लग इन केलेले आहे, आता चार्ज करू शकत नाही"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"पूर्ण"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"प्रशासकाने नियंत्रित केलेले"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"प्रशासकाने सक्षम केलेले"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"प्रशासकाने अक्षम केलेले"</string>
<string name="disabled" msgid="9206776641295849915">"अक्षम"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"अनुमती आहे"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"अनुमती नाही"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index b4ed016..a7ac3ef 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Dipalamkan, tidak boleh mengecas sekarang"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Penuh"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Dikawal oleh pentadbir"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Didayakan oleh pentadbir"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Dilumpuhkan oleh pentadbir"</string>
<string name="disabled" msgid="9206776641295849915">"Dilumpuhkan"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Dibenarkan"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Tidak dibenarkan"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index c1ffd28..6cdab67 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"ပလပ်ထိုးထားသောကြောင့် ယခုအားသွင်း၍ မရသေးပါ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"အပြည့်"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"စီမံခန့်ခွဲသူမှ ထိန်းချုပ်ပါသည်"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"စီမံခန့်ခွဲသူက ဖွင့်ထားသည်"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"စီမံခန့်ခွဲသူက ပိတ်ထားသည်"</string>
<string name="disabled" msgid="9206776641295849915">"ပိတ်ထားပြီး"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"ခွင့်ပြုထားသည်"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"ခွင့်မပြုပါ"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 5a8e01e..cf18477 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Laderen er koblet til – kan ikke lade akkurat nå"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Fullt"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrollert av administratoren"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Slått på av administratoren"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Avslått av administratoren"</string>
<string name="disabled" msgid="9206776641295849915">"Slått av"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Tillatt"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Ikke tillatt"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 72a9abb..8aba0f8 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"प्लगइन गरिएको छ, अहिले नै चार्ज गर्न सकिँदैन"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"पूर्ण चार्ज भएको स्थिति"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"प्रशासकद्वारा नियन्त्रित"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"प्रशासकद्वारा सक्षम पारिएको छ"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"प्रशासकद्वारा असक्षम पारिएको छ"</string>
<string name="disabled" msgid="9206776641295849915">"असक्षम पारियो"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"अनुमति छ"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"अनुमति छैन"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index f341717..e3f1aea 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Aangesloten, kan nu niet opladen"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Volledig"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Ingesteld door beheerder"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Ingeschakeld door beheerder"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Uitgeschakeld door beheerder"</string>
<string name="disabled" msgid="9206776641295849915">"Uitgeschakeld"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Toegestaan"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Niet toegestaan"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index a7761e9..8ecac4d 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"ପ୍ଲଗ୍ରେ ଲାଗିଛି, ହେଲେ ଏବେ ଚାର୍ଜ କରିପାରିବ ନାହିଁ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ଚାର୍ଜ ଅଛି"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ଆଡ୍ମିନ୍ ଦ୍ୱାରା ନିୟନ୍ତ୍ରିତ"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"ଆଡମିନ୍ଙ୍କ ଦ୍ୱାରା ସକ୍ଷମ କରାଯାଇଛି"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"ଆଡ୍ମିନ୍ ଦ୍ଵାରା ଅକ୍ଷମ କରାଯାଇଛି"</string>
<string name="disabled" msgid="9206776641295849915">"ଅକ୍ଷମ ହୋଇଛି"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"ଅନୁମୋଦିତ"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"ଅନୁମତି ନାହିଁ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index c7ab379..6f17e13 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"ਪਲੱਗ ਲੱਗਾ ਹੋਇਆ ਹੈ, ਇਸ ਸਮੇਂ ਚਾਰਜ ਨਹੀਂ ਹੋ ਸਕਦੀ"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"ਪੂਰੀ"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਕੰਟਰੋਲ ਕੀਤੀ ਗਈ"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"ਪ੍ਰਸ਼ਾਸਕ ਦੁਆਰਾ ਯੋਗ ਬਣਾਇਆ ਗਿਆ"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"ਪ੍ਰਸ਼ਾਸਕ ਦੁਆਰਾ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ"</string>
<string name="disabled" msgid="9206776641295849915">"ਅਯੋਗ ਬਣਾਇਆ"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"ਇਜਾਜ਼ਤ ਹੈ"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"ਇਜਾਜ਼ਤ ਨਹੀਂ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index effa59a..3c208e3 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Podłączony. Nie można teraz ładować"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Naładowana"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolowane przez administratora"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Włączone przez administratora"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Wyłączone przez administratora"</string>
<string name="disabled" msgid="9206776641295849915">"Wyłączone"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Dozwolone"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Niedozwolone"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index afefeda..5c363a4 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Conectado. Não é possível carregar no momento"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Carregada"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada pelo admin"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Ativado pelo administrador"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Desativada pelo administrador"</string>
<string name="disabled" msgid="9206776641295849915">"Desativado"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Permitido"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Não permitido"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 4ee4521..66c59ac 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Ligada à corrente, não é possível carregar neste momento"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Completo"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlado pelo gestor"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Ativada pelo gestor"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Desativada pelo gestor"</string>
<string name="disabled" msgid="9206776641295849915">"Desativada"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Autorizada"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Não autorizada"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index afefeda..5c363a4 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Conectado. Não é possível carregar no momento"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Carregada"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlada pelo admin"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Ativado pelo administrador"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Desativada pelo administrador"</string>
<string name="disabled" msgid="9206776641295849915">"Desativado"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Permitido"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Não permitido"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index f42363e..703add6 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Conectat, nu se poate încărca chiar acum"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Complet"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlată de administrator"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Activat de administrator"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Dezactivat de administrator"</string>
<string name="disabled" msgid="9206776641295849915">"Dezactivată"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Permise"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Nepermise"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 451c710..4eb3ca4 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Подключено, не заряжается"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Батарея заряжена"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролируется администратором"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Включено администратором"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Отключено администратором"</string>
<string name="disabled" msgid="9206776641295849915">"Отключено"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Разрешено"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Запрещено"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index d9e69ce..1ab5b79 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"පේනුගත කර ඇත, මේ අවස්ථාවේදී ආරෝපණය කළ නොහැකිය"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"පූර්ණ"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"පරිපාලක විසින් පාලනය කරන ලදී"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"පරිපාලක විසින් සබල කර ඇත"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"ඔබගේ පරිපාලක විසින් අබල කර ඇත"</string>
<string name="disabled" msgid="9206776641295849915">"අබල කර ඇත"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"ඉඩ දුන්"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"ඉඩ නොදෙන"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index a0c1062..5c3920f 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Pripojené, ale nie je možné nabíjať"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Nabitá"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Ovládané správcom"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Povolené správcom"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Zakázané správcom"</string>
<string name="disabled" msgid="9206776641295849915">"Deaktivované"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Povolené"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Nie je povolené"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 3088d0f..f479405 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Priključeno, trenutno ni mogoče polniti"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Poln"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Nadzira skrbnik"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Omogočil skrbnik"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Onemogočil skrbnik"</string>
<string name="disabled" msgid="9206776641295849915">"Onemogočeno"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Dovoljene"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Ni dovoljeno"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 8e31013..2741985 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Në prizë, por nuk mund të ngarkohet për momentin"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"E mbushur"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kontrolluar nga administratori"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Aktivizuar nga administratori"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Çaktivizuar nga administratori"</string>
<string name="disabled" msgid="9206776641295849915">"Çaktivizuar"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Lejohet"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Nuk lejohet"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index fe97119..241d9cb 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Прикључено је, али пуњење тренутно није могуће"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Пуна"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Контролише администратор"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Омогућио је администратор"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Администратор је онемогућио"</string>
<string name="disabled" msgid="9206776641295849915">"Онемогућено"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Дозвољено"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Није дозвољено"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 11f446c..d338e96 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Inkopplad, kan inte laddas just nu"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Fullt"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Strys av administratören"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Aktiverad av administratör"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Inaktiverad av administratören"</string>
<string name="disabled" msgid="9206776641295849915">"Inaktiverad"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Tillåts"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Tillåts inte"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index ba3aaba..df122e2 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Haiwezi kuchaji kwa sasa"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Imejaa"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Imedhibitiwa na msimamizi"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Imewashwa na msimamizi"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Imezimwa na msimamizi"</string>
<string name="disabled" msgid="9206776641295849915">"Imezimwa"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Imeruhusiwa"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Hairuhusiwi"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 63d5e75..8f5c7d8 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"செருகப்பட்டது, ஆனால் இப்போது சார்ஜ் செய்ய முடியவில்லை"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"முழுவதும் சார்ஜ் ஆனது"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"நிர்வாகி கட்டுப்படுத்துகிறார்"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"நிர்வாகி இயக்கியுள்ளார்"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"நிர்வாகி முடக்கியுள்ளார்"</string>
<string name="disabled" msgid="9206776641295849915">"முடக்கப்பட்டது"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"அனுமதிக்கப்பட்டது"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"அனுமதிக்கப்படவில்லை"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 4af461d..5f7ab996 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"ప్లగ్ ఇన్ చేయబడింది, ప్రస్తుతం ఛార్జ్ చేయడం సాధ్యం కాదు"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"నిండింది"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"నిర్వాహకుని ద్వారా నియంత్రించబడింది"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"నిర్వాహకులు ప్రారంభించారు"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"నిర్వాహకులు నిలిపివేసారు"</string>
<string name="disabled" msgid="9206776641295849915">"నిలిపివేయబడింది"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"అనుమతించినవి"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"అనుమతించబడలేదు"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 9cc5c73..020baf0 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"เสียบอยู่ ไม่สามารถชาร์จได้ในขณะนี้"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"เต็ม"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"ผู้ดูแลระบบเป็นผู้ควบคุม"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"เปิดใช้โดยผู้ดูแลระบบ"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"ปิดใช้โดยผู้ดูแลระบบ"</string>
<string name="disabled" msgid="9206776641295849915">"ปิดอยู่"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"อนุญาต"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"ไม่อนุญาต"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 49abe42..2164ade 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Nakasaksak, hindi makapag-charge sa ngayon"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Puno"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Pinapamahalaan ng admin"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Na-enable ng admin"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Na-disable ng admin"</string>
<string name="disabled" msgid="9206776641295849915">"Naka-disable"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Pinapayagan"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Hindi pinapayagan"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 23a96d9..532927c 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Prize takıldı, şu anda şarj olamıyor"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Dolu"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Yönetici tarafından denetleniyor"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Yönetici tarafından etkinleştirildi"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Yönetici devre dışı bıraktı"</string>
<string name="disabled" msgid="9206776641295849915">"Devre dışı"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"İzin verildi"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"İzin verilmiyor"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index cea870a4..cf26d20 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Підключено. Не вдається зарядити"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Акумулятор заряджено"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Керується адміністратором"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Увімкнено адміністратором"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Вимкнено адміністратором"</string>
<string name="disabled" msgid="9206776641295849915">"Вимкнено"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Дозволено"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Заборонено"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 0fb60d9..c158179 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"پلگ ان ہے، ابھی چارج نہیں کر سکتے"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"مکمل"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"کنٹرول کردہ بذریعہ منتظم"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"منتظم کی طرف سے فعال کردہ"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"منتظم کی طرف سے غیر فعال کردہ"</string>
<string name="disabled" msgid="9206776641295849915">"غیر فعال"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"اجازت ہے"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"اجازت نہیں ہے"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 4690db3..ac8bffe 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Ulangan, lekin quvvat olmayapti"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"To‘la"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Administrator tomonidan boshqariladi"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Administrator tomonidan yoqilgan"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Administrator tomonidan o‘chirilgan"</string>
<string name="disabled" msgid="9206776641295849915">"O‘chiq"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Ruxsat berilgan"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Ruxsat berilmagan"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 937b37d..78306da 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Đã cắm nhưng không thể sạc ngay"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Đầy"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Do quản trị viên kiểm soát"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Kích hoạt bởi quản trị viên"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Bị quản trị viên vô hiệu hóa"</string>
<string name="disabled" msgid="9206776641295849915">"Đã tắt"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Được phép"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Không được phép"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 47753fd..4fb26100 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"已插入电源,但是现在无法充电"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"电量充足"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"由管理员控制"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"已被管理员启用"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"已被管理员停用"</string>
<string name="disabled" msgid="9206776641295849915">"已停用"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"允许"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"不允许"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 4cbf5a6..c5a8f92 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"已插入電源插座,但目前無法充電"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"電量已滿"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"已由管理員停用"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"已由管理員啟用"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"已由管理員停用"</string>
<string name="disabled" msgid="9206776641295849915">"已停用"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"允許"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"不允許"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index cecc6ac..0947ccec 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"已接上電源,但現在無法充電"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"電力充足"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"已由管理員停用"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"已由管理員啟用"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"已由管理員停用"</string>
<string name="disabled" msgid="9206776641295849915">"已停用"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"允許"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"不允許"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 94c3abf..cd90d74 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -395,8 +395,6 @@
<string name="battery_info_status_not_charging" msgid="8523453668342598579">"Kuxhunyiwe, ayikwazi ukushaja khona manje"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Kugcwele"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Kulawulwa umqondisi"</string>
- <string name="enabled_by_admin" msgid="5302986023578399263">"Kunikwe amandla umlawuli"</string>
- <string name="disabled_by_admin" msgid="8505398946020816620">"Kukhutshazwe umlawuli"</string>
<string name="disabled" msgid="9206776641295849915">"Akusebenzi"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Kuvumelekile"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Akuvumelekile"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 9050b4b..0dbc037 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -81,7 +81,7 @@
private static final long DEFAULT_MAX_CACHED_SCORE_AGE_MILLIS = 20 * DateUtils.MINUTE_IN_MILLIS;
/** Maximum age of scan results to hold onto while actively scanning. **/
- private static final long MAX_SCAN_RESULT_AGE_MILLIS = 25000;
+ private static final long MAX_SCAN_RESULT_AGE_MILLIS = 15000;
private static final String TAG = "WifiTracker";
private static final boolean DBG() {
@@ -134,8 +134,8 @@
/**
* Tracks whether fresh scan results have been received since scanning start.
*
- * <p>If this variable is false, we will not evict the scan result cache or invoke callbacks
- * so that we do not update the UI with stale data / clear out existing UI elements prematurely.
+ * <p>If this variable is false, we will not invoke callbacks so that we do not
+ * update the UI with stale data / clear out existing UI elements prematurely.
*/
private boolean mStaleScanResults = true;
@@ -327,7 +327,8 @@
* <p>Intended to only be invoked within {@link #onStart()}.
*/
@MainThread
- private void forceUpdate() {
+ @VisibleForTesting
+ void forceUpdate() {
mLastInfo = mWifiManager.getConnectionInfo();
mLastNetworkInfo = mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());
@@ -443,10 +444,8 @@
mScanResultCache.put(newResult.BSSID, newResult);
}
- // Don't evict old results if no new scan results
- if (!mStaleScanResults) {
- evictOldScans();
- }
+ // Evict old results in all conditions
+ evictOldScans();
ArrayMap<String, List<ScanResult>> scanResultsByApKey = new ArrayMap<>();
for (ScanResult result : mScanResultCache.values()) {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 517db78..1860b31 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -21,7 +21,6 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doAnswer;
@@ -104,6 +103,10 @@
private static final byte SCORE_2 = 15;
private static final int BADGE_2 = AccessPoint.Speed.FAST;
+ private static final String SSID_3 = "ssid3";
+ private static final String BSSID_3 = "CC:00:00:00:00:00";
+ private static final int RSSI_3 = -40;
+
// TODO(b/65594609): Convert mutable Data objects to instance variables / builder pattern
private static final int NETWORK_ID_1 = 123;
private static final int CONNECTED_RSSI = -50;
@@ -255,6 +258,19 @@
SystemClock.elapsedRealtime() * 1000 /* microsecond timestamp */);
}
+ private static ScanResult buildStaleScanResult() {
+ return new ScanResult(
+ WifiSsid.createFromAsciiEncoded(SSID_3),
+ BSSID_3,
+ 0, // hessid
+ 0, //anqpDomainId
+ null, // osuProviders
+ "", // capabilities
+ RSSI_3,
+ 0, // frequency
+ 0 /* microsecond timestamp */);
+ }
+
private WifiTracker createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(
Intent ... intents)
throws InterruptedException {
@@ -896,4 +912,18 @@
assertThat(aps.get(0).isReachable()).isTrue();
assertThat(aps.get(1).isReachable()).isTrue();
}
+
+ @Test
+ public void onStart_updateScanResults_evictOldScanResult() {
+ when(mockWifiManager.getScanResults()).thenReturn(
+ Arrays.asList(buildScanResult1(), buildScanResult2(), buildStaleScanResult()));
+ WifiTracker tracker = createMockedWifiTracker();
+
+ tracker.forceUpdate();
+
+ // Only has scanResult1 and scanResult2
+ assertThat(tracker.getAccessPoints()).hasSize(2);
+ assertThat(tracker.getAccessPoints().get(0).getBssid()).isEqualTo(BSSID_1);
+ assertThat(tracker.getAccessPoints().get(1).getBssid()).isEqualTo(BSSID_2);
+ }
}
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index ec35b3d..2530abc 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -44,6 +44,7 @@
import libcore.io.Streams;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ChooserActivity;
import com.android.internal.logging.MetricsLogger;
@@ -234,6 +235,7 @@
*/
private boolean mTakingScreenshot;
+ @GuardedBy("sNotificationBundle")
private static final Bundle sNotificationBundle = new Bundle();
private boolean mIsWatch;
@@ -1059,10 +1061,12 @@
}
private static Notification.Builder newBaseNotification(Context context) {
- if (sNotificationBundle.isEmpty()) {
- // Rename notifcations from "Shell" to "Android System"
- sNotificationBundle.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
- context.getString(com.android.internal.R.string.android_system_label));
+ synchronized (sNotificationBundle) {
+ if (sNotificationBundle.isEmpty()) {
+ // Rename notifcations from "Shell" to "Android System"
+ sNotificationBundle.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
+ context.getString(com.android.internal.R.string.android_system_label));
+ }
}
return new Notification.Builder(context, NOTIFICATION_CHANNEL_ID)
.addExtras(sNotificationBundle)
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
index 680f14b..0b1dab1 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
@@ -38,11 +38,12 @@
public interface NotificationMenuRowPlugin extends Plugin {
public static final String ACTION = "com.android.systemui.action.PLUGIN_NOTIFICATION_MENU_ROW";
- public static final int VERSION = 4;
+ public static final int VERSION = 5;
@ProvidesInterface(version = OnMenuEventListener.VERSION)
public interface OnMenuEventListener {
public static final int VERSION = 1;
+
public void onMenuClicked(View row, int x, int y, MenuItem menu);
public void onMenuReset(View row);
@@ -53,6 +54,7 @@
@ProvidesInterface(version = MenuItem.VERSION)
public interface MenuItem {
public static final int VERSION = 1;
+
public View getMenuView();
public View getGutsView();
@@ -84,34 +86,136 @@
public void setMenuClickListener(OnMenuEventListener listener);
- public void setSwipeActionHelper(NotificationSwipeActionHelper listener);
-
public void setAppName(String appName);
public void createMenu(ViewGroup parent, StatusBarNotification sbn);
- public View getMenuView();
-
- public boolean isMenuVisible();
-
public void resetMenu();
- public void onTranslationUpdate(float translation);
+ public View getMenuView();
- public void onHeightUpdate();
+ /**
+ * Get the target position that a notification row should be snapped open to in order to reveal
+ * the menu. This is generally determined by the number of icons in the notification menu and the
+ * size of each icon. This method accounts for whether the menu appears on the left or ride side
+ * of the parent notification row.
+ *
- public void onNotificationUpdated(StatusBarNotification sbn);
+ * @return an int representing the x-offset in pixels that the notification should snap open to.
+ * Positive values imply that the notification should be offset to the right to reveal the menu,
+ * and negative alues imply that the notification should be offset to the right.
+ */
+ public int getMenuSnapTarget();
- public boolean onTouchEvent(View view, MotionEvent ev, float velocity);
+ /**
+ * Determines whether or not the menu should be shown in response to user input.
+ * @return true if the menu should be shown, false otherwise.
+ */
+ public boolean shouldShowMenu();
+
+ /**
+ * Determines whether the menu is currently visible.
+ * @return true if the menu is visible, false otherwise.
+ */
+ public boolean isMenuVisible();
+
+ /**
+ * Determines whether a given movement is towards or away from the current location of the menu.
+ * @param movement
+ * @return true if the movement is towards the menu, false otherwise.
+ */
+ public boolean isTowardsMenu(float movement);
+
+ /**
+ * Determines whether the menu should snap closed instead of dismissing the
+ * parent notification, as a function of its current state.
+ *
+ * @return true if the menu should snap closed, false otherwise.
+ */
+ public boolean shouldSnapBack();
+
+ /**
+ * Determines whether the menu was previously snapped open to the same side that it is currently
+ * being shown on.
+ * @return true if the menu is snapped open to the same side on which it currently appears,
+ * false otherwise.
+ */
+ public boolean isSnappedAndOnSameSide();
+
+ /**
+ * Determines whether the notification the menu is attached to is able to be dismissed.
+ * @return true if the menu's parent notification is dismissable, false otherwise.
+ */
+ public boolean canBeDismissed();
+
+ /**
+ * Determines whether the menu should remain open given its current state, or snap closed.
+ * @return true if the menu should remain open, false otherwise.
+ */
+ public boolean isWithinSnapMenuThreshold();
+
+ /**
+ * Determines whether the menu has been swiped far enough to snap open.
+ * @return true if the menu has been swiped far enough to open, false otherwise.
+ */
+ public boolean isSwipedEnoughToShowMenu();
public default boolean onInterceptTouchEvent(View view, MotionEvent ev) {
return false;
}
- public default boolean useDefaultMenuItems() {
+ public default boolean shouldUseDefaultMenuItems() {
return false;
}
- public default void onConfigurationChanged() {
- }
+ /**
+ * Callback used to signal the menu that its parent's translation has changed.
+ * @param translation The new x-translation of the menu as a position (not an offset).
+ */
+ public void onParentTranslationUpdate(float translation);
+
+ /**
+ * Callback used to signal the menu that its parent's height has changed.
+ */
+ public void onParentHeightUpdate();
+
+ /**
+ * Callback used to signal the menu that its parent notification has been updated.
+ * @param sbn
+ */
+ public void onNotificationUpdated(StatusBarNotification sbn);
+
+ /**
+ * Callback used to signal the menu that a user is moving the parent notification.
+ * @param delta The change in the parent notification's position.
+ */
+ public void onTouchMove(float delta);
+
+ /**
+ * Callback used to signal the menu that a user has begun touching its parent notification.
+ */
+ public void onTouchStart();
+
+ /**
+ * Callback used to signal the menu that a user has finished touching its parent notification.
+ */
+ public void onTouchEnd();
+
+ /**
+ * Callback used to signal the menu that it has been snapped closed.
+ */
+ public void onSnapClosed();
+
+ /**
+ * Callback used to signal the menu that it has been snapped open.
+ */
+ public void onSnapOpen();
+
+ /**
+ * Callback used to signal the menu that its parent notification has been dismissed.
+ */
+ public void onDismiss();
+
+ public default void onConfigurationChanged() { }
+
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java
index f6cf035..8db0d02 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java
@@ -39,7 +39,7 @@
/**
* Call this to snap a notification to provided {@code targetLeft}.
*/
- public void snap(View animView, float velocity, float targetLeft);
+ public void snapOpen(View animView, int targetLeft, float velocity);
/**
* Call this to snooze a notification based on the provided {@link SnoozeOption}.
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml b/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
similarity index 80%
rename from packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml
rename to packages/SystemUI/res/drawable/biometric_dialog_bg.xml
index 221f170..335448d 100644
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_bg.xml
+++ b/packages/SystemUI/res/drawable/biometric_dialog_bg.xml
@@ -17,10 +17,10 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="@color/fingerprint_dialog_bg_color" />
+ <solid android:color="@color/biometric_dialog_bg_color" />
<corners android:radius="1dp"
- android:topLeftRadius="@dimen/fingerprint_dialog_corner_size"
- android:topRightRadius="@dimen/fingerprint_dialog_corner_size"
+ android:topLeftRadius="@dimen/biometric_dialog_corner_size"
+ android:topRightRadius="@dimen/biometric_dialog_corner_size"
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp"/>
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/face_dialog_icon.xml b/packages/SystemUI/res/drawable/face_dialog_icon.xml
new file mode 100644
index 0000000..6d28b5a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/face_dialog_icon.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path android:fillColor="#000" android:pathData="M9,11.75A1.25,1.25 0 0,0 7.75,13A1.25,1.25 0 0,0 9,14.25A1.25,1.25 0 0,0 10.25,13A1.25,1.25 0 0,0 9,11.75M15,11.75A1.25,1.25 0 0,0 13.75,13A1.25,1.25 0 0,0 15,14.25A1.25,1.25 0 0,0 16.25,13A1.25,1.25 0 0,0 15,11.75M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20C7.59,20 4,16.41 4,12C4,11.71 4,11.42 4.05,11.14C6.41,10.09 8.28,8.16 9.26,5.77C11.07,8.33 14.05,10 17.42,10C18.2,10 18.95,9.91 19.67,9.74C19.88,10.45 20,11.21 20,12C20,16.41 16.41,20 12,20Z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
index 83c1949..05fd467 100644
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
+++ b/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
@@ -36,7 +36,7 @@
android:name="_R_G_L_2_G_D_0_P_0"
android:pathData=" M-25.36 -24.41 C-25.93,-24.31 -26.49,-24.27 -26.81,-24.27 C-28.11,-24.27 -29.35,-24.62 -30.43,-25.4 C-32.11,-26.6 -33.2,-28.57 -33.2,-30.79 "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+ android:strokeColor="@color/biometric_dialog_biometric_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="1.45"
@@ -47,7 +47,7 @@
android:name="_R_G_L_2_G_D_1_P_0"
android:pathData=" M-36.14 -21.78 C-37.15,-22.98 -37.72,-23.7 -38.51,-25.29 C-39.33,-26.94 -39.82,-28.78 -39.82,-30.77 C-39.82,-34.43 -36.85,-37.4 -33.19,-37.4 C-29.52,-37.4 -26.55,-34.43 -26.55,-30.77 "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+ android:strokeColor="@color/biometric_dialog_biometric_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="1.45"
@@ -58,7 +58,7 @@
android:name="_R_G_L_2_G_D_2_P_0"
android:pathData=" M-42.19 -25.68 C-42.95,-27.82 -43.09,-29.54 -43.09,-30.8 C-43.09,-32.27 -42.84,-33.65 -42.27,-34.9 C-40.71,-38.35 -37.24,-40.75 -33.2,-40.75 C-27.71,-40.75 -23.26,-36.3 -23.26,-30.8 C-23.26,-28.97 -24.74,-27.49 -26.57,-27.49 C-28.4,-27.49 -29.89,-28.97 -29.89,-30.8 C-29.89,-32.64 -31.37,-34.12 -33.2,-34.12 C-35.04,-34.12 -36.52,-32.64 -36.52,-30.8 C-36.52,-28.23 -35.53,-25.92 -33.92,-24.22 C-32.69,-22.93 -31.48,-22.12 -29.44,-21.53 "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+ android:strokeColor="@color/biometric_dialog_biometric_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="1.45"
@@ -69,7 +69,7 @@
android:name="_R_G_L_2_G_D_3_P_0"
android:pathData=" M-44.06 -38.17 C-42.87,-39.94 -41.39,-41.41 -39.51,-42.44 C-37.62,-43.47 -35.46,-44.05 -33.16,-44.05 C-30.88,-44.05 -28.72,-43.47 -26.85,-42.45 C-24.97,-41.43 -23.48,-39.97 -22.29,-38.21 "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+ android:strokeColor="@color/biometric_dialog_biometric_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="1.45"
@@ -80,7 +80,7 @@
android:name="_R_G_L_2_G_D_4_P_0"
android:pathData=" M-25.72 -45.45 C-27.99,-46.76 -30.43,-47.52 -33.28,-47.52 C-36.13,-47.52 -38.51,-46.74 -40.62,-45.45 "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+ android:strokeColor="@color/biometric_dialog_biometric_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="1.45"
@@ -97,7 +97,7 @@
android:name="_R_G_L_1_G_D_0_P_0"
android:pathData=" M0 -9 C4.97,-9 9,-4.97 9,0 C9,4.97 4.97,9 0,9 C-4.97,9 -9,4.97 -9,0 C-9,-4.97 -4.97,-9 0,-9c "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_error_color"
+ android:strokeColor="@color/biometric_dialog_error_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="2"
@@ -118,7 +118,7 @@
<path
android:name="_R_G_L_0_G_D_0_P_0"
android:fillAlpha="1"
- android:fillColor="@color/fingerprint_dialog_error_color"
+ android:fillColor="@color/biometric_dialog_error_color"
android:fillType="nonZero"
android:pathData=" M1.1 3.94 C1.1,4.55 0.61,5.04 0,5.04 C-0.61,5.04 -1.1,4.55 -1.1,3.94 C-1.1,3.33 -0.61,2.84 0,2.84 C0.61,2.84 1.1,3.33 1.1,3.94c " />
</group>
@@ -131,7 +131,7 @@
<path
android:name="_R_G_L_0_G_D_0_P_1"
android:fillAlpha="1"
- android:fillColor="@color/fingerprint_dialog_error_color"
+ android:fillColor="@color/biometric_dialog_error_color"
android:fillType="nonZero"
android:pathData=" M1 -4.06 C1,-4.06 1,-0.06 1,-0.06 C1,0.49 0.55,0.94 0,0.94 C-0.55,0.94 -1,0.49 -1,-0.06 C-1,-0.06 -1,-4.06 -1,-4.06 C-1,-4.61 -0.55,-5.06 0,-5.06 C0.55,-5.06 1,-4.61 1,-4.06c " />
</group>
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
index f682f87..fd0ab22 100644
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
+++ b/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
@@ -36,7 +36,7 @@
android:name="_R_G_L_3_G_D_0_P_0"
android:pathData=" M-25.36 -24.41 C-25.93,-24.31 -26.49,-24.27 -26.81,-24.27 C-28.11,-24.27 -29.35,-24.62 -30.43,-25.4 C-32.11,-26.6 -33.2,-28.57 -33.2,-30.79 "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+ android:strokeColor="@color/biometric_dialog_biometric_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="1.45"
@@ -47,7 +47,7 @@
android:name="_R_G_L_3_G_D_1_P_0"
android:pathData=" M-36.14 -21.78 C-37.15,-22.98 -37.72,-23.7 -38.51,-25.29 C-39.33,-26.94 -39.82,-28.78 -39.82,-30.77 C-39.82,-34.43 -36.85,-37.4 -33.19,-37.4 C-29.52,-37.4 -26.55,-34.43 -26.55,-30.77 "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+ android:strokeColor="@color/biometric_dialog_biometric_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="1.45"
@@ -58,7 +58,7 @@
android:name="_R_G_L_3_G_D_2_P_0"
android:pathData=" M-42.19 -25.68 C-42.95,-27.82 -43.09,-29.54 -43.09,-30.8 C-43.09,-32.27 -42.84,-33.65 -42.27,-34.9 C-40.71,-38.35 -37.24,-40.75 -33.2,-40.75 C-27.71,-40.75 -23.26,-36.3 -23.26,-30.8 C-23.26,-28.97 -24.74,-27.49 -26.57,-27.49 C-28.4,-27.49 -29.89,-28.97 -29.89,-30.8 C-29.89,-32.64 -31.37,-34.12 -33.2,-34.12 C-35.04,-34.12 -36.52,-32.64 -36.52,-30.8 C-36.52,-28.23 -35.53,-25.92 -33.92,-24.22 C-32.69,-22.93 -31.48,-22.12 -29.44,-21.53 "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+ android:strokeColor="@color/biometric_dialog_biometric_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="1.45"
@@ -69,7 +69,7 @@
android:name="_R_G_L_3_G_D_3_P_0"
android:pathData=" M-44.06 -38.17 C-42.87,-39.94 -41.39,-41.41 -39.51,-42.44 C-37.62,-43.47 -35.46,-44.05 -33.16,-44.05 C-30.88,-44.05 -28.72,-43.47 -26.85,-42.45 C-24.97,-41.43 -23.48,-39.97 -22.29,-38.21 "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+ android:strokeColor="@color/biometric_dialog_biometric_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="1.45"
@@ -80,7 +80,7 @@
android:name="_R_G_L_3_G_D_4_P_0"
android:pathData=" M-25.72 -45.45 C-27.99,-46.76 -30.43,-47.52 -33.28,-47.52 C-36.13,-47.52 -38.51,-46.74 -40.62,-45.45 "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_fingerprint_color"
+ android:strokeColor="@color/biometric_dialog_biometric_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="1.45"
@@ -101,7 +101,7 @@
android:name="_R_G_L_2_G_D_0_P_0"
android:pathData=" M-25.36 -24.41 C-25.93,-24.31 -26.49,-24.27 -26.81,-24.27 C-28.11,-24.27 -29.35,-24.62 -30.43,-25.4 C-32.11,-26.6 -33.2,-28.57 -33.2,-30.79 "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_error_color"
+ android:strokeColor="@color/biometric_dialog_error_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="1.45"
@@ -112,7 +112,7 @@
android:name="_R_G_L_2_G_D_1_P_0"
android:pathData=" M-36.14 -21.78 C-37.15,-22.98 -37.72,-23.7 -38.51,-25.29 C-39.33,-26.94 -39.82,-28.78 -39.82,-30.77 C-39.82,-34.43 -36.85,-37.4 -33.19,-37.4 C-29.52,-37.4 -26.55,-34.43 -26.55,-30.77 "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_error_color"
+ android:strokeColor="@color/biometric_dialog_error_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="1.45"
@@ -123,7 +123,7 @@
android:name="_R_G_L_2_G_D_2_P_0"
android:pathData=" M-42.19 -25.68 C-42.95,-27.82 -43.09,-29.54 -43.09,-30.8 C-43.09,-32.27 -42.84,-33.65 -42.27,-34.9 C-40.71,-38.35 -37.24,-40.75 -33.2,-40.75 C-27.71,-40.75 -23.26,-36.3 -23.26,-30.8 C-23.26,-28.97 -24.74,-27.49 -26.57,-27.49 C-28.4,-27.49 -29.89,-28.97 -29.89,-30.8 C-29.89,-32.64 -31.37,-34.12 -33.2,-34.12 C-35.04,-34.12 -36.52,-32.64 -36.52,-30.8 C-36.52,-28.23 -35.53,-25.92 -33.92,-24.22 C-32.69,-22.93 -31.48,-22.12 -29.44,-21.53 "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_error_color"
+ android:strokeColor="@color/biometric_dialog_error_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="1.45"
@@ -134,7 +134,7 @@
android:name="_R_G_L_2_G_D_3_P_0"
android:pathData=" M-44.06 -38.17 C-42.87,-39.94 -41.39,-41.41 -39.51,-42.44 C-37.62,-43.47 -35.46,-44.05 -33.16,-44.05 C-30.88,-44.05 -28.72,-43.47 -26.85,-42.45 C-24.97,-41.43 -23.48,-39.97 -22.29,-38.21 "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_error_color"
+ android:strokeColor="@color/biometric_dialog_error_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="1.45"
@@ -145,7 +145,7 @@
android:name="_R_G_L_2_G_D_4_P_0"
android:pathData=" M-25.72 -45.45 C-27.99,-46.76 -30.43,-47.52 -33.28,-47.52 C-36.13,-47.52 -38.51,-46.74 -40.62,-45.45 "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_error_color"
+ android:strokeColor="@color/biometric_dialog_error_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="1.45"
@@ -162,7 +162,7 @@
android:name="_R_G_L_1_G_D_0_P_0"
android:pathData=" M0 -9 C4.97,-9 9,-4.97 9,0 C9,4.97 4.97,9 0,9 C-4.97,9 -9,4.97 -9,0 C-9,-4.97 -4.97,-9 0,-9c "
android:strokeAlpha="1"
- android:strokeColor="@color/fingerprint_dialog_error_color"
+ android:strokeColor="@color/biometric_dialog_error_color"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="2"
@@ -183,7 +183,7 @@
<path
android:name="_R_G_L_0_G_D_0_P_0"
android:fillAlpha="1"
- android:fillColor="@color/fingerprint_dialog_error_color"
+ android:fillColor="@color/biometric_dialog_error_color"
android:fillType="nonZero"
android:pathData=" M1.1 3.94 C1.1,4.55 0.61,5.04 0,5.04 C-0.61,5.04 -1.1,4.55 -1.1,3.94 C-1.1,3.33 -0.61,2.84 0,2.84 C0.61,2.84 1.1,3.33 1.1,3.94c " />
</group>
@@ -196,7 +196,7 @@
<path
android:name="_R_G_L_0_G_D_0_P_1"
android:fillAlpha="1"
- android:fillColor="@color/fingerprint_dialog_error_color"
+ android:fillColor="@color/biometric_dialog_error_color"
android:fillType="nonZero"
android:pathData=" M1 -4.06 C1,-4.06 1,-0.06 1,-0.06 C1,0.49 0.55,0.94 0,0.94 C-0.55,0.94 -1,0.49 -1,-0.06 C-1,-0.06 -1,-4.06 -1,-4.06 C-1,-4.61 -0.55,-5.06 0,-5.06 C0.55,-5.06 1,-4.61 1,-4.06c " />
</group>
diff --git a/packages/SystemUI/res/layout/fingerprint_dialog.xml b/packages/SystemUI/res/layout/biometric_dialog.xml
similarity index 78%
rename from packages/SystemUI/res/layout/fingerprint_dialog.xml
rename to packages/SystemUI/res/layout/biometric_dialog.xml
index 1bdaf6e..0417e2e 100644
--- a/packages/SystemUI/res/layout/fingerprint_dialog.xml
+++ b/packages/SystemUI/res/layout/biometric_dialog.xml
@@ -19,7 +19,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
- android:background="@color/fingerprint_dialog_dim_color"
+ android:background="@color/biometric_dialog_dim_color"
android:orientation="vertical">
<!-- This is not a Space since Spaces cannot be clicked -->
@@ -47,7 +47,7 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:elevation="2dp"
- android:background="@drawable/fingerprint_dialog_bg">
+ android:background="@drawable/biometric_dialog_bg">
<TextView
android:id="@+id/title"
@@ -57,13 +57,13 @@
android:layout_marginEnd="24dp"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
- android:gravity="@integer/fingerprint_dialog_text_gravity"
+ android:gravity="@integer/biometric_dialog_text_gravity"
android:textSize="20sp"
android:maxLines="1"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
- android:textColor="@color/fingerprint_dialog_text_dark_color"/>
+ android:textColor="@color/biometric_dialog_text_dark_color"/>
<TextView
android:id="@+id/subtitle"
@@ -72,13 +72,13 @@
android:layout_marginTop="8dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
- android:gravity="@integer/fingerprint_dialog_text_gravity"
+ android:gravity="@integer/biometric_dialog_text_gravity"
android:textSize="16sp"
android:maxLines="1"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
- android:textColor="@color/fingerprint_dialog_text_dark_color"/>
+ android:textColor="@color/biometric_dialog_text_dark_color"/>
<TextView
android:id="@+id/description"
@@ -86,20 +86,19 @@
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:layout_marginStart="24dp"
- android:gravity="@integer/fingerprint_dialog_text_gravity"
+ android:gravity="@integer/biometric_dialog_text_gravity"
android:paddingTop="8dp"
android:textSize="16sp"
android:maxLines="4"
- android:textColor="@color/fingerprint_dialog_text_dark_color"/>
+ android:textColor="@color/biometric_dialog_text_dark_color"/>
<ImageView
- android:id="@+id/fingerprint_icon"
- android:layout_width="@dimen/fingerprint_dialog_fp_icon_size"
- android:layout_height="@dimen/fingerprint_dialog_fp_icon_size"
+ android:id="@+id/biometric_icon"
+ android:layout_width="@dimen/biometric_dialog_biometric_icon_size"
+ android:layout_height="@dimen/biometric_dialog_biometric_icon_size"
android:layout_gravity="center_horizontal"
android:layout_marginTop="48dp"
- android:scaleType="fitXY"
- android:contentDescription="@string/accessibility_fingerprint_dialog_fingerprint_icon" />
+ android:scaleType="fitXY" />
<TextView
android:id="@+id/error"
@@ -112,9 +111,8 @@
android:textSize="12sp"
android:gravity="center_horizontal"
android:accessibilityLiveRegion="polite"
- android:text="@string/fingerprint_dialog_touch_sensor"
- android:contentDescription="@string/accessibility_fingerprint_dialog_help_area"
- android:textColor="@color/fingerprint_dialog_text_light_color"/>
+ android:contentDescription="@string/accessibility_biometric_dialog_help_area"
+ android:textColor="@color/biometric_dialog_text_light_color"/>
<LinearLayout
android:layout_width="match_parent"
@@ -125,7 +123,7 @@
android:orientation="horizontal"
android:measureWithLargestChild="true">
<Space android:id="@+id/leftSpacer"
- android:layout_width="24dp"
+ android:layout_width="12dp"
android:layout_height="match_parent"
android:visibility="visible" />
<!-- Negative Button -->
@@ -133,20 +131,26 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_marginStart="-12dp"
- android:gravity="start|center_vertical"
+ android:gravity="center"
android:maxLines="2" />
+ <Space android:id="@+id/middleSpacer"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:visibility="visible" />
<!-- Positive Button -->
<Button android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_marginEnd="12dp"
- android:maxLines="2" />
+ style="@*android:style/Widget.DeviceDefault.Button.Colored"
+ android:gravity="center"
+ android:maxLines="2"
+ android:text="@string/biometric_dialog_confirm"
+ android:visibility="gone"/>
<Space android:id="@+id/rightSpacer"
- android:layout_width="24dip"
+ android:layout_width="12dip"
android:layout_height="match_parent"
- android:visibility="gone" />
+ android:visibility="visible" />
</LinearLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_customize_panel_content.xml b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
index bb67c54..87b4551 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel_content.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
@@ -17,6 +17,7 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android">->
<View
+ android:id="@+id/customizer_transparent_view"
android:layout_width="match_parent"
android:layout_height="@*android:dimen/quick_qs_offset_height"
android:background="@android:color/transparent" />
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 4920fb2..d1320a3 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -160,13 +160,13 @@
<color name="smart_reply_button_background">#ffffffff</color>
<color name="smart_reply_button_stroke">#ffdadce0</color>
- <!-- Fingerprint dialog colors -->
- <color name="fingerprint_dialog_bg_color">#ffffffff</color> <!-- 100% white -->
- <color name="fingerprint_dialog_text_dark_color">#dd000000</color> <!-- 87% black -->
- <color name="fingerprint_dialog_text_light_color">#89000000</color> <!-- 54% black -->
- <color name="fingerprint_dialog_dim_color">#80000000</color> <!-- 50% black -->
- <color name="fingerprint_dialog_error_color">#fff44336</color> <!-- red -->
- <color name="fingerprint_dialog_fingerprint_color">#ff008577</color> <!-- teal -->
+ <!-- Biometric dialog colors -->
+ <color name="biometric_dialog_bg_color">#ffffffff</color> <!-- 100% white -->
+ <color name="biometric_dialog_text_dark_color">#dd000000</color> <!-- 87% black -->
+ <color name="biometric_dialog_text_light_color">#89000000</color> <!-- 54% black -->
+ <color name="biometric_dialog_dim_color">#80000000</color> <!-- 50% black -->
+ <color name="biometric_dialog_error_color">#fff44336</color> <!-- red -->
+ <color name="biometric_dialog_biometric_color">#ff008577</color> <!-- teal -->
<!-- Logout button -->
<color name="logout_button_bg_color">#ccffffff</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 24dcd3e..2fbf42f 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -508,4 +508,7 @@
<!-- Allow dragging the PIP to a location to close it -->
<bool name="config_pipEnableDismissDragToEdge">true</bool>
+
+ <!-- SystemUI Plugins that can be loaded on user builds. -->
+ <string-array name="config_pluginWhitelist" translatable="false" />
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c168d4e..7c355c9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -650,7 +650,6 @@
<dimen name="keyguard_affordance_icon_width">24dp</dimen>
<dimen name="keyguard_indication_margin_bottom">65dp</dimen>
- <dimen name="keyguard_indication_margin_bottom_ambient">16dp</dimen>
<!-- The text size for battery level -->
<dimen name="battery_level_text_size">12sp</dimen>
@@ -939,9 +938,8 @@
burn-in on AOD. -->
<dimen name="burn_in_prevention_offset_y">50dp</dimen>
- <!-- The maximum offset in either direction that the charging indication moves vertically
- to prevent burn-in on AOD. -->
- <dimen name="charging_indication_burn_in_prevention_offset_y">5dp</dimen>
+ <!-- The maximum offset in either direction that icons move to prevent burn-in on AOD. -->
+ <dimen name="default_burn_in_prevention_offset">5dp</dimen>
<dimen name="corner_size">8dp</dimen>
<dimen name="top_padding">0dp</dimen>
@@ -982,10 +980,10 @@
the regular notification, when we have remote input history texts present. -->
<dimen name="remote_input_history_extra_height">60dp</dimen>
- <!-- Fingerprint Dialog values -->
- <dimen name="fingerprint_dialog_fp_icon_size">64dp</dimen>
- <dimen name="fingerprint_dialog_animation_translation_offset">350dp</dimen>
- <dimen name="fingerprint_dialog_corner_size">4dp</dimen>
+ <!-- Biometric Dialog values -->
+ <dimen name="biometric_dialog_biometric_icon_size">64dp</dimen>
+ <dimen name="biometric_dialog_corner_size">4dp</dimen>
+ <dimen name="biometric_dialog_animation_translation_offset">350dp</dimen>
<!-- Wireless Charging Animation values -->
<dimen name="wireless_charging_dots_radius_start">0dp</dimen>
diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml
index 87c4bbb..fd7a105 100644
--- a/packages/SystemUI/res/values/integers.xml
+++ b/packages/SystemUI/res/values/integers.xml
@@ -15,7 +15,7 @@
~ limitations under the License
-->
<resources>
- <integer name="fingerprint_dialog_text_gravity">8388611</integer> <!-- gravity start -->
+ <integer name="biometric_dialog_text_gravity">8388611</integer> <!-- gravity start -->
<!-- Action footer width used for layout_width to indicate WRAP_CONTENT (along with a weight of
0) as we can allow the carrier text to stretch as far as needed in the QS footer. -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 36f97cd..2b51aaa 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -257,14 +257,20 @@
<!-- Button name for "Cancel". [CHAR LIMIT=NONE] -->
<string name="cancel">Cancel</string>
+ <!-- Content description for the error/help message are when the system-provided fingerprint dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_biometric_dialog_help_area">Help message area</string>
+ <!-- Message shown when a biometric is authenticated, asking the user to confirm authentication [CHAR LIMIT=30] -->
+ <string name="biometric_dialog_confirm">Confirm</string>
+
<!-- Message shown when the system-provided fingerprint dialog is shown, asking for authentication -->
<string name="fingerprint_dialog_touch_sensor">Touch the fingerprint sensor</string>
<!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_fingerprint_dialog_fingerprint_icon">Fingerprint icon</string>
- <!-- Content description of the application icon when the system-provided fingerprint dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_fingerprint_dialog_app_icon">Application icon</string>
- <!-- Content description for the error/help message are when the system-provided fingerprint dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_fingerprint_dialog_help_area">Help message area</string>
+
+ <!-- Message shown when the system-provided face dialog is shown, asking for authentication [CHAR LIMIT=30] -->
+ <string name="face_dialog_looking_for_face">Looking for you\u2026</string>
+ <!-- Content description of the face icon when the system-provided face dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_face_dialog_face_icon">Face icon</string>
<!-- Content description of the compatibility zoom button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_compatibility_zoom_button">Compatibility zoom button.</string>
@@ -2132,14 +2138,23 @@
<!-- App label of the instant apps notification [CHAR LIMIT=60] -->
<string name="instant_apps">Instant Apps</string>
- <!-- Message of the instant apps notification indicating they don't need install [CHAR LIMIT=NONE] -->
- <string name="instant_apps_message">Instant apps don\'t require installation.</string>
+ <!-- Title of notification indicating that an instant app is running. [CHAR LIMIT=60] -->
+ <string name="instant_apps_title"><xliff:g id="app" example="Gmail">%1$s</xliff:g> running</string>
+
+ <!-- Message of the instant apps notification indicating they don't need install. [CHAR LIMIT=NONE] -->
+ <string name="instant_apps_message">App opened without being installed.</string>
+
+ <!-- Message of the instant apps notification indicating they don't need install, plus a link to more information. [CHAR LIMIT=NONE] -->
+ <string name="instant_apps_message_with_help">App opened without being installed. Tap to learn more.</string>
+
+ <!-- URL of the webpage that explains instant apps. -->
+ <string name="instant_apps_help_url" translatable="false"></string>
<!-- Action label for launching app info on the specified app [CHAR LIMIT=20] -->
<string name="app_info">App info</string>
<!-- Action label for switching to a browser for an instant app [CHAR LIMIT=20] -->
- <string name="go_to_web">Go to browser</string>
+ <string name="go_to_web">Go to web</string>
<!-- Quick settings tile for toggling mobile data [CHAR LIMIT=20] -->
<string name="mobile_data">Mobile data</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index ff6a1c9..10c8ec0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -39,9 +39,9 @@
import android.app.UserSwitchObserver;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
-import android.hardware.biometrics.BiometricSourceType;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -49,11 +49,13 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.ContentObserver;
+import android.hardware.biometrics.BiometricSourceType;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
import android.media.AudioManager;
+import android.net.Uri;
import android.os.BatteryManager;
import android.os.CancellationSignal;
import android.os.Handler;
@@ -75,7 +77,6 @@
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.IccCardConstants;
@@ -250,6 +251,51 @@
private static final int HW_UNAVAILABLE_TIMEOUT = 3000; // ms
private static final int HW_UNAVAILABLE_RETRY_MAX = 3;
+ private class SettingObserver extends ContentObserver {
+ private final Uri FACE_UNLOCK_KEYGUARD_ENABLED =
+ Settings.Secure.getUriFor(Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED);
+
+ private final ContentResolver mContentResolver;
+
+ /**
+ * Creates a content observer.
+ *
+ * @param handler The handler to run {@link #onChange} on, or null if none.
+ */
+ public SettingObserver(Handler handler) {
+ super(handler);
+ mContentResolver = mContext.getContentResolver();
+ updateContentObserver();
+ }
+
+ public void updateContentObserver() {
+ mContentResolver.unregisterContentObserver(this);
+ mContentResolver.registerContentObserver(FACE_UNLOCK_KEYGUARD_ENABLED,
+ false /* notifyForDescendents */,
+ this,
+ UserHandle.USER_CURRENT);
+
+ // Update the value immediately
+ onChange(true /* selfChange */, FACE_UNLOCK_KEYGUARD_ENABLED);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (FACE_UNLOCK_KEYGUARD_ENABLED.equals(uri)) {
+ mFaceSettingEnabledForUser =
+ Settings.Secure.getIntForUser(
+ mContentResolver,
+ Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED,
+ 1 /* default */,
+ UserHandle.USER_CURRENT) != 0;
+ updateBiometricListeningState();
+ }
+ }
+ }
+
+ private final SettingObserver mSettingObserver;
+ private boolean mFaceSettingEnabledForUser;
+
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
@@ -1389,6 +1435,7 @@
mSubscriptionManager = SubscriptionManager.from(context);
mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
mStrongAuthTracker = new StrongAuthTracker(context);
+ mSettingObserver = new SettingObserver(mHandler);
// Since device can't be un-provisioned, we only need to register a content observer
// to update mDeviceProvisioned when we are...
@@ -1549,7 +1596,7 @@
(mBouncer && !mKeyguardGoingAway) || mGoingToSleep ||
shouldListenForFaceAssistant() || (mKeyguardOccluded && mIsDreaming))
&& !mSwitchingUser && !isFaceDisabled(getCurrentUser())
- && !mKeyguardGoingAway;
+ && !mKeyguardGoingAway && mFaceSettingEnabledForUser;
}
@@ -1719,6 +1766,7 @@
* Handle {@link #MSG_USER_SWITCH_COMPLETE}
*/
private void handleUserSwitchComplete(int userId) {
+ mSettingObserver.updateContentObserver();
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
index 8fe577a..8fc4689 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
+import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.IBiometricPromptReceiver;
import android.os.Bundle;
@@ -31,9 +32,12 @@
import com.android.systemui.SystemUI;
import com.android.systemui.statusbar.CommandQueue;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* Receives messages sent from AuthenticationClient and shows the appropriate biometric UI (e.g.
- * FingerprintDialogView).
+ * BiometricDialogView).
*/
public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callbacks {
private static final String TAG = "BiometricDialogImpl";
@@ -48,7 +52,8 @@
private static final int MSG_USER_CANCELED = 7;
private static final int MSG_BUTTON_POSITIVE = 8;
- private FingerprintDialogView mDialogView;
+ private Map<Integer, BiometricDialogView> mDialogs; // BiometricAuthenticator type, view
+ private BiometricDialogView mCurrentDialog;
private WindowManager mWindowManager;
private IBiometricPromptReceiver mReceiver;
private boolean mDialogShowing;
@@ -111,16 +116,25 @@
@Override
public void start() {
- if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
- return;
+ final PackageManager pm = mContext.getPackageManager();
+ mDialogs = new HashMap<>();
+ if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ mDialogs.put(BiometricAuthenticator.TYPE_FACE, new FaceDialogView(mContext, mCallback));
}
- getComponent(CommandQueue.class).addCallbacks(this);
- mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- mDialogView = new FingerprintDialogView(mContext, mCallback);
+ if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+ mDialogs.put(BiometricAuthenticator.TYPE_FINGERPRINT,
+ new FingerprintDialogView(mContext, mCallback));
+ }
+
+ if (!mDialogs.isEmpty()) {
+ getComponent(CommandQueue.class).addCallbacks(this);
+ mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ }
}
@Override
- public void showBiometricDialog(Bundle bundle, IBiometricPromptReceiver receiver, int type) {
+ public void showBiometricDialog(Bundle bundle, IBiometricPromptReceiver receiver, int type,
+ boolean requireConfirmation) {
if (DEBUG) Log.d(TAG, "showBiometricDialog, type: " + type);
// Remove these messages as they are part of the previous client
mHandler.removeMessages(MSG_BIOMETRIC_ERROR);
@@ -129,6 +143,8 @@
SomeArgs args = SomeArgs.obtain();
args.arg1 = bundle;
args.arg2 = receiver;
+ args.argi1 = type;
+ args.arg3 = requireConfirmation;
mHandler.obtainMessage(MSG_SHOW_DIALOG, args).sendToTarget();
}
@@ -157,33 +173,41 @@
}
private void handleShowDialog(SomeArgs args) {
+ final int type = args.argi1;
+ mCurrentDialog = mDialogs.get(type);
+
if (DEBUG) Log.d(TAG, "handleShowDialog, isAnimatingAway: "
- + mDialogView.isAnimatingAway());
- if (mDialogView.isAnimatingAway()) {
- mDialogView.forceRemove();
+ + mCurrentDialog.isAnimatingAway() + " type: " + type);
+
+ if (mCurrentDialog.isAnimatingAway()) {
+ mCurrentDialog.forceRemove();
} else if (mDialogShowing) {
Log.w(TAG, "Dialog already showing");
return;
}
mReceiver = (IBiometricPromptReceiver) args.arg2;
- mDialogView.setBundle((Bundle)args.arg1);
- mWindowManager.addView(mDialogView, mDialogView.getLayoutParams());
+ mCurrentDialog.setBundle((Bundle)args.arg1);
+ mCurrentDialog.setRequireConfirmation((boolean)args.arg3);
+ mWindowManager.addView(mCurrentDialog, mCurrentDialog.getLayoutParams());
mDialogShowing = true;
}
private void handleBiometricAuthenticated() {
if (DEBUG) Log.d(TAG, "handleBiometricAuthenticated");
- // TODO: announce correct string depending on modality
- mDialogView.announceForAccessibility(
- mContext.getResources().getText(
- com.android.internal.R.string.fingerprint_authenticated));
- handleHideDialog(false /* userCanceled */);
+ mCurrentDialog.announceForAccessibility(
+ mContext.getResources()
+ .getText(mCurrentDialog.getAuthenticatedAccessibilityResourceId()));
+ if (mCurrentDialog.requiresConfirmation()) {
+ mCurrentDialog.showConfirmationButton();
+ } else {
+ handleHideDialog(false /* userCanceled */);
+ }
}
private void handleBiometricHelp(String message) {
if (DEBUG) Log.d(TAG, "handleBiometricHelp: " + message);
- mDialogView.showHelpMessage(message);
+ mCurrentDialog.showHelpMessage(message);
}
private void handleBiometricError(String error) {
@@ -192,7 +216,7 @@
if (DEBUG) Log.d(TAG, "Dialog already dismissed");
return;
}
- mDialogView.showErrorMessage(error);
+ mCurrentDialog.showErrorMessage(error);
}
private void handleHideDialog(boolean userCanceled) {
@@ -212,7 +236,7 @@
}
mReceiver = null;
mDialogShowing = false;
- mDialogView.startDismiss();
+ mCurrentDialog.startDismiss();
}
private void handleButtonNegative() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
new file mode 100644
index 0000000..c90861e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -0,0 +1,363 @@
+/*
+ * 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.systemui.biometrics;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.hardware.biometrics.BiometricPrompt;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.animation.Interpolator;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+
+/**
+ * Abstract base class. Shows a dialog for BiometricPrompt.
+ */
+public abstract class BiometricDialogView extends LinearLayout {
+
+ private static final String TAG = "BiometricDialogView";
+
+ private static final int ANIMATION_DURATION_SHOW = 250; // ms
+ private static final int ANIMATION_DURATION_AWAY = 350; // ms
+
+ private static final int MSG_CLEAR_MESSAGE = 1;
+
+ protected static final int STATE_NONE = 0;
+ protected static final int STATE_AUTHENTICATING = 1;
+ protected static final int STATE_ERROR = 2;
+ protected static final int STATE_AUTHENTICATED = 3;
+
+ private final IBinder mWindowToken = new Binder();
+ private final Interpolator mLinearOutSlowIn;
+ private final WindowManager mWindowManager;
+ private final float mAnimationTranslationOffset;
+ private final int mErrorColor;
+ private final int mTextColor;
+ private final float mDisplayWidth;
+ private final DialogViewCallback mCallback;
+
+ private ViewGroup mLayout;
+ private final TextView mErrorText;
+ private Bundle mBundle;
+ private final LinearLayout mDialog;
+ private int mLastState;
+ private boolean mAnimatingAway;
+ private boolean mWasForceRemoved;
+ protected boolean mRequireConfirmation;
+
+ protected abstract void updateIcon(int lastState, int newState);
+ protected abstract int getHintStringResourceId();
+ protected abstract int getAuthenticatedAccessibilityResourceId();
+ protected abstract int getIconDescriptionResourceId();
+
+ private final Runnable mShowAnimationRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mLayout.animate()
+ .alpha(1f)
+ .setDuration(ANIMATION_DURATION_SHOW)
+ .setInterpolator(mLinearOutSlowIn)
+ .withLayer()
+ .start();
+ mDialog.animate()
+ .translationY(0)
+ .setDuration(ANIMATION_DURATION_SHOW)
+ .setInterpolator(mLinearOutSlowIn)
+ .withLayer()
+ .start();
+ }
+ };
+
+ private Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ case MSG_CLEAR_MESSAGE:
+ handleClearMessage();
+ break;
+ default:
+ Log.e(TAG, "Unhandled message: " + msg.what);
+ break;
+ }
+ }
+ };
+
+ public BiometricDialogView(Context context, DialogViewCallback callback) {
+ super(context);
+ mCallback = callback;
+ mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
+ mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ mAnimationTranslationOffset = getResources()
+ .getDimension(R.dimen.biometric_dialog_animation_translation_offset);
+ mErrorColor = Color.parseColor(
+ getResources().getString(R.color.biometric_dialog_error_color));
+ mTextColor = Color.parseColor(
+ getResources().getString(R.color.biometric_dialog_text_light_color));
+
+ DisplayMetrics metrics = new DisplayMetrics();
+ mWindowManager.getDefaultDisplay().getMetrics(metrics);
+ mDisplayWidth = metrics.widthPixels;
+
+ // Create the dialog
+ LayoutInflater factory = LayoutInflater.from(getContext());
+ mLayout = (ViewGroup) factory.inflate(R.layout.biometric_dialog, this, false);
+ addView(mLayout);
+
+ mDialog = mLayout.findViewById(R.id.dialog);
+
+ mErrorText = mLayout.findViewById(R.id.error);
+
+ mLayout.setOnKeyListener(new View.OnKeyListener() {
+ boolean downPressed = false;
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ if (keyCode != KeyEvent.KEYCODE_BACK) {
+ return false;
+ }
+ if (event.getAction() == KeyEvent.ACTION_DOWN && downPressed == false) {
+ downPressed = true;
+ } else if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ downPressed = false;
+ } else if (event.getAction() == KeyEvent.ACTION_UP && downPressed == true) {
+ downPressed = false;
+ mCallback.onUserCanceled();
+ }
+ return true;
+ }
+ });
+
+ final View space = mLayout.findViewById(R.id.space);
+ final View leftSpace = mLayout.findViewById(R.id.left_space);
+ final View rightSpace = mLayout.findViewById(R.id.right_space);
+ final Button negative = mLayout.findViewById(R.id.button2);
+ final Button positive = mLayout.findViewById(R.id.button1);
+ final ImageView icon = mLayout.findViewById(R.id.biometric_icon);
+
+ icon.setContentDescription(getResources().getString(getIconDescriptionResourceId()));
+ mErrorText.setText(getResources().getString(getHintStringResourceId()));
+
+ setDismissesDialog(space);
+ setDismissesDialog(leftSpace);
+ setDismissesDialog(rightSpace);
+
+ negative.setOnClickListener((View v) -> {
+ mCallback.onNegativePressed();
+ });
+
+ positive.setOnClickListener((View v) -> {
+ mCallback.onPositivePressed();
+ });
+
+ mLayout.setFocusableInTouchMode(true);
+ mLayout.requestFocus();
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ final TextView title = mLayout.findViewById(R.id.title);
+ final TextView subtitle = mLayout.findViewById(R.id.subtitle);
+ final TextView description = mLayout.findViewById(R.id.description);
+ final Button negative = mLayout.findViewById(R.id.button2);
+ final Button positive = mLayout.findViewById(R.id.button1);
+
+ mDialog.getLayoutParams().width = (int) mDisplayWidth;
+
+ mLastState = STATE_NONE;
+ updateState(STATE_AUTHENTICATING);
+
+ title.setText(mBundle.getCharSequence(BiometricPrompt.KEY_TITLE));
+ title.setSelected(true);
+
+ positive.setVisibility(View.INVISIBLE);
+
+ final CharSequence subtitleText = mBundle.getCharSequence(BiometricPrompt.KEY_SUBTITLE);
+ if (TextUtils.isEmpty(subtitleText)) {
+ subtitle.setVisibility(View.GONE);
+ } else {
+ subtitle.setVisibility(View.VISIBLE);
+ subtitle.setText(subtitleText);
+ }
+
+ final CharSequence descriptionText = mBundle.getCharSequence(BiometricPrompt.KEY_DESCRIPTION);
+ if (TextUtils.isEmpty(descriptionText)) {
+ description.setVisibility(View.GONE);
+ } else {
+ description.setVisibility(View.VISIBLE);
+ description.setText(descriptionText);
+ }
+
+ negative.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
+
+ if (!mWasForceRemoved) {
+ // Dim the background and slide the dialog up
+ mDialog.setTranslationY(mAnimationTranslationOffset);
+ mLayout.setAlpha(0f);
+ postOnAnimation(mShowAnimationRunnable);
+ } else {
+ // Show the dialog immediately
+ mLayout.animate().cancel();
+ mDialog.animate().cancel();
+ mDialog.setAlpha(1.0f);
+ mDialog.setTranslationY(0);
+ mLayout.setAlpha(1.0f);
+ }
+ mWasForceRemoved = false;
+ }
+
+ private void setDismissesDialog(View v) {
+ v.setClickable(true);
+ v.setOnTouchListener((View view, MotionEvent event) -> {
+ mCallback.onUserCanceled();
+ return true;
+ });
+ }
+
+ public void startDismiss() {
+ mAnimatingAway = true;
+
+ final Runnable endActionRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mWindowManager.removeView(BiometricDialogView.this);
+ mAnimatingAway = false;
+ }
+ };
+
+ postOnAnimation(new Runnable() {
+ @Override
+ public void run() {
+ mLayout.animate()
+ .alpha(0f)
+ .setDuration(ANIMATION_DURATION_AWAY)
+ .setInterpolator(mLinearOutSlowIn)
+ .withLayer()
+ .start();
+ mDialog.animate()
+ .translationY(mAnimationTranslationOffset)
+ .setDuration(ANIMATION_DURATION_AWAY)
+ .setInterpolator(mLinearOutSlowIn)
+ .withLayer()
+ .withEndAction(endActionRunnable)
+ .start();
+ }
+ });
+ }
+
+ /**
+ * Force remove the window, cancelling any animation that's happening. This should only be
+ * called if we want to quickly show the dialog again (e.g. on rotation). Calling this method
+ * will cause the dialog to show without an animation the next time it's attached.
+ */
+ public void forceRemove() {
+ mLayout.animate().cancel();
+ mDialog.animate().cancel();
+ mWindowManager.removeView(BiometricDialogView.this);
+ mAnimatingAway = false;
+ mWasForceRemoved = true;
+ }
+
+ public boolean isAnimatingAway() {
+ return mAnimatingAway;
+ }
+
+ public void setBundle(Bundle bundle) {
+ mBundle = bundle;
+ }
+
+ public void setRequireConfirmation(boolean requireConfirmation) {
+ mRequireConfirmation = requireConfirmation;
+ }
+
+ public boolean requiresConfirmation() {
+ return mRequireConfirmation;
+ }
+
+ public void showConfirmationButton() {
+ final Button positive = mLayout.findViewById(R.id.button1);
+ positive.setVisibility(View.VISIBLE);
+ }
+
+ public ViewGroup getLayout() {
+ return mLayout;
+ }
+
+ // Clears the temporary message and shows the help message.
+ private void handleClearMessage() {
+ updateState(STATE_AUTHENTICATING);
+ mErrorText.setText(getHintStringResourceId());
+ mErrorText.setTextColor(mTextColor);
+ }
+
+ // Shows an error/help message
+ private void showTemporaryMessage(String message) {
+ mHandler.removeMessages(MSG_CLEAR_MESSAGE);
+ updateState(STATE_ERROR);
+ mErrorText.setText(message);
+ mErrorText.setTextColor(mErrorColor);
+ mErrorText.setContentDescription(message);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_MESSAGE),
+ BiometricPrompt.HIDE_DIALOG_DELAY);
+ }
+
+ public void showHelpMessage(String message) {
+ showTemporaryMessage(message);
+ }
+
+ public void showErrorMessage(String error) {
+ showTemporaryMessage(error);
+ mCallback.onErrorShown();
+ }
+
+ private void updateState(int newState) {
+ updateIcon(mLastState, newState);
+ mLastState = newState;
+ }
+
+ public WindowManager.LayoutParams getLayoutParams() {
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+ PixelFormat.TRANSLUCENT);
+ lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ lp.setTitle("BiometricDialogView");
+ lp.token = mWindowToken;
+ return lp;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
new file mode 100644
index 0000000..feef3a6d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceDialogView.java
@@ -0,0 +1,62 @@
+/*
+ * 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.systemui.biometrics;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+
+/**
+ * This class loads the view for the system-provided dialog. The view consists of:
+ * Application Icon, Title, Subtitle, Description, Fingerprint Icon, Error/Help message area,
+ * and positive/negative buttons.
+ */
+public class FaceDialogView extends BiometricDialogView {
+ public FaceDialogView(Context context,
+ DialogViewCallback callback) {
+ super(context, callback);
+ }
+
+ @Override
+ protected int getHintStringResourceId() {
+ return R.string.face_dialog_looking_for_face;
+ }
+
+ @Override
+ protected int getAuthenticatedAccessibilityResourceId() {
+ if (mRequireConfirmation) {
+ return com.android.internal.R.string.face_authenticated_confirmation_required;
+ } else {
+ return com.android.internal.R.string.face_authenticated_no_confirmation_required;
+ }
+ }
+
+ @Override
+ protected int getIconDescriptionResourceId() {
+ return R.string.accessibility_face_dialog_face_icon;
+ }
+
+ @Override
+ protected void updateIcon(int lastState, int newState) {
+ Drawable icon = mContext.getDrawable(R.drawable.face_dialog_icon);
+
+ final ImageView faceIcon = getLayout().findViewById(R.id.biometric_icon);
+ faceIcon.setImageDrawable(icon);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
index 68c2c42..38a69a9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FingerprintDialogView.java
@@ -17,32 +17,11 @@
package com.android.systemui.biometrics;
import android.content.Context;
-import android.graphics.Color;
-import android.graphics.PixelFormat;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
-import android.hardware.biometrics.BiometricPrompt;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.text.TextUtils;
-import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.animation.Interpolator;
-import android.widget.Button;
import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import com.android.systemui.Interpolators;
import com.android.systemui.R;
/**
@@ -50,288 +29,27 @@
* Application Icon, Title, Subtitle, Description, Fingerprint Icon, Error/Help message area,
* and positive/negative buttons.
*/
-public class FingerprintDialogView extends LinearLayout {
-
+public class FingerprintDialogView extends BiometricDialogView {
private static final String TAG = "FingerprintDialogView";
- private static final int ANIMATION_DURATION_SHOW = 250; // ms
- private static final int ANIMATION_DURATION_AWAY = 350; // ms
-
- private static final int MSG_CLEAR_MESSAGE = 1;
-
- private static final int STATE_NONE = 0;
- private static final int STATE_FINGERPRINT = 1;
- private static final int STATE_FINGERPRINT_ERROR = 2;
- private static final int STATE_FINGERPRINT_AUTHENTICATED = 3;
-
- private final IBinder mWindowToken = new Binder();
- private final Interpolator mLinearOutSlowIn;
- private final WindowManager mWindowManager;
- private final float mAnimationTranslationOffset;
- private final int mErrorColor;
- private final int mTextColor;
- private final int mFingerprintColor;
- private final float mDisplayWidth;
- private final DialogViewCallback mCallback;
-
- private ViewGroup mLayout;
- private final TextView mErrorText;
- private Bundle mBundle;
- private final LinearLayout mDialog;
- private int mLastState;
- private boolean mAnimatingAway;
- private boolean mWasForceRemoved;
-
- private final Runnable mShowAnimationRunnable = new Runnable() {
- @Override
- public void run() {
- mLayout.animate()
- .alpha(1f)
- .setDuration(ANIMATION_DURATION_SHOW)
- .setInterpolator(mLinearOutSlowIn)
- .withLayer()
- .start();
- mDialog.animate()
- .translationY(0)
- .setDuration(ANIMATION_DURATION_SHOW)
- .setInterpolator(mLinearOutSlowIn)
- .withLayer()
- .start();
- }
- };
-
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch(msg.what) {
- case MSG_CLEAR_MESSAGE:
- handleClearMessage();
- break;
- default:
- Log.e(TAG, "Unhandled message: " + msg.what);
- break;
- }
- }
- };
-
- public FingerprintDialogView(Context context, DialogViewCallback callback) {
- super(context);
- mCallback = callback;
- mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
- mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- mAnimationTranslationOffset = getResources()
- .getDimension(R.dimen.fingerprint_dialog_animation_translation_offset);
- mErrorColor = Color.parseColor(
- getResources().getString(R.color.fingerprint_dialog_error_color));
- mTextColor = Color.parseColor(
- getResources().getString(R.color.fingerprint_dialog_text_light_color));
- mFingerprintColor = Color.parseColor(
- getResources().getString(R.color.fingerprint_dialog_fingerprint_color));
-
- DisplayMetrics metrics = new DisplayMetrics();
- mWindowManager.getDefaultDisplay().getMetrics(metrics);
- mDisplayWidth = metrics.widthPixels;
-
- // Create the dialog
- LayoutInflater factory = LayoutInflater.from(getContext());
- mLayout = (ViewGroup) factory.inflate(R.layout.fingerprint_dialog, this, false);
- addView(mLayout);
-
- mDialog = mLayout.findViewById(R.id.dialog);
-
- mErrorText = mLayout.findViewById(R.id.error);
-
- mLayout.setOnKeyListener(new View.OnKeyListener() {
- boolean downPressed = false;
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- if (keyCode != KeyEvent.KEYCODE_BACK) {
- return false;
- }
- if (event.getAction() == KeyEvent.ACTION_DOWN && downPressed == false) {
- downPressed = true;
- } else if (event.getAction() == KeyEvent.ACTION_DOWN) {
- downPressed = false;
- } else if (event.getAction() == KeyEvent.ACTION_UP && downPressed == true) {
- downPressed = false;
- mCallback.onUserCanceled();
- }
- return true;
- }
- });
-
- final View space = mLayout.findViewById(R.id.space);
- final View leftSpace = mLayout.findViewById(R.id.left_space);
- final View rightSpace = mLayout.findViewById(R.id.right_space);
- final Button negative = mLayout.findViewById(R.id.button2);
- final Button positive = mLayout.findViewById(R.id.button1);
-
- setDismissesDialog(space);
- setDismissesDialog(leftSpace);
- setDismissesDialog(rightSpace);
-
- negative.setOnClickListener((View v) -> {
- mCallback.onNegativePressed();
- });
-
- positive.setOnClickListener((View v) -> {
- mCallback.onPositivePressed();
- });
-
- mLayout.setFocusableInTouchMode(true);
- mLayout.requestFocus();
+ @Override
+ protected int getHintStringResourceId() {
+ return R.string.fingerprint_dialog_touch_sensor;
}
@Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- final TextView title = mLayout.findViewById(R.id.title);
- final TextView subtitle = mLayout.findViewById(R.id.subtitle);
- final TextView description = mLayout.findViewById(R.id.description);
- final Button negative = mLayout.findViewById(R.id.button2);
- final Button positive = mLayout.findViewById(R.id.button1);
-
- mDialog.getLayoutParams().width = (int) mDisplayWidth;
-
- mLastState = STATE_NONE;
- updateFingerprintIcon(STATE_FINGERPRINT);
-
- title.setText(mBundle.getCharSequence(BiometricPrompt.KEY_TITLE));
- title.setSelected(true);
-
- final CharSequence subtitleText = mBundle.getCharSequence(BiometricPrompt.KEY_SUBTITLE);
- if (TextUtils.isEmpty(subtitleText)) {
- subtitle.setVisibility(View.GONE);
- } else {
- subtitle.setVisibility(View.VISIBLE);
- subtitle.setText(subtitleText);
- }
-
- final CharSequence descriptionText = mBundle.getCharSequence(BiometricPrompt.KEY_DESCRIPTION);
- if (TextUtils.isEmpty(descriptionText)) {
- description.setVisibility(View.GONE);
- } else {
- description.setVisibility(View.VISIBLE);
- description.setText(descriptionText);
- }
-
- negative.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
-
- final CharSequence positiveText =
- mBundle.getCharSequence(BiometricPrompt.KEY_POSITIVE_TEXT);
- positive.setText(positiveText); // needs to be set for marquee to work
- if (positiveText != null) {
- positive.setVisibility(View.VISIBLE);
- } else {
- positive.setVisibility(View.GONE);
- }
-
- if (!mWasForceRemoved) {
- // Dim the background and slide the dialog up
- mDialog.setTranslationY(mAnimationTranslationOffset);
- mLayout.setAlpha(0f);
- postOnAnimation(mShowAnimationRunnable);
- } else {
- // Show the dialog immediately
- mLayout.animate().cancel();
- mDialog.animate().cancel();
- mDialog.setAlpha(1.0f);
- mDialog.setTranslationY(0);
- mLayout.setAlpha(1.0f);
- }
- mWasForceRemoved = false;
+ protected int getAuthenticatedAccessibilityResourceId() {
+ return com.android.internal.R.string.fingerprint_authenticated;
}
- private void setDismissesDialog(View v) {
- v.setClickable(true);
- v.setOnTouchListener((View view, MotionEvent event) -> {
- mCallback.onUserCanceled();
- return true;
- });
+ @Override
+ protected int getIconDescriptionResourceId() {
+ return R.string.accessibility_fingerprint_dialog_fingerprint_icon;
}
- public void startDismiss() {
- mAnimatingAway = true;
-
- final Runnable endActionRunnable = new Runnable() {
- @Override
- public void run() {
- mWindowManager.removeView(FingerprintDialogView.this);
- mAnimatingAway = false;
- }
- };
-
- postOnAnimation(new Runnable() {
- @Override
- public void run() {
- mLayout.animate()
- .alpha(0f)
- .setDuration(ANIMATION_DURATION_AWAY)
- .setInterpolator(mLinearOutSlowIn)
- .withLayer()
- .start();
- mDialog.animate()
- .translationY(mAnimationTranslationOffset)
- .setDuration(ANIMATION_DURATION_AWAY)
- .setInterpolator(mLinearOutSlowIn)
- .withLayer()
- .withEndAction(endActionRunnable)
- .start();
- }
- });
- }
-
- /**
- * Force remove the window, cancelling any animation that's happening. This should only be
- * called if we want to quickly show the dialog again (e.g. on rotation). Calling this method
- * will cause the dialog to show without an animation the next time it's attached.
- */
- public void forceRemove() {
- mLayout.animate().cancel();
- mDialog.animate().cancel();
- mWindowManager.removeView(FingerprintDialogView.this);
- mAnimatingAway = false;
- mWasForceRemoved = true;
- }
-
- public boolean isAnimatingAway() {
- return mAnimatingAway;
- }
-
- public void setBundle(Bundle bundle) {
- mBundle = bundle;
- }
-
- // Clears the temporary message and shows the help message.
- private void handleClearMessage() {
- updateFingerprintIcon(STATE_FINGERPRINT);
- mErrorText.setText(R.string.fingerprint_dialog_touch_sensor);
- mErrorText.setTextColor(mTextColor);
- }
-
- // Shows an error/help message
- private void showTemporaryMessage(String message) {
- mHandler.removeMessages(MSG_CLEAR_MESSAGE);
- updateFingerprintIcon(STATE_FINGERPRINT_ERROR);
- mErrorText.setText(message);
- mErrorText.setTextColor(mErrorColor);
- mErrorText.setContentDescription(message);
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_MESSAGE),
- BiometricPrompt.HIDE_DIALOG_DELAY);
- }
-
- public void showHelpMessage(String message) {
- showTemporaryMessage(message);
- }
-
- public void showErrorMessage(String error) {
- showTemporaryMessage(error);
- mCallback.onErrorShown();
- }
-
- private void updateFingerprintIcon(int newState) {
- Drawable icon = getAnimationForTransition(mLastState, newState);
+ @Override
+ protected void updateIcon(int lastState, int newState) {
+ Drawable icon = getAnimationForTransition(lastState, newState);
if (icon == null) {
Log.e(TAG, "Animation not found");
@@ -342,25 +60,28 @@
? (AnimatedVectorDrawable) icon
: null;
- final ImageView fingerprint_icon = mLayout.findViewById(R.id.fingerprint_icon);
- fingerprint_icon.setImageDrawable(icon);
+ final ImageView fingerprintIcon = getLayout().findViewById(R.id.biometric_icon);
+ fingerprintIcon.setImageDrawable(icon);
- if (animation != null && shouldAnimateForTransition(mLastState, newState)) {
+ if (animation != null && shouldAnimateForTransition(lastState, newState)) {
animation.forceAnimationOnUI();
animation.start();
}
+ }
- mLastState = newState;
+ public FingerprintDialogView(Context context,
+ DialogViewCallback callback) {
+ super(context, callback);
}
private boolean shouldAnimateForTransition(int oldState, int newState) {
- if (oldState == STATE_NONE && newState == STATE_FINGERPRINT) {
+ if (oldState == STATE_NONE && newState == STATE_AUTHENTICATING) {
return false;
- } else if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_ERROR) {
+ } else if (oldState == STATE_AUTHENTICATING && newState == STATE_ERROR) {
return true;
- } else if (oldState == STATE_FINGERPRINT_ERROR && newState == STATE_FINGERPRINT) {
+ } else if (oldState == STATE_ERROR && newState == STATE_AUTHENTICATING) {
return true;
- } else if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_AUTHENTICATED) {
+ } else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) {
// TODO(b/77328470): add animation when fingerprint is authenticated
return false;
}
@@ -369,32 +90,18 @@
private Drawable getAnimationForTransition(int oldState, int newState) {
int iconRes;
- if (oldState == STATE_NONE && newState == STATE_FINGERPRINT) {
+ if (oldState == STATE_NONE && newState == STATE_AUTHENTICATING) {
iconRes = R.drawable.fingerprint_dialog_fp_to_error;
- } else if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_ERROR) {
+ } else if (oldState == STATE_AUTHENTICATING && newState == STATE_ERROR) {
iconRes = R.drawable.fingerprint_dialog_fp_to_error;
- } else if (oldState == STATE_FINGERPRINT_ERROR && newState == STATE_FINGERPRINT) {
+ } else if (oldState == STATE_ERROR && newState == STATE_AUTHENTICATING) {
iconRes = R.drawable.fingerprint_dialog_error_to_fp;
- } else if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_AUTHENTICATED) {
+ } else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) {
// TODO(b/77328470): add animation when fingerprint is authenticated
iconRes = R.drawable.fingerprint_dialog_error_to_fp;
- }
- else {
+ } else {
return null;
}
return mContext.getDrawable(iconRes);
}
-
- public WindowManager.LayoutParams getLayoutParams() {
- final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
- PixelFormat.TRANSLUCENT);
- lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
- lp.setTitle("FingerprintDialogView");
- lp.token = mWindowToken;
- return lp;
- }
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt b/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
new file mode 100644
index 0000000..d1e5059
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.systemui.doze.util
+
+import android.util.MathUtils
+
+private const val MILLIS_PER_MINUTES = 1000 * 60f
+private const val BURN_IN_PREVENTION_PERIOD_Y = 521f
+private const val BURN_IN_PREVENTION_PERIOD_X = 83f
+
+/**
+ * Returns the translation offset that should be used to avoid burn in at
+ * the current time (in pixels.)
+ *
+ * @param amplitude Maximum translation that will be interpolated.
+ * @param xAxis If we're moving on X or Y.
+ */
+fun getBurnInOffset(amplitude: Int, xAxis: Boolean): Int {
+ return zigzag(System.currentTimeMillis() / MILLIS_PER_MINUTES,
+ amplitude.toFloat(),
+ if (xAxis) BURN_IN_PREVENTION_PERIOD_X else BURN_IN_PREVENTION_PERIOD_Y).toInt()
+}
+
+/**
+ * Implements a continuous, piecewise linear, periodic zig-zag function
+ *
+ * Can be thought of as a linear approximation of abs(sin(x)))
+ *
+ * @param period period of the function, ie. zigzag(x + period) == zigzag(x)
+ * @param amplitude maximum value of the function
+ * @return a value between 0 and amplitude
+ */
+private fun zigzag(x: Float, amplitude: Float, period: Float): Float {
+ val xprime = x % period / (period / 2)
+ val interpolationAmount = if (xprime <= 1) xprime else 2 - xprime
+ return MathUtils.lerp(0f, amplitude, interpolationAmount)
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
index d5541e9..7bc7e5f 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -33,6 +33,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.UserHandle;
+import android.util.ArraySet;
import android.util.Log;
import android.view.LayoutInflater;
@@ -41,7 +42,9 @@
import com.android.systemui.plugins.VersionInfo.InvalidVersionException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import com.android.systemui.R;
public class PluginInstanceManager<T extends Plugin> {
@@ -63,17 +66,19 @@
private final boolean isDebuggable;
private final PackageManager mPm;
private final PluginManagerImpl mManager;
+ private final ArraySet<String> mWhitelistedPlugins = new ArraySet<>();
PluginInstanceManager(Context context, String action, PluginListener<T> listener,
boolean allowMultiple, Looper looper, VersionInfo version, PluginManagerImpl manager) {
this(context, context.getPackageManager(), action, listener, allowMultiple, looper, version,
- manager, Build.IS_DEBUGGABLE);
+ manager, Build.IS_DEBUGGABLE,
+ context.getResources().getStringArray(R.array.config_pluginWhitelist));
}
@VisibleForTesting
PluginInstanceManager(Context context, PackageManager pm, String action,
PluginListener<T> listener, boolean allowMultiple, Looper looper, VersionInfo version,
- PluginManagerImpl manager, boolean debuggable) {
+ PluginManagerImpl manager, boolean debuggable, String[] pluginWhitelist) {
mMainHandler = new MainHandler(Looper.getMainLooper());
mPluginHandler = new PluginHandler(looper);
mManager = manager;
@@ -83,6 +88,7 @@
mListener = listener;
mAllowMultiple = allowMultiple;
mVersion = version;
+ mWhitelistedPlugins.addAll(Arrays.asList(pluginWhitelist));
isDebuggable = debuggable;
}
@@ -294,9 +300,9 @@
protected PluginInfo<T> handleLoadPlugin(ComponentName component) {
// This was already checked, but do it again here to make extra extra sure, we don't
// use these on production builds.
- if (!isDebuggable) {
+ if (!isDebuggable && !mWhitelistedPlugins.contains(component.getPackageName())) {
// Never ever ever allow these on production builds, they are only for prototyping.
- Log.d(TAG, "Somehow hit second debuggable check");
+ Log.w(TAG, "Plugin cannot be loaded on production build: " + component);
return null;
}
String pkg = component.getPackageName();
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
index 2a17e35..1cbf1fe 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
@@ -37,13 +37,12 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import android.util.Log.TerribleFailure;
-import android.util.Log.TerribleFailureHandler;
import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.Dependency;
+import com.android.systemui.R;
import com.android.systemui.plugins.PluginInstanceManager.PluginContextWrapper;
import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
import com.android.systemui.plugins.annotations.ProvidesInterface;
@@ -53,13 +52,14 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.Arrays;
import java.util.Map;
-
/**
* @see Plugin
*/
public class PluginManagerImpl extends BroadcastReceiver implements PluginManager {
+ private static final String TAG = PluginManagerImpl.class.getSimpleName();
static final String DISABLE_PLUGIN = "com.android.systemui.action.DISABLE_PLUGIN";
private static PluginManager sInstance;
@@ -68,6 +68,7 @@
= new ArrayMap<>();
private final Map<String, ClassLoader> mClassLoaders = new ArrayMap<>();
private final ArraySet<String> mOneShotPackages = new ArraySet<>();
+ private final ArraySet<String> mWhitelistedPlugins = new ArraySet<>();
private final Context mContext;
private final PluginInstanceManagerFactory mFactory;
private final boolean isDebuggable;
@@ -79,30 +80,30 @@
private boolean mWtfsSet;
public PluginManagerImpl(Context context) {
- this(context, new PluginInstanceManagerFactory(),
- Build.IS_DEBUGGABLE, Thread.getUncaughtExceptionPreHandler());
+ this(context, new PluginInstanceManagerFactory(), Build.IS_DEBUGGABLE,
+ context.getResources().getStringArray(R.array.config_pluginWhitelist),
+ Thread.getUncaughtExceptionPreHandler());
}
@VisibleForTesting
PluginManagerImpl(Context context, PluginInstanceManagerFactory factory, boolean debuggable,
- UncaughtExceptionHandler defaultHandler) {
+ String[] whitelistedPlugins, UncaughtExceptionHandler defaultHandler) {
mContext = context;
mFactory = factory;
mLooper = Dependency.get(Dependency.BG_LOOPER);
isDebuggable = debuggable;
+ mWhitelistedPlugins.addAll(Arrays.asList(whitelistedPlugins));
mPluginPrefs = new PluginPrefs(mContext);
PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler(
defaultHandler);
Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler);
- if (isDebuggable) {
- new Handler(mLooper).post(() -> {
- // Plugin dependencies that don't have another good home can go here, but
- // dependencies that have better places to init can happen elsewhere.
- Dependency.get(PluginDependencyProvider.class)
- .allowPluginDependency(ActivityStarter.class);
- });
- }
+ new Handler(mLooper).post(() -> {
+ // Plugin dependencies that don't have another good home can go here, but
+ // dependencies that have better places to init can happen elsewhere.
+ Dependency.get(PluginDependencyProvider.class)
+ .allowPluginDependency(ActivityStarter.class);
+ });
}
public <T extends Plugin> T getOneShotPlugin(Class<T> cls) {
@@ -117,10 +118,6 @@
}
public <T extends Plugin> T getOneShotPlugin(String action, Class<?> cls) {
- if (!isDebuggable) {
- // Never ever ever allow these on production builds, they are only for prototyping.
- return null;
- }
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new RuntimeException("Must be called from UI thread");
}
@@ -153,10 +150,6 @@
public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
Class cls, boolean allowMultiple) {
- if (!isDebuggable) {
- // Never ever ever allow these on production builds, they are only for prototyping.
- return;
- }
mPluginPrefs.addAction(action);
PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener,
allowMultiple, mLooper, cls, this);
@@ -166,10 +159,6 @@
}
public void removePluginListener(PluginListener<?> listener) {
- if (!isDebuggable) {
- // Never ever ever allow these on production builds, they are only for prototyping.
- return;
- }
if (!mPluginMap.containsKey(listener)) return;
mPluginMap.remove(listener).destroy();
if (mPluginMap.size() == 0) {
@@ -261,6 +250,11 @@
}
public ClassLoader getClassLoader(String sourceDir, String pkg) {
+ if (!isDebuggable && !mWhitelistedPlugins.contains(pkg)) {
+ Log.w(TAG, "Cannot get class loader for non-whitelisted plugin. Src:" + sourceDir +
+ ", pkg: " + pkg);
+ return null;
+ }
if (mClassLoaders.containsKey(pkg)) {
return mClassLoaders.get(pkg);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 3f7eeb8..dc17dd8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -69,6 +69,7 @@
private final QSDetailClipper mClipper;
private final LightBarController mLightBarController;
private final TileQueryHelper mTileQueryHelper;
+ private final View mTransparentView;
private boolean isShown;
private QSTileHost mHost;
@@ -108,6 +109,7 @@
mToolbar.getNavigationIcon().setTint(accentColor);
mToolbar.getOverflowIcon().setTint(accentColor);
mRecyclerView = findViewById(android.R.id.list);
+ mTransparentView = findViewById(R.id.customizer_transparent_view);
mTileAdapter = new TileAdapter(getContext());
mTileQueryHelper = new TileQueryHelper(context, mTileAdapter);
mRecyclerView.setAdapter(mTileAdapter);
@@ -127,6 +129,14 @@
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
updateNavBackDrop(newConfig);
+ updateResources();
+ }
+
+ private void updateResources() {
+ LayoutParams lp = (LayoutParams) mTransparentView.getLayoutParams();
+ lp.height = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.quick_qs_offset_height);
+ mTransparentView.setLayoutParams(lp);
}
private void updateNavBackDrop(Configuration newConfig) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index e19c844..5c0b328 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -161,7 +161,7 @@
default void onRotationProposal(int rotation, boolean isValid) { }
default void showBiometricDialog(Bundle bundle, IBiometricPromptReceiver receiver,
- int type) { }
+ int type, boolean requireConfirmation) { }
default void onBiometricAuthenticated() { }
default void onBiometricHelp(String message) { }
default void onBiometricError(String error) { }
@@ -514,12 +514,14 @@
}
@Override
- public void showBiometricDialog(Bundle bundle, IBiometricPromptReceiver receiver, int type) {
+ public void showBiometricDialog(Bundle bundle, IBiometricPromptReceiver receiver, int type,
+ boolean requireConfirmation) {
synchronized (mLock) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = bundle;
args.arg2 = receiver;
args.argi1 = type;
+ args.arg3 = requireConfirmation;
mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args)
.sendToTarget();
}
@@ -763,7 +765,8 @@
mCallbacks.get(i).showBiometricDialog(
(Bundle) someArgs.arg1,
(IBiometricPromptReceiver) someArgs.arg2,
- someArgs.argi1);
+ someArgs.argi1,
+ (boolean) someArgs.arg3);
}
someArgs.recycle();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 551e8a9..0c5f391 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -298,27 +298,6 @@
if (mVisible) {
// Walk down a precedence-ordered list of what indication
// should be shown based on user or device state
- if (mDozing) {
- mTextView.setTextColor(Color.WHITE);
- if (!TextUtils.isEmpty(mTransientIndication)) {
- // When dozing we ignore any text color and use white instead, because
- // colors can be hard to read in low brightness.
- mTextView.switchIndication(mTransientIndication);
- } else if (mPowerPluggedIn) {
- String indication = computePowerIndication();
- if (animate) {
- animateText(mTextView, indication);
- } else {
- mTextView.switchIndication(indication);
- }
- } else {
- String percentage = NumberFormat.getPercentInstance()
- .format(mBatteryLevel / 100f);
- mTextView.switchIndication(percentage);
- }
- return;
- }
-
KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
int userId = KeyguardUpdateMonitor.getCurrentUser();
String trustGrantedIndication = getTrustGrantedIndication();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 019e88b..9b1d334 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1037,7 +1037,7 @@
removeView(mMenuRow.getMenuView());
}
mMenuRow = plugin;
- if (mMenuRow.useDefaultMenuItems()) {
+ if (mMenuRow.shouldUseDefaultMenuItems()) {
ArrayList<MenuItem> items = new ArrayList<>();
items.add(NotificationMenuRow.createInfoItem(mContext));
items.add(NotificationMenuRow.createSnoozeItem(mContext));
@@ -1787,7 +1787,7 @@
getEntry().expandedIcon.setScrollX((int) -translationX);
}
if (mMenuRow.getMenuView() != null) {
- mMenuRow.onTranslationUpdate(translationX);
+ mMenuRow.onParentTranslationUpdate(translationX);
}
}
@@ -2292,7 +2292,7 @@
notifyHeightChanged(true /* needsAnimation */);
}
if (mMenuRow.getMenuView() != null) {
- mMenuRow.onHeightUpdate();
+ mMenuRow.onParentHeightUpdate();
}
updateContentShiftHeight();
if (mLayoutListener != null) {
@@ -2543,7 +2543,7 @@
mGuts.setActualHeight(height);
}
if (mMenuRow.getMenuView() != null) {
- mMenuRow.onHeightUpdate();
+ mMenuRow.onParentHeightUpdate();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index dec88d4..7e60c4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -16,14 +16,13 @@
package com.android.systemui.statusbar.notification.row;
-import static com.android.systemui.SwipeHelper.SWIPED_FAR_ENOUGH_SIZE_FRACTION;
-
import java.util.ArrayList;
+import static com.android.systemui.SwipeHelper.SWIPED_FAR_ENOUGH_SIZE_FRACTION;
+
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
@@ -38,25 +37,21 @@
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
-import android.util.Log;
import android.service.notification.StatusBarNotification;
import android.view.LayoutInflater;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
+import com.android.internal.annotations.VisibleForTesting;
+
public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnClickListener,
ExpandableNotificationRow.LayoutListener {
private static final boolean DEBUG = false;
private static final String TAG = "swipe";
- private static final int ICON_ALPHA_ANIM_DURATION = 200;
- private static final long SHOW_MENU_DELAY = 60;
- private static final long SWIPE_MENU_TIMING = 200;
-
// Notification must be swiped at least this fraction of a single menu item to show menu
private static final float SWIPED_FAR_ENOUGH_MENU_FRACTION = 0.25f;
private static final float SWIPED_FAR_ENOUGH_MENU_UNCLEARABLE_FRACTION = 0.15f;
@@ -65,6 +60,9 @@
// menu item to snap back to menu (else it will cover the menu or it'll be dismissed)
private static final float SWIPED_BACK_ENOUGH_TO_COVER_FRACTION = 0.2f;
+ private static final int ICON_ALPHA_ANIM_DURATION = 200;
+ private static final long SHOW_MENU_DELAY = 60;
+
private ExpandableNotificationRow mParent;
private Context mContext;
@@ -89,22 +87,20 @@
private int[] mIconLocation = new int[2];
private int[] mParentLocation = new int[2];
- private float mHorizSpaceForIcon = -1;
+ private int mHorizSpaceForIcon = -1;
private int mVertSpaceForIcons = -1;
private int mIconPadding = -1;
private int mSidePadding;
private float mAlpha = 0f;
- private float mPrevX;
private CheckForDrag mCheckForDrag;
private Handler mHandler;
- private boolean mMenuSnappedTo;
+ private boolean mMenuSnapped;
private boolean mMenuSnappedOnLeft;
private boolean mShouldShowMenu;
- private NotificationSwipeActionHelper mSwipeHelper;
private boolean mIsUserTouching;
public NotificationMenuRow(Context context) {
@@ -134,9 +130,34 @@
return mSnoozeItem;
}
- @Override
- public void setSwipeActionHelper(NotificationSwipeActionHelper helper) {
- mSwipeHelper = helper;
+ @VisibleForTesting
+ protected ExpandableNotificationRow getParent() {
+ return mParent;
+ }
+
+ @VisibleForTesting
+ protected boolean isMenuOnLeft() {
+ return mOnLeft;
+ }
+
+ @VisibleForTesting
+ protected boolean isMenuSnappedOnLeft() {
+ return mMenuSnappedOnLeft;
+ }
+
+ @VisibleForTesting
+ protected boolean isMenuSnapped() {
+ return mMenuSnapped;
+ }
+
+ @VisibleForTesting
+ protected boolean isDismissing() {
+ return mDismissing;
+ }
+
+ @VisibleForTesting
+ protected boolean isSnapping() {
+ return mSnapping;
}
@Override
@@ -155,17 +176,37 @@
return mAlpha > 0;
}
+ @VisibleForTesting
+ protected boolean isUserTouching() {
+ return mIsUserTouching;
+ }
+
+ @Override
+ public boolean shouldShowMenu() {
+ return mShouldShowMenu;
+ }
+
@Override
public View getMenuView() {
return mMenuContainer;
}
+ @VisibleForTesting
+ protected float getTranslation() {
+ return mTranslation;
+ }
+
@Override
public void resetMenu() {
resetState(true);
}
@Override
+ public void onTouchEnd() {
+ mIsUserTouching = false;
+ }
+
+ @Override
public void onNotificationUpdated(StatusBarNotification sbn) {
if (mMenuContainer == null) {
// Menu hasn't been created yet, no need to do anything.
@@ -222,9 +263,7 @@
mIconsPlaced = false;
setMenuLocation();
if (!mIsUserTouching) {
- // If the # of items showing changed we need to update the snap position
- showMenu(mParent, mOnLeft ? getSpaceForMenu() : -getSpaceForMenu(),
- 0 /* velocity */);
+ onSnapOpen();
}
}
}
@@ -236,7 +275,7 @@
mAnimating = false;
mSnapping = false;
mDismissing = false;
- mMenuSnappedTo = false;
+ mMenuSnapped = false;
setMenuLocation();
if (mMenuListener != null && notify) {
mMenuListener.onMenuReset(mParent);
@@ -244,185 +283,102 @@
}
@Override
- public boolean onTouchEvent(View view, MotionEvent ev, float velocity) {
- final int action = ev.getActionMasked();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- mSnapping = false;
- if (mFadeAnimator != null) {
- mFadeAnimator.cancel();
- }
- mHandler.removeCallbacks(mCheckForDrag);
+ public void onTouchMove(float delta) {
+ mSnapping = false;
+
+ if (!isTowardsMenu(delta) && isMenuLocationChange()) {
+ // Don't consider it "snapped" if location has changed.
+ mMenuSnapped = false;
+
+ // Changed directions, make sure we check to fade in icon again.
+ if (!mHandler.hasCallbacks(mCheckForDrag)) {
+ // No check scheduled, set null to schedule a new one.
mCheckForDrag = null;
- mPrevX = ev.getRawX();
- mIsUserTouching = true;
- break;
-
- case MotionEvent.ACTION_MOVE:
- mSnapping = false;
- float diffX = ev.getRawX() - mPrevX;
- mPrevX = ev.getRawX();
- if (!isTowardsMenu(diffX) && isMenuLocationChange()) {
- // Don't consider it "snapped" if location has changed.
- mMenuSnappedTo = false;
-
- // Changed directions, make sure we check to fade in icon again.
- if (!mHandler.hasCallbacks(mCheckForDrag)) {
- // No check scheduled, set null to schedule a new one.
- mCheckForDrag = null;
- } else {
- // Check scheduled, reset alpha and update location; check will fade it in
- setMenuAlpha(0f);
- setMenuLocation();
- }
- }
- if (mShouldShowMenu
- && !NotificationStackScrollLayout.isPinnedHeadsUp(view)
- && !mParent.areGutsExposed()
- && !mParent.isDark()
- && (mCheckForDrag == null || !mHandler.hasCallbacks(mCheckForDrag))) {
- // Only show the menu if we're not a heads up view and guts aren't exposed.
- mCheckForDrag = new CheckForDrag();
- mHandler.postDelayed(mCheckForDrag, SHOW_MENU_DELAY);
- }
- break;
-
- case MotionEvent.ACTION_UP:
- mIsUserTouching = false;
- return handleUpEvent(ev, view, velocity);
- case MotionEvent.ACTION_CANCEL:
- mIsUserTouching = false;
- cancelDrag();
- return false;
- }
- return false;
- }
-
- private boolean handleUpEvent(MotionEvent ev, View animView, float velocity) {
- // If the menu should not be shown, then there is no need to check if the a swipe
- // should result in a snapping to the menu. As a result, just check if the swipe
- // was enough to dismiss the notification.
- if (!mShouldShowMenu) {
- if (mSwipeHelper.isDismissGesture(ev)) {
- dismiss(animView, velocity);
} else {
- snapBack(animView, velocity);
+ // Check scheduled, reset alpha and update location; check will fade it in
+ setMenuAlpha(0f);
+ setMenuLocation();
}
- return true;
}
-
- final boolean gestureTowardsMenu = isTowardsMenu(velocity);
- final boolean gestureFastEnough =
- mSwipeHelper.getMinDismissVelocity() <= Math.abs(velocity);
- final boolean gestureFarEnough =
- mSwipeHelper.swipedFarEnough(mTranslation, mParent.getWidth());
- final double timeForGesture = ev.getEventTime() - ev.getDownTime();
- final boolean showMenuForSlowOnGoing = !mParent.canViewBeDismissed()
- && timeForGesture >= SWIPE_MENU_TIMING;
- final float menuSnapTarget = mOnLeft ? getSpaceForMenu() : -getSpaceForMenu();
-
- if (DEBUG) {
- Log.d(TAG, "mTranslation= " + mTranslation
- + " mAlpha= " + mAlpha
- + " velocity= " + velocity
- + " mMenuSnappedTo= " + mMenuSnappedTo
- + " mMenuSnappedOnLeft= " + mMenuSnappedOnLeft
- + " mOnLeft= " + mOnLeft
- + " minDismissVel= " + mSwipeHelper.getMinDismissVelocity()
- + " isDismissGesture= " + mSwipeHelper.isDismissGesture(ev)
- + " gestureTowardsMenu= " + gestureTowardsMenu
- + " gestureFastEnough= " + gestureFastEnough
- + " gestureFarEnough= " + gestureFarEnough);
+ if (mShouldShowMenu
+ && !NotificationStackScrollLayout.isPinnedHeadsUp(getParent())
+ && !mParent.areGutsExposed()
+ && !mParent.isDark()
+ && (mCheckForDrag == null || !mHandler.hasCallbacks(mCheckForDrag))) {
+ // Only show the menu if we're not a heads up view and guts aren't exposed.
+ mCheckForDrag = new CheckForDrag();
+ mHandler.postDelayed(mCheckForDrag, SHOW_MENU_DELAY);
}
-
- if (mMenuSnappedTo && isMenuVisible() && mMenuSnappedOnLeft == mOnLeft) {
- // Menu was snapped to previously and we're on the same side, figure out if
- // we should stick to the menu, snap back into place, or dismiss
- final float maximumSwipeDistance = mHorizSpaceForIcon
- * SWIPED_BACK_ENOUGH_TO_COVER_FRACTION;
- final float targetLeft = getSpaceForMenu() - maximumSwipeDistance;
- final float targetRight = mParent.getWidth() * SWIPED_FAR_ENOUGH_SIZE_FRACTION;
- boolean withinSnapMenuThreshold = mOnLeft
- ? mTranslation > targetLeft && mTranslation < targetRight
- : mTranslation < -targetLeft && mTranslation > -targetRight;
- boolean shouldSnapTo = mOnLeft ? mTranslation < targetLeft : mTranslation > -targetLeft;
- if (DEBUG) {
- Log.d(TAG, " withinSnapMenuThreshold= " + withinSnapMenuThreshold
- + " shouldSnapTo= " + shouldSnapTo
- + " targetLeft= " + targetLeft
- + " targetRight= " + targetRight);
- }
- if (withinSnapMenuThreshold && !mSwipeHelper.isDismissGesture(ev)) {
- // Haven't moved enough to unsnap from the menu
- showMenu(animView, menuSnapTarget, velocity);
- } else if (mSwipeHelper.isDismissGesture(ev) && !shouldSnapTo) {
- // Only dismiss if we're not moving towards the menu
- dismiss(animView, velocity);
- } else {
- snapBack(animView, velocity);
- }
- } else if (!mSwipeHelper.isFalseGesture(ev)
- && (swipedEnoughToShowMenu() && (!gestureFastEnough || showMenuForSlowOnGoing))
- || (gestureTowardsMenu && !mSwipeHelper.isDismissGesture(ev))) {
- // Menu has not been snapped to previously and this is menu revealing gesture
- showMenu(animView, menuSnapTarget, velocity);
- } else if (mSwipeHelper.isDismissGesture(ev) && !gestureTowardsMenu) {
- dismiss(animView, velocity);
- } else {
- snapBack(animView, velocity);
- }
- return true;
}
- private void showMenu(View animView, float targetLeft, float velocity) {
- mMenuSnappedTo = true;
- mMenuSnappedOnLeft = mOnLeft;
- mMenuListener.onMenuShown(animView);
- mSwipeHelper.snap(animView, targetLeft, velocity);
+ @VisibleForTesting
+ protected void beginDrag() {
+ mSnapping = false;
+ if (mFadeAnimator != null) {
+ mFadeAnimator.cancel();
+ }
+ mHandler.removeCallbacks(mCheckForDrag);
+ mCheckForDrag = null;
+ mIsUserTouching = true;
}
- private void snapBack(View animView, float velocity) {
+ @Override
+ public void onTouchStart() {
+ beginDrag();
+ }
+
+ @Override
+ public void onSnapOpen() {
+ mMenuSnapped = true;
+ mMenuSnappedOnLeft = isMenuOnLeft();
+ if (mMenuListener != null) {
+ mMenuListener.onMenuShown(getParent());
+ }
+ }
+
+ @Override
+ public void onSnapClosed() {
cancelDrag();
- mMenuSnappedTo = false;
+ mMenuSnapped = false;
mSnapping = true;
- mSwipeHelper.snap(animView, 0 /* leftTarget */, velocity);
}
- private void dismiss(View animView, float velocity) {
+ @Override
+ public void onDismiss() {
cancelDrag();
- mMenuSnappedTo = false;
+ mMenuSnapped = false;
mDismissing = true;
- mSwipeHelper.dismiss(animView, velocity);
}
- private void cancelDrag() {
+ @VisibleForTesting
+ protected void cancelDrag() {
if (mFadeAnimator != null) {
mFadeAnimator.cancel();
}
mHandler.removeCallbacks(mCheckForDrag);
}
- /**
- * @return whether the notification has been translated enough to show the menu and not enough
- * to be dismissed.
- */
- private boolean swipedEnoughToShowMenu() {
- final float multiplier = mParent.canViewBeDismissed()
+ @VisibleForTesting
+ protected float getMinimumSwipeDistance() {
+ final float multiplier = getParent().canViewBeDismissed()
? SWIPED_FAR_ENOUGH_MENU_FRACTION
: SWIPED_FAR_ENOUGH_MENU_UNCLEARABLE_FRACTION;
- final float minimumSwipeDistance = mHorizSpaceForIcon * multiplier;
- return !mSwipeHelper.swipedFarEnough(0, 0) && isMenuVisible()
- && (mOnLeft ? mTranslation > minimumSwipeDistance
- : mTranslation < -minimumSwipeDistance);
+ return mHorizSpaceForIcon * multiplier;
+ }
+
+ @VisibleForTesting
+ protected float getMaximumSwipeDistance() {
+ return mHorizSpaceForIcon * SWIPED_BACK_ENOUGH_TO_COVER_FRACTION;
}
/**
* Returns whether the gesture is towards the menu location or not.
*/
- private boolean isTowardsMenu(float movement) {
+ @Override
+ public boolean isTowardsMenu(float movement) {
return isMenuVisible()
- && ((mOnLeft && movement <= 0)
- || (!mOnLeft && movement >= 0));
+ && ((isMenuOnLeft() && movement <= 0)
+ || (!isMenuOnLeft() && movement >= 0));
}
@Override
@@ -445,7 +401,7 @@
}
@Override
- public void onHeightUpdate() {
+ public void onParentHeightUpdate() {
if (mParent == null || mMenuItems.size() == 0 || mMenuContainer == null) {
return;
}
@@ -460,7 +416,7 @@
}
@Override
- public void onTranslationUpdate(float translation) {
+ public void onParentTranslationUpdate(float translation) {
mTranslation = translation;
if (mAnimating || !mMenuFadedIn) {
// Don't adjust when animating, or if the menu hasn't been shown yet.
@@ -492,13 +448,15 @@
final int x = mIconLocation[0] - mParentLocation[0] + centerX;
final int y = mIconLocation[1] - mParentLocation[1] + centerY;
final int index = mMenuContainer.indexOfChild(v);
- mMenuListener.onMenuClicked(mParent, x, y, mMenuItems.get(index));
+ if (mMenuListener != null) {
+ mMenuListener.onMenuClicked(mParent, x, y, mMenuItems.get(index));
+ }
}
private boolean isMenuLocationChange() {
boolean onLeft = mTranslation > mIconPadding;
boolean onRight = mTranslation < -mIconPadding;
- if ((mOnLeft && onRight) || (!mOnLeft && onLeft)) {
+ if ((isMenuOnLeft() && onRight) || (!isMenuOnLeft() && onLeft)) {
return true;
}
return false;
@@ -506,7 +464,7 @@
private void setMenuLocation() {
boolean showOnLeft = mTranslation > 0;
- if ((mIconsPlaced && showOnLeft == mOnLeft) || mSnapping || mMenuContainer == null
+ if ((mIconsPlaced && showOnLeft == isMenuOnLeft()) || isSnapping() || mMenuContainer == null
|| !mMenuContainer.isAttachedToWindow()) {
// Do nothing
return;
@@ -522,7 +480,8 @@
mIconsPlaced = true;
}
- private void setMenuAlpha(float alpha) {
+ @VisibleForTesting
+ protected void setMenuAlpha(float alpha) {
mAlpha = alpha;
if (mMenuContainer == null) {
return;
@@ -542,7 +501,8 @@
/**
* Returns the horizontal space in pixels required to display the menu.
*/
- private float getSpaceForMenu() {
+ @VisibleForTesting
+ protected int getSpaceForMenu() {
return mHorizSpaceForIcon * mMenuContainer.getChildCount();
}
@@ -646,12 +606,71 @@
parent.addView(menuView);
menuView.setOnClickListener(this);
FrameLayout.LayoutParams lp = (LayoutParams) menuView.getLayoutParams();
- lp.width = (int) mHorizSpaceForIcon;
- lp.height = (int) mHorizSpaceForIcon;
+ lp.width = mHorizSpaceForIcon;
+ lp.height = mHorizSpaceForIcon;
menuView.setLayoutParams(lp);
}
}
+ @VisibleForTesting
+ /**
+ * Determine the minimum offset below which the menu should snap back closed.
+ */
+ protected float getSnapBackThreshold() {
+ return getSpaceForMenu() - getMaximumSwipeDistance();
+ }
+
+ /**
+ * Determine the maximum offset above which the parent notification should be dismissed.
+ * @return
+ */
+ @VisibleForTesting
+ protected float getDismissThreshold() {
+ return getParent().getWidth() * SWIPED_FAR_ENOUGH_SIZE_FRACTION;
+ }
+
+ @Override
+ public boolean isWithinSnapMenuThreshold() {
+ float translation = getTranslation();
+ float snapBackThreshold = getSnapBackThreshold();
+ float targetRight = getDismissThreshold();
+ return isMenuOnLeft()
+ ? translation > snapBackThreshold && translation < targetRight
+ : translation < -snapBackThreshold && translation > -targetRight;
+ }
+
+ @Override
+ public boolean isSwipedEnoughToShowMenu() {
+ final float minimumSwipeDistance = getMinimumSwipeDistance();
+ final float translation = getTranslation();
+ return isMenuVisible() && (isMenuOnLeft() ?
+ translation > minimumSwipeDistance
+ : translation < -minimumSwipeDistance);
+ }
+
+ @Override
+ public int getMenuSnapTarget() {
+ return isMenuOnLeft() ? getSpaceForMenu() : -getSpaceForMenu();
+ }
+
+ @Override
+ public boolean shouldSnapBack() {
+ float translation = getTranslation();
+ float targetLeft = getSnapBackThreshold();
+ return isMenuOnLeft() ? translation < targetLeft : translation > -targetLeft;
+ }
+
+ @Override
+ public boolean isSnappedAndOnSameSide() {
+ return isMenuSnapped() && isMenuVisible()
+ && isMenuSnappedOnLeft() == isMenuOnLeft();
+ }
+
+ @Override
+ public boolean canBeDismissed() {
+ return getParent().canViewBeDismissed();
+ }
+
public static class NotificationMenuItem implements MenuItem {
View mMenuView;
GutsContent mGutsContent;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 958a162..72c2c0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -26,7 +26,6 @@
import android.animation.TimeAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.annotation.FloatRange;
import android.annotation.Nullable;
import android.app.WallpaperManager;
import android.content.Context;
@@ -5315,13 +5314,15 @@
void flingTopOverscroll(float velocity, boolean open);
}
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private class NotificationSwipeHelper extends SwipeHelper
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ private class NotificationSwipeHelper extends SwipeHelper
implements NotificationSwipeActionHelper {
private static final long COVER_MENU_DELAY = 4000;
private Runnable mFalsingCheck;
private Handler mHandler;
+ private static final long SWIPE_MENU_TIMING = 200;
+
public NotificationSwipeHelper(int swipeDirection, Callback callback, Context context) {
super(swipeDirection, callback, context);
mHandler = new Handler();
@@ -5337,7 +5338,7 @@
public void onDownUpdate(View currView, MotionEvent ev) {
mTranslatingParentView = currView;
if (mCurrMenuRow != null) {
- mCurrMenuRow.onTouchEvent(currView, ev, 0 /* velocity */);
+ mCurrMenuRow.onTouchStart();
}
mCurrMenuRow = null;
mHandler.removeCallbacks(mFalsingCheck);
@@ -5350,18 +5351,21 @@
if (row.getEntry().hasFinishedInitialization()) {
mCurrMenuRow = row.createMenu();
- mCurrMenuRow.setSwipeActionHelper(NotificationSwipeHelper.this);
mCurrMenuRow.setMenuClickListener(NotificationStackScrollLayout.this);
- mCurrMenuRow.onTouchEvent(currView, ev, 0 /* velocity */);
+ mCurrMenuRow.onTouchStart();
}
}
}
+ private boolean swipedEnoughToShowMenu(NotificationMenuRowPlugin menuRow) {
+ return !swipedFarEnough() && menuRow.isSwipedEnoughToShowMenu();
+ }
+
@Override
public void onMoveUpdate(View view, MotionEvent ev, float translation, float delta) {
mHandler.removeCallbacks(mFalsingCheck);
if (mCurrMenuRow != null) {
- mCurrMenuRow.onTouchEvent(view, ev, 0 /* velocity */);
+ mCurrMenuRow.onTouchMove(delta);
}
}
@@ -5369,12 +5373,92 @@
public boolean handleUpEvent(MotionEvent ev, View animView, float velocity,
float translation) {
if (mCurrMenuRow != null) {
- return mCurrMenuRow.onTouchEvent(animView, ev, velocity);
+ mCurrMenuRow.onTouchEnd();
+ handleMenuRowSwipe(ev, animView, velocity, mCurrMenuRow);
+ return true;
}
return false;
}
@Override
+ public boolean swipedFarEnough(float translation, float viewSize) {
+ return swipedFarEnough();
+ }
+
+ private void handleMenuRowSwipe(MotionEvent ev, View animView, float velocity,
+ NotificationMenuRowPlugin menuRow) {
+ if (!menuRow.shouldShowMenu()) {
+ // If the menu should not be shown, then there is no need to check if the a swipe
+ // should result in a snapping to the menu. As a result, just check if the swipe
+ // was enough to dismiss the notification.
+ if (isDismissGesture(ev)) {
+ dismiss(animView, velocity);
+ } else {
+ snapBack(animView, velocity);
+ menuRow.onSnapClosed();
+ }
+ return;
+ }
+
+ if (menuRow.isSnappedAndOnSameSide()) {
+ // Menu was snapped to previously and we're on the same side
+ handleSwipeFromSnap(ev, animView, velocity, menuRow);
+ } else {
+ // Menu has not been snapped, or was snapped previously but is now on
+ // the opposite side.
+ handleSwipeFromNonSnap(ev, animView, velocity, menuRow);
+ }
+ }
+
+ private void handleSwipeFromNonSnap(MotionEvent ev, View animView, float velocity,
+ NotificationMenuRowPlugin menuRow) {
+ boolean isDismissGesture = isDismissGesture(ev);
+ final boolean gestureTowardsMenu = menuRow.isTowardsMenu(velocity);
+ final boolean gestureFastEnough =
+ mSwipeHelper.getMinDismissVelocity() <= Math.abs(velocity);
+
+ final double timeForGesture = ev.getEventTime() - ev.getDownTime();
+ final boolean showMenuForSlowOnGoing = !menuRow.canBeDismissed()
+ && timeForGesture >= SWIPE_MENU_TIMING;
+
+ if (!isFalseGesture(ev)
+ && (swipedEnoughToShowMenu(menuRow)
+ && (!gestureFastEnough || showMenuForSlowOnGoing))
+ || (gestureTowardsMenu && !isDismissGesture)) {
+ // Menu has not been snapped to previously and this is menu revealing gesture
+ snapOpen(animView, menuRow.getMenuSnapTarget(), velocity);
+ menuRow.onSnapOpen();
+ } else if (isDismissGesture(ev) && !gestureTowardsMenu) {
+ dismiss(animView, velocity);
+ menuRow.onDismiss();
+ } else {
+ snapBack(animView, velocity);
+ menuRow.onSnapClosed();
+ }
+ }
+
+ private void handleSwipeFromSnap(MotionEvent ev, View animView, float velocity,
+ NotificationMenuRowPlugin menuRow) {
+ boolean isDismissGesture = isDismissGesture(ev);
+
+ final boolean withinSnapMenuThreshold =
+ menuRow.isWithinSnapMenuThreshold();
+
+ if (withinSnapMenuThreshold && !isDismissGesture) {
+ // Haven't moved enough to unsnap from the menu
+ menuRow.onSnapOpen();
+ snapOpen(animView, menuRow.getMenuSnapTarget(), velocity);
+ } else if (isDismissGesture && !menuRow.shouldSnapBack()) {
+ // Only dismiss if we're not moving towards the menu
+ dismiss(animView, velocity);
+ menuRow.onDismiss();
+ } else {
+ snapBack(animView, velocity);
+ menuRow.onSnapClosed();
+ }
+ }
+
+ @Override
public void dismissChild(final View view, float velocity,
boolean useAccelerateInterpolator) {
super.dismissChild(view, velocity, useAccelerateInterpolator);
@@ -5403,10 +5487,6 @@
mStatusBar.setNotificationSnoozed(sbn, snoozeOption);
}
- public boolean isFalseGesture(MotionEvent ev) {
- return super.isFalseGesture(ev);
- }
-
private void handleMenuCoveredOrDismissed() {
if (mMenuExposedView != null && mMenuExposedView == mTranslatingParentView) {
mMenuExposedView = null;
@@ -5440,13 +5520,12 @@
}
@Override
- public void snap(View animView, float targetLeft, float velocity) {
+ public void snapOpen(View animView, int targetLeft, float velocity) {
snapChild(animView, targetLeft, velocity);
}
- @Override
- public boolean swipedFarEnough(float translation, float viewSize) {
- return swipedFarEnough();
+ private void snapBack(View animView, float velocity) {
+ snapChild(animView, 0, velocity);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
new file mode 100644
index 0000000..4f957bf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java
@@ -0,0 +1,76 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import android.annotation.DrawableRes;
+import android.annotation.IdRes;
+import android.content.Context;
+import android.view.View;
+import com.android.systemui.statusbar.policy.KeyButtonDrawable;
+import com.android.systemui.statusbar.policy.KeyButtonView;
+
+/**
+ * Simple contextual button that is added to the {@link ContextualButtonGroup}. Extend if need extra
+ * functionality.
+ */
+public class ContextualButton extends ButtonDispatcher {
+
+ protected final @DrawableRes int mIconResId;
+
+ /**
+ * Create a contextual button that will use a {@link KeyButtonView} and
+ * {@link KeyButtonDrawable} get and show the button from xml to its icon drawable.
+ * @param buttonResId the button view from xml layout
+ * @param iconResId icon resource to be used
+ */
+ public ContextualButton(@IdRes int buttonResId, @DrawableRes int iconResId) {
+ super(buttonResId);
+ mIconResId = iconResId;
+ }
+
+ /**
+ * Reload the drawable from resource id, should reapply the previous dark intensity.
+ */
+ public void updateIcon() {
+ final KeyButtonDrawable currentDrawable = getImageDrawable();
+ KeyButtonDrawable drawable = getNewDrawable();
+ if (currentDrawable != null) {
+ drawable.setDarkIntensity(currentDrawable.getDarkIntensity());
+ }
+ setImageDrawable(drawable);
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ super.setVisibility(visibility);
+
+ // Stop any active animations if hidden
+ final KeyButtonDrawable currentDrawable = getImageDrawable();
+ if (visibility != View.VISIBLE && currentDrawable != null && currentDrawable.canAnimate()) {
+ currentDrawable.clearAnimationCallbacks();
+ currentDrawable.resetAnimation();
+ }
+ }
+
+ protected KeyButtonDrawable getNewDrawable() {
+ return KeyButtonDrawable.create(getContext(), mIconResId, false /* shadow */);
+ }
+
+ protected Context getContext() {
+ return getCurrentView().getContext();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java
new file mode 100644
index 0000000..1b03966
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java
@@ -0,0 +1,155 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import android.annotation.IdRes;
+import android.annotation.NonNull;
+import android.view.View;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ContextualButtonGroup extends ButtonDispatcher {
+ private static final int INVALID_INDEX = -1;
+
+ // List of pairs that contains the button and if the button was visible within this group
+ private final List<ButtonData> mButtonData = new ArrayList<>();
+
+ public ContextualButtonGroup(@IdRes int containerId) {
+ super(containerId);
+ }
+
+ /**
+ * Add a contextual button to the group. The order of adding increases in its priority. The
+ * priority is used to determine which button should be visible when setting multiple button's
+ * visibility {@see setButtonVisiblity}.
+ * @param button the button added to the group
+ */
+ public void addButton(@NonNull ContextualButton button) {
+ mButtonData.add(new ButtonData(button));
+ }
+
+ public ContextualButton getContextButton(@IdRes int buttonResId) {
+ int index = getContextButtonIndex(buttonResId);
+ if (index != INVALID_INDEX) {
+ return mButtonData.get(index).button;
+ }
+ return null;
+ }
+
+ public ContextualButton getVisibleContextButton() {
+ for (int i = mButtonData.size() - 1; i >= 0; --i) {
+ if (mButtonData.get(i).markedVisible) {
+ return mButtonData.get(i).button;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Set the visibility of the button by {@param buttonResId} with {@param visible}. Only one
+ * button is shown at a time. The input button will only show up if it has higher priority than
+ * a previous button, otherwise it will be marked as visible and shown later if all higher
+ * priority buttons are invisible. Therefore hiding a button will show the next marked visible
+ * button. This group's view will be visible if at least one button is visible.
+ * @return if the button is visible after operation
+ * @throws RuntimeException if the input id does not match any of the ids in the group
+ */
+ public int setButtonVisiblity(@IdRes int buttonResId, boolean visible) {
+ final int index = getContextButtonIndex(buttonResId);
+ if (index == INVALID_INDEX) {
+ throw new RuntimeException("Cannot find the button id of " + buttonResId
+ + " in context group");
+ }
+ setVisibility(View.INVISIBLE);
+ mButtonData.get(index).markedVisible = visible;
+
+ // Make all buttons invisible except the first markedVisible button
+ boolean alreadyFoundVisibleButton = false;
+ int i = mButtonData.size() - 1;
+ for (; i >= 0; --i) {
+ final ButtonData buttonData = mButtonData.get(i);
+ if (!alreadyFoundVisibleButton && buttonData.markedVisible) {
+ buttonData.setVisibility(View.VISIBLE);
+ setVisibility(View.VISIBLE);
+ alreadyFoundVisibleButton = true;
+ } else {
+ buttonData.setVisibility(View.INVISIBLE);
+ }
+ }
+ return mButtonData.get(index).button.getVisibility();
+ }
+
+ /**
+ * See if button is group visible. Group visible determines if a button can be visible when
+ * higher priority buttons go invisible.
+ * @param buttonResId the button to see if it is group visible
+ * @return true if button is group visible
+ */
+ public boolean isButtonVisibleWithinGroup(@IdRes int buttonResId) {
+ final int index = getContextButtonIndex(buttonResId);
+ return index != INVALID_INDEX && mButtonData.get(index).markedVisible;
+ }
+
+ /**
+ * Update all the icons that are attached to this group. This will get all the buttons to update
+ * their icons for their buttons.
+ */
+ public void updateIcons() {
+ for (ButtonData data : mButtonData) {
+ data.button.updateIcon();
+ }
+ }
+
+ public void dump(PrintWriter pw) {
+ pw.println("ContextualButtonGroup {");
+ pw.println(" getVisibleContextButton(): " + getVisibleContextButton());
+ pw.println(" isVisible(): " + isVisible());
+ pw.println(" mButtonData [ ");
+ for (int i = mButtonData.size() - 1; i >= 0; --i) {
+ final ButtonData data = mButtonData.get(i);
+ pw.println(" " + i + ": markedVisible=" + data.markedVisible
+ + " visible=" + data.button.getVisibility()
+ + " alpha=" + data.button.getAlpha());
+ }
+ pw.println(" ]");
+ pw.println(" }");
+ }
+
+ private int getContextButtonIndex(@IdRes int buttonResId) {
+ for (int i = 0; i < mButtonData.size(); ++i) {
+ if (mButtonData.get(i).button.getId() == buttonResId) {
+ return i;
+ }
+ }
+ return INVALID_INDEX;
+ }
+
+ private final static class ButtonData {
+ ContextualButton button;
+ boolean markedVisible;
+
+ ButtonData(ContextualButton button) {
+ this.button = button;
+ this.markedVisible = false;
+ }
+
+ void setVisibility(int visiblity) {
+ button.setVisibility(visiblity);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index d89bcda..f667726 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -19,6 +19,7 @@
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON;
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK;
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON;
@@ -171,7 +172,6 @@
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
private boolean mDozing;
private int mIndicationBottomMargin;
- private int mIndicationBottomMarginAmbient;
private float mDarkAmount;
private int mBurnInXOffset;
private int mBurnInYOffset;
@@ -246,10 +246,8 @@
mIndicationText = findViewById(R.id.keyguard_indication_text);
mIndicationBottomMargin = getResources().getDimensionPixelSize(
R.dimen.keyguard_indication_margin_bottom);
- mIndicationBottomMarginAmbient = getResources().getDimensionPixelSize(
- R.dimen.keyguard_indication_margin_bottom_ambient);
mBurnInYOffset = getResources().getDimensionPixelSize(
- R.dimen.charging_indication_burn_in_prevention_offset_y);
+ R.dimen.default_burn_in_prevention_offset);
updateCameraVisibility();
mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
mUnlockMethodCache.addListener(this);
@@ -320,10 +318,8 @@
super.onConfigurationChanged(newConfig);
mIndicationBottomMargin = getResources().getDimensionPixelSize(
R.dimen.keyguard_indication_margin_bottom);
- mIndicationBottomMarginAmbient = getResources().getDimensionPixelSize(
- R.dimen.keyguard_indication_margin_bottom_ambient);
mBurnInYOffset = getResources().getDimensionPixelSize(
- R.dimen.charging_indication_burn_in_prevention_offset_y);
+ R.dimen.default_burn_in_prevention_offset);
MarginLayoutParams mlp = (MarginLayoutParams) mIndicationArea.getLayoutParams();
if (mlp.bottomMargin != mIndicationBottomMargin) {
mlp.bottomMargin = mIndicationBottomMargin;
@@ -567,9 +563,7 @@
return;
}
mDarkAmount = darkAmount;
- mIndicationArea.setAlpha(MathUtils.lerp(1f, 0.7f, darkAmount));
- mIndicationArea.setTranslationY(MathUtils.lerp(0,
- mIndicationBottomMargin - mIndicationBottomMarginAmbient, darkAmount));
+ mIndicationArea.setAlpha(1f - darkAmount);
}
private static boolean isSuccessfulLaunch(int result) {
@@ -842,10 +836,10 @@
public void dozeTimeTick() {
if (mDarkAmount == 1) {
- // Move indication every minute to avoid burn-in
- int dozeTranslation = mIndicationBottomMargin - mIndicationBottomMarginAmbient;
- int burnInYOffset = (int) (-mBurnInYOffset + Math.random() * mBurnInYOffset * 2);
- mIndicationArea.setTranslationY(dozeTranslation + burnInYOffset);
+ // Move views every minute to avoid burn-in
+ int burnInYOffset = getBurnInOffset(mBurnInYOffset * 2, false /* xAxis */)
+ - mBurnInYOffset;
+ mLockIcon.setTranslationY(burnInYOffset);
}
}
@@ -854,7 +848,7 @@
return;
}
mBurnInXOffset = burnInXOffset;
- mIndicationArea.setTranslationX(burnInXOffset);
+ mLockIcon.setTranslationX(burnInXOffset);
}
private class DefaultLeftButton implements IntentButton {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 042e4ff..33bc164 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
import static com.android.systemui.statusbar.notification.NotificationUtils.interpolate;
import android.content.res.Resources;
@@ -30,10 +31,6 @@
*/
public class KeyguardClockPositionAlgorithm {
- private static final long MILLIS_PER_MINUTES = 1000 * 60;
- private static final float BURN_IN_PREVENTION_PERIOD_Y = 521;
- private static final float BURN_IN_PREVENTION_PERIOD_X = 83;
-
/**
* How much the clock height influences the shade position.
* 0 means nothing, 1 means move the shade up by the height of the clock
@@ -228,34 +225,15 @@
}
private float burnInPreventionOffsetY() {
- return zigzag(System.currentTimeMillis() / MILLIS_PER_MINUTES,
- mBurnInPreventionOffsetY * 2,
- BURN_IN_PREVENTION_PERIOD_Y)
+ return getBurnInOffset(mBurnInPreventionOffsetY * 2, false /* xAxis */)
- mBurnInPreventionOffsetY;
}
private float burnInPreventionOffsetX() {
- return zigzag(System.currentTimeMillis() / MILLIS_PER_MINUTES,
- mBurnInPreventionOffsetX * 2,
- BURN_IN_PREVENTION_PERIOD_X)
+ return getBurnInOffset(mBurnInPreventionOffsetX * 2, true /* xAxis */)
- mBurnInPreventionOffsetX;
}
- /**
- * Implements a continuous, piecewise linear, periodic zig-zag function
- *
- * Can be thought of as a linear approximation of abs(sin(x)))
- *
- * @param period period of the function, ie. zigzag(x + period) == zigzag(x)
- * @param amplitude maximum value of the function
- * @return a value between 0 and amplitude
- */
- private float zigzag(float x, float amplitude, float period) {
- float xprime = (x % period) / (period / 2);
- float interpolationAmount = (xprime <= 1) ? xprime : (2 - xprime);
- return interpolate(0, amplitude, interpolationAmount);
- }
-
public static class Result {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 5630da6..7c84df9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone;
import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
+import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
import android.annotation.ColorInt;
import android.content.Context;
@@ -70,16 +71,18 @@
private static final int LAYOUT_CUTOUT = 1;
private static final int LAYOUT_NO_CUTOUT = 2;
+ private final Rect mEmptyRect = new Rect(0, 0, 0, 0);
+
private boolean mShowPercentAvailable;
private boolean mBatteryCharging;
private boolean mKeyguardUserSwitcherShowing;
private boolean mBatteryListening;
private TextView mCarrierLabel;
- private View mSystemIconsSuperContainer;
private MultiUserSwitch mMultiUserSwitch;
private ImageView mMultiUserAvatar;
private BatteryMeterView mBatteryView;
+ private StatusIconContainer mStatusIconContainer;
private BatteryController mBatteryController;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
@@ -99,6 +102,18 @@
*/
private int mCutoutSideNudge = 0;
+ /**
+ * How much to move icons to avoid burn in.
+ */
+ private int mBurnInOffset;
+ private int mCurrentBurnInOffsetX;
+ private int mCurrentBurnInOffsetY;
+
+ /**
+ * Ratio representing being in ambient mode or not.
+ */
+ private float mDarkAmount;
+
public KeyguardStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -113,6 +128,7 @@
mBatteryView = mSystemIconsContainer.findViewById(R.id.battery);
mCutoutSpace = findViewById(R.id.cutout_space_view);
mStatusIconArea = findViewById(R.id.status_icon_area);
+ mStatusIconContainer = findViewById(R.id.statusIcons);
loadDimens();
updateUserSwitcher();
@@ -169,6 +185,8 @@
R.dimen.system_icons_super_container_avatarless_margin_end);
mCutoutSideNudge = getResources().getDimensionPixelSize(
R.dimen.display_cutout_margin_consumption);
+ mBurnInOffset = getResources().getDimensionPixelSize(
+ R.dimen.default_burn_in_prevention_offset);
mShowPercentAvailable = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_battery_percentage_setting_available);
}
@@ -440,6 +458,14 @@
}
public void onThemeChanged() {
+ mBatteryView.setColorsFromContext(mContext);
+ updateIconsAndTextColors();
+ // Reload user avatar
+ ((UserInfoControllerImpl) Dependency.get(UserInfoController.class))
+ .onDensityOrFontScaleChanged();
+ }
+
+ private void updateIconsAndTextColors() {
@ColorInt int textColor = Utils.getColorAttrDefaultColor(mContext,
R.attr.wallpaperTextColor);
@ColorInt int iconColor = Utils.getColorStateListDefaultColor(mContext,
@@ -448,14 +474,9 @@
float intensity = textColor == Color.WHITE ? 0 : 1;
mCarrierLabel.setTextColor(iconColor);
mIconManager.setTint(iconColor);
- mBatteryView.setColorsFromContext(mContext);
- Rect tintArea = new Rect(0, 0, 0, 0);
- applyDarkness(R.id.battery, tintArea, intensity, iconColor);
- applyDarkness(R.id.clock, tintArea, intensity, iconColor);
- // Reload user avatar
- ((UserInfoControllerImpl) Dependency.get(UserInfoController.class))
- .onDensityOrFontScaleChanged();
+ applyDarkness(R.id.battery, mEmptyRect, intensity * (1f - mDarkAmount), iconColor);
+ applyDarkness(R.id.clock, mEmptyRect, intensity, iconColor);
}
private void applyDarkness(int id, Rect tintArea, float intensity, int color) {
@@ -475,4 +496,32 @@
mBatteryView.dump(fd, pw, args);
}
}
+
+ public void setDarkAmount(float darkAmount) {
+ mDarkAmount = darkAmount;
+ if (darkAmount == 0) {
+ dozeTimeTick();
+ }
+ updateDozeState();
+ }
+
+ public void dozeTimeTick() {
+ mCurrentBurnInOffsetX = getBurnInOffset(mBurnInOffset, true /* xAxis */);
+ mCurrentBurnInOffsetY = getBurnInOffset(mBurnInOffset, false /* xAxis */);
+ updateDozeState();
+ }
+
+ private void updateDozeState() {
+ float alpha = 1f - mDarkAmount;
+ int visibility = alpha != 0f ? VISIBLE : INVISIBLE;
+ mCarrierLabel.setAlpha(alpha);
+ mCarrierLabel.setVisibility(visibility);
+ mStatusIconContainer.setAlpha(alpha);
+ mStatusIconContainer.setVisibility(visibility);
+
+ mSystemIconsContainer.setTranslationX(-mCurrentBurnInOffsetX * mDarkAmount);
+ mSystemIconsContainer.setTranslationY(mCurrentBurnInOffsetY * mDarkAmount);
+ updateIconsAndTextColors();
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 66486ce..cbbb0e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -463,7 +463,7 @@
style = rotationCCW ? R.style.RotateButtonCCWStart0 :
R.style.RotateButtonCWStart0;
}
- mNavigationBarView.updateRotateSuggestionButtonStyle(style, true);
+ mNavigationBarView.updateRotateSuggestionButtonStyle(style);
}
if (mNavigationBarWindowState != WINDOW_STATE_SHOWING) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 9d13ea2..aebcb9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -36,8 +36,6 @@
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.drawable.AnimatedVectorDrawable;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -46,7 +44,6 @@
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
-import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.MotionEvent;
import android.view.Surface;
@@ -59,7 +56,6 @@
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
-import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.DockedStackExistsListener;
import com.android.systemui.Interpolators;
@@ -106,10 +102,7 @@
boolean mVertical;
private int mCurrentRotation = -1;
- boolean mShowMenu;
- boolean mShowAccessibilityButton;
boolean mLongClickableAccessibilityButton;
- boolean mShowRotateButton;
int mDisabledFlags = 0;
int mNavigationIconHints = 0;
@@ -125,10 +118,6 @@
private KeyButtonDrawable mHomeDefaultIcon;
private KeyButtonDrawable mRecentIcon;
private KeyButtonDrawable mDockedIcon;
- private KeyButtonDrawable mImeIcon;
- private KeyButtonDrawable mMenuIcon;
- private KeyButtonDrawable mAccessibilityIcon;
- private KeyButtonDrawable mRotateSuggestionIcon;
private GestureHelper mGestureHelper;
private final DeadZone mDeadZone;
@@ -151,6 +140,7 @@
private boolean mDockedStackExists;
private final SparseArray<ButtonDispatcher> mButtonDispatchers = new SparseArray<>();
+ private final ContextualButtonGroup mContextualButtonGroup;
private Configuration mConfiguration;
private NavigationBarInflaterView mNavigationInflaterView;
@@ -159,8 +149,6 @@
private RecentsOnboarding mRecentsOnboarding;
private NotificationPanelView mPanelView;
- private int mRotateBtnStyle = R.style.RotateButtonCCWStart90;
-
/**
* Helper that is responsible for showing the right toast when a disallowed activity operation
* occurred. In pinned mode, we show instructions on how to break out of this mode, whilst in
@@ -279,17 +267,30 @@
Context.WINDOW_SERVICE)).getDefaultDisplay();
mVertical = false;
- mShowMenu = false;
-
- mShowAccessibilityButton = false;
mLongClickableAccessibilityButton = false;
+ // Set up the context group of buttons
+ mContextualButtonGroup = new ContextualButtonGroup(R.id.menu_container);
+ final ContextualButton menuButton = new ContextualButton(R.id.menu,
+ R.drawable.ic_sysbar_menu);
+ final ContextualButton imeSwitcherButton = new ContextualButton(R.id.ime_switcher,
+ R.drawable.ic_ime_switcher_default);
+ final RotationContextButton rotateSuggestionButton = new RotationContextButton(
+ R.id.rotate_suggestion, R.drawable.ic_sysbar_rotate_button,
+ R.style.RotateButtonCCWStart90);
+ final ContextualButton accessibilityButton =
+ new ContextualButton(R.id.accessibility_button,
+ R.drawable.ic_sysbar_accessibility_button);
+ mContextualButtonGroup.addButton(menuButton);
+ mContextualButtonGroup.addButton(imeSwitcherButton);
+ mContextualButtonGroup.addButton(rotateSuggestionButton);
+ mContextualButtonGroup.addButton(accessibilityButton);
+
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
mConfiguration = new Configuration();
mConfiguration.updateFrom(context.getResources().getConfiguration());
- reloadNavIcons();
mScreenPinningNotify = new ScreenPinningNotify(mContext);
mBarTransitions = new NavigationBarTransitions(this);
@@ -297,14 +298,11 @@
mButtonDispatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
mButtonDispatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
- mButtonDispatchers.put(R.id.menu, new ButtonDispatcher(R.id.menu));
- mButtonDispatchers.put(R.id.ime_switcher, new ButtonDispatcher(R.id.ime_switcher));
- mButtonDispatchers.put(R.id.accessibility_button,
- new ButtonDispatcher(R.id.accessibility_button));
- mButtonDispatchers.put(R.id.rotate_suggestion,
- new ButtonDispatcher(R.id.rotate_suggestion));
- mButtonDispatchers.put(R.id.menu_container,
- new ButtonDispatcher(R.id.menu_container));
+ mButtonDispatchers.put(R.id.menu, menuButton);
+ mButtonDispatchers.put(R.id.ime_switcher, imeSwitcherButton);
+ mButtonDispatchers.put(R.id.accessibility_button, accessibilityButton);
+ mButtonDispatchers.put(R.id.rotate_suggestion, rotateSuggestionButton);
+ mButtonDispatchers.put(R.id.menu_container, mContextualButtonGroup);
mDeadZone = new DeadZone(this);
}
@@ -432,10 +430,6 @@
return mButtonDispatchers.get(R.id.rotate_suggestion);
}
- public ButtonDispatcher getMenuContainer() {
- return mButtonDispatchers.get(R.id.menu_container);
- }
-
public SparseArray<ButtonDispatcher> getButtonDispatchers() {
return mButtonDispatchers;
}
@@ -473,14 +467,7 @@
}
if (densityChange || dirChange) {
mRecentIcon = getDrawable(R.drawable.ic_sysbar_recent);
- mMenuIcon = getDrawable(R.drawable.ic_sysbar_menu);
-
- mAccessibilityIcon = getDrawable(R.drawable.ic_sysbar_accessibility_button,
- false /* hasShadow */);
-
- mImeIcon = getDrawable(R.drawable.ic_ime_switcher_default, false /* hasShadow */);
-
- updateRotateSuggestionButtonStyle(mRotateBtnStyle, false);
+ mContextualButtonGroup.updateIcons();
}
if (orientationChange || densityChange || dirChange) {
mBackIcon = getBackDrawable();
@@ -538,19 +525,11 @@
}
private KeyButtonDrawable getDrawable(@DrawableRes int icon) {
- return getDrawable(mContext, icon, true /* hasShadow */);
+ return KeyButtonDrawable.create(mContext, icon, true /* hasShadow */);
}
private KeyButtonDrawable getDrawable(@DrawableRes int icon, boolean hasShadow) {
- return getDrawable(mContext, icon, hasShadow);
- }
-
- private KeyButtonDrawable getDrawable(Context ctx, @DrawableRes int icon, boolean hasShadow) {
- final int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme);
- final int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme);
- Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme);
- Context darkContext = new ContextThemeWrapper(ctx, dualToneDarkTheme);
- return KeyButtonDrawable.create(lightContext, darkContext, icon, hasShadow);
+ return KeyButtonDrawable.create(mContext, icon, hasShadow);
}
@Override
@@ -609,24 +588,8 @@
updateRecentsIcon();
// Update IME button visibility, a11y and rotate button always overrides the appearance
- final boolean showImeButton =
- !mShowAccessibilityButton &&
- !mShowRotateButton &&
- ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
- getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE);
- getImeSwitchButton().setImageDrawable(mImeIcon);
- updateContextualContainerVisibility();
-
- // Update menu button, visibility logic in method
- setMenuVisibility(mShowMenu, true);
- getMenuButton().setImageDrawable(mMenuIcon);
-
- // Update rotate button, visibility altered by a11y button logic
- getRotateSuggestionButton().setImageDrawable(mRotateSuggestionIcon);
-
- // Update a11y button, visibility logic in state method
- setAccessibilityButtonState(mShowAccessibilityButton, mLongClickableAccessibilityButton);
- getAccessibilityButton().setImageDrawable(mAccessibilityIcon);
+ mContextualButtonGroup.setButtonVisiblity(R.id.ime_switcher,
+ (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
mBarTransitions.reapplyDarkIntensity();
@@ -782,88 +745,28 @@
}
public void setMenuVisibility(final boolean show) {
- setMenuVisibility(show, false);
+ mContextualButtonGroup.setButtonVisiblity(R.id.menu, show);
}
- public void setMenuVisibility(final boolean show, final boolean force) {
- if (!force && mShowMenu == show) return;
-
- mShowMenu = show;
-
- // Only show Menu if IME switcher, rotate and Accessibility buttons are not shown.
- final boolean shouldShow = mShowMenu &&
- !mShowAccessibilityButton &&
- !mShowRotateButton &&
- ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0);
-
- getMenuButton().setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
- updateContextualContainerVisibility();
+ public void updateRotateSuggestionButtonStyle(@StyleRes int style) {
+ RotationContextButton button = (RotationContextButton) mContextualButtonGroup
+ .getContextButton(R.id.rotate_suggestion);
+ button.setStyle(style);
+ button.updateIcon();
}
public void setAccessibilityButtonState(final boolean visible, final boolean longClickable) {
- mShowAccessibilityButton = visible;
mLongClickableAccessibilityButton = longClickable;
- if (visible) {
- // Accessibility button overrides Menu, IME switcher and rotate buttons.
- setMenuVisibility(false, true);
- getImeSwitchButton().setVisibility(View.INVISIBLE);
- setRotateButtonVisibility(false);
- }
-
- getAccessibilityButton().setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
getAccessibilityButton().setLongClickable(longClickable);
- updateContextualContainerVisibility();
- }
-
- public void updateRotateSuggestionButtonStyle(@StyleRes int style, boolean setIcon) {
- mRotateBtnStyle = style;
- final Context ctx = getContext();
-
- // Use the supplied style to set the icon's rotation parameters
- Context rotateContext = new ContextThemeWrapper(ctx, style);
-
- // Recreate the icon and set it if needed
- float previousIntensity = mRotateSuggestionIcon != null
- ? mRotateSuggestionIcon.getDarkIntensity() : 0;
- mRotateSuggestionIcon = getDrawable(rotateContext, R.drawable.ic_sysbar_rotate_button,
- false /* hasShadow */);
- mRotateSuggestionIcon.setDarkIntensity(previousIntensity);
-
- if (setIcon) getRotateSuggestionButton().setImageDrawable(mRotateSuggestionIcon);
+ mContextualButtonGroup.setButtonVisiblity(R.id.accessibility_button, visible);
}
public int setRotateButtonVisibility(boolean visible) {
- // Never show if a11y is visible
- final boolean adjVisible = visible && !mShowAccessibilityButton;
- final int vis = adjVisible ? View.VISIBLE : View.INVISIBLE;
-
- // No need to do anything if the request matches the current state
- if (vis == getRotateSuggestionButton().getVisibility()) return vis;
-
- getRotateSuggestionButton().setVisibility(vis);
- mShowRotateButton = visible;
- updateContextualContainerVisibility();
-
- // Stop any active animations if hidden
- if (!visible && mRotateSuggestionIcon.canAnimate()) {
- mRotateSuggestionIcon.clearAnimationCallbacks();
- mRotateSuggestionIcon.resetAnimation();
- }
-
- // Hide/restore other button visibility, if necessary
- updateNavButtonIcons();
-
- // Return applied visibility
- return vis;
+ return mContextualButtonGroup.setButtonVisiblity(R.id.rotate_suggestion, visible);
}
- public boolean isRotateButtonVisible() { return mShowRotateButton; }
-
- private void updateContextualContainerVisibility() {
- // Only show the menu container when one of its buttons are visible
- getMenuContainer().setVisibility((mShowAccessibilityButton || mShowRotateButton || mShowMenu
- || (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0)
- ? VISIBLE : INVISIBLE);
+ public boolean isRotateButtonVisible() {
+ return getRotateSuggestionButton().isVisible();
}
void hideRecentsOnboarding() {
@@ -897,6 +800,7 @@
DockedStackExistsListener.register(mDockedListener);
updateRotatedViews();
+ reloadNavIcons();
}
public void onDarkIntensityChange(float intensity) {
@@ -998,7 +902,6 @@
// force the low profile & disabled states into compliance
mBarTransitions.init();
- setMenuVisibility(mShowMenu, true /* force */);
if (DEBUG) {
Log.d(TAG, "reorient(): rot=" + mCurrentRotation);
@@ -1204,17 +1107,19 @@
pw.println(String.format(" disabled=0x%08x vertical=%s menu=%s",
mDisabledFlags,
mVertical ? "true" : "false",
- mShowMenu ? "true" : "false"));
+ getMenuButton().isVisible() ? "true" : "false"));
dumpButton(pw, "back", getBackButton());
dumpButton(pw, "home", getHomeButton());
dumpButton(pw, "rcnt", getRecentsButton());
dumpButton(pw, "menu", getMenuButton());
+ dumpButton(pw, "rota", getRotateSuggestionButton());
dumpButton(pw, "a11y", getAccessibilityButton());
- mRecentsOnboarding.dump(pw);
-
pw.println(" }");
+
+ mContextualButtonGroup.dump(pw);
+ mRecentsOnboarding.dump(pw);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index e5e5d40..3a4c218 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -63,6 +63,7 @@
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.qs.QSFragment;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyguardAffordanceView;
@@ -455,6 +456,10 @@
initBottomArea();
setDarkAmount(mLinearDarkAmount, mInterpolatedDarkAmount);
+ if (mKeyguardStatusBar != null) {
+ mKeyguardStatusBar.onThemeChanged();
+ }
+
setKeyguardStatusViewVisibility(mBarState, false, false);
setKeyguardBottomAreaVisibility(mBarState, false);
}
@@ -1836,10 +1841,10 @@
return;
}
float alphaQsExpansion = 1 - Math.min(1, getQsExpansionFraction() * 2);
- mKeyguardStatusBar.setAlpha(Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
- * mKeyguardStatusBarAnimateAlpha);
- mKeyguardStatusBar.setVisibility(mKeyguardStatusBar.getAlpha() != 0f
- && !mDozing ? VISIBLE : INVISIBLE);
+ float newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
+ * mKeyguardStatusBarAnimateAlpha;
+ mKeyguardStatusBar.setAlpha(newAlpha);
+ mKeyguardStatusBar.setVisibility(newAlpha != 0f ? VISIBLE : INVISIBLE);
}
private void updateKeyguardBottomAreaAlpha() {
@@ -2347,16 +2352,7 @@
}
private void updateDozingVisibilities(boolean animate) {
- if (mDozing) {
- mKeyguardStatusBar.setVisibility(View.INVISIBLE);
- mKeyguardBottomArea.setDozing(mDozing, animate);
- } else {
- mKeyguardStatusBar.setVisibility(View.VISIBLE);
- mKeyguardBottomArea.setDozing(mDozing, animate);
- if (animate) {
- animateKeyguardStatusBarIn(DOZE_ANIMATION_DURATION);
- }
- }
+ mKeyguardBottomArea.setDozing(mDozing, animate);
}
@Override
@@ -2749,6 +2745,9 @@
}
});
mNotificationStackScroller.setQsContainer((ViewGroup) mQs.getView());
+ if (mQs instanceof QSFragment) {
+ mKeyguardStatusBar.setQSPanel(((QSFragment) mQs).getQsPanel());
+ }
updateQsExpansion();
}
@@ -2811,6 +2810,7 @@
private void setDarkAmount(float linearAmount, float amount) {
mInterpolatedDarkAmount = amount;
mLinearDarkAmount = linearAmount;
+ mKeyguardStatusBar.setDarkAmount(mInterpolatedDarkAmount);
mKeyguardStatusView.setDarkAmount(mInterpolatedDarkAmount);
mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount);
positionClockAndNotifications();
@@ -2837,6 +2837,7 @@
}
public void dozeTimeTick() {
+ mKeyguardStatusBar.dozeTimeTick();
mKeyguardStatusView.dozeTimeTick();
mKeyguardBottomArea.dozeTimeTick();
if (mInterpolatedDarkAmount > 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index a900c14..1afdc66b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -595,16 +595,29 @@
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
mContext.getString(R.string.instant_apps));
mCurrentNotifs.add(new Pair<>(pkg, userId));
- String message = mContext.getString(R.string.instant_apps_message);
+
+ String helpUrl = mContext.getString(R.string.instant_apps_help_url);
+ boolean hasHelpUrl = !helpUrl.isEmpty();
+ String message = mContext.getString(hasHelpUrl
+ ? R.string.instant_apps_message_with_help
+ : R.string.instant_apps_message);
+
UserHandle user = UserHandle.of(userId);
PendingIntent appInfoAction = PendingIntent.getActivityAsUser(mContext, 0,
new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
.setData(Uri.fromParts("package", pkg, null)), 0, null, user);
Action action = new Notification.Action.Builder(null, mContext.getString(R.string.app_info),
appInfoAction).build();
+ PendingIntent helpCenterIntent = hasHelpUrl
+ ? PendingIntent.getActivityAsUser(mContext, 0,
+ new Intent(Intent.ACTION_VIEW).setData(Uri.parse(
+ helpUrl)),
+ 0, null, user)
+ : null;
Intent browserIntent = getTaskIntent(taskId, userId);
- Notification.Builder builder = new Notification.Builder(mContext, NotificationChannels.GENERAL);
+ Notification.Builder builder = new Notification.Builder(mContext,
+ NotificationChannels.GENERAL);
if (browserIntent != null && browserIntent.isWebIntent()) {
// Make sure that this doesn't resolve back to an instant app
browserIntent.setComponent(null)
@@ -632,7 +645,8 @@
PendingIntent webPendingIntent = PendingIntent.getActivityAsUser(mContext, 0,
goToWebIntent, 0, null, user);
- Action webAction = new Notification.Action.Builder(null, mContext.getString(R.string.go_to_web),
+ Action webAction = new Notification.Action.Builder(null,
+ mContext.getString(R.string.go_to_web),
webPendingIntent).build();
builder.addAction(webAction);
}
@@ -640,13 +654,15 @@
noMan.notifyAsUser(pkg, SystemMessage.NOTE_INSTANT_APPS, builder
.addExtras(extras)
.addAction(action)
- .setContentIntent(appInfoAction)
+ .setContentIntent(helpCenterIntent)
.setColor(mContext.getColor(R.color.instant_apps_color))
- .setContentTitle(appInfo.loadLabel(mContext.getPackageManager()))
+ .setContentTitle(mContext.getString(R.string.instant_apps_title,
+ appInfo.loadLabel(mContext.getPackageManager())))
.setLargeIcon(Icon.createWithResource(pkg, appInfo.icon))
.setSmallIcon(Icon.createWithResource(mContext.getPackageName(),
R.drawable.instant_icon))
.setContentText(message)
+ .setStyle(new Notification.BigTextStyle().bigText(message))
.setOngoing(true)
.build(),
new UserHandle(userId));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
new file mode 100644
index 0000000..15e189c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
@@ -0,0 +1,61 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import android.annotation.DrawableRes;
+import android.annotation.IdRes;
+import android.annotation.NonNull;
+import android.annotation.StyleRes;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+import com.android.systemui.statusbar.policy.KeyButtonDrawable;
+import com.android.systemui.util.Utils;
+
+public class RotationContextButton extends ContextualButton {
+
+ private @StyleRes int mStyleRes;
+
+ public RotationContextButton(@IdRes int buttonResId, @DrawableRes int iconResId,
+ @StyleRes int style) {
+ super(buttonResId, iconResId);
+ mStyleRes = style;
+ }
+
+ public void setStyle(@StyleRes int styleRes) {
+ mStyleRes = styleRes;
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ super.setVisibility(visibility);
+
+ // Start the rotation animation once it becomes visible
+ final KeyButtonDrawable currentDrawable = getImageDrawable();
+ if (visibility == View.VISIBLE && currentDrawable != null) {
+ currentDrawable.resetAnimation();
+ currentDrawable.startAnimation();
+ }
+ }
+
+ @Override
+ protected KeyButtonDrawable getNewDrawable() {
+ Context context = new ContextThemeWrapper(getContext().getApplicationContext(), mStyleRes);
+ return KeyButtonDrawable.create(context, mIconResId, false /* shadow */);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index e1d8638..103781b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -381,8 +381,6 @@
// settings
private QSPanel mQSPanel;
- // top bar
- private KeyguardStatusBarView mKeyguardStatusBar;
KeyguardIndicationController mKeyguardIndicationController;
// RemoteInputView to be activated after unlock
@@ -805,7 +803,6 @@
mAboveShelfObserver = new AboveShelfObserver(mStackScroller);
mAboveShelfObserver.setListener(mStatusBarWindow.findViewById(
R.id.notification_container_parent));
- mKeyguardStatusBar = mStatusBarWindow.findViewById(R.id.keyguard_header);
mNotificationIconAreaController = SystemUIFactory.getInstance()
.createNotificationIconAreaController(context, this);
@@ -980,7 +977,6 @@
((QSFragment) qs).setHost(qsh);
mQSPanel = ((QSFragment) qs).getQsPanel();
mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
- mKeyguardStatusBar.setQSPanel(mQSPanel);
}
});
}
@@ -1118,8 +1114,6 @@
@Override
public void onThemeChanged() {
- // The status bar on the keyguard is a special layout.
- if (mKeyguardStatusBar != null) mKeyguardStatusBar.onThemeChanged();
// Recreate Indication controller because internal references changed
mKeyguardIndicationController =
SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
@@ -1154,7 +1148,8 @@
protected void createUserSwitcher() {
mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
- mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mKeyguardStatusBar,
+ mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
+ mStatusBarWindow.findViewById(R.id.keyguard_header),
mNotificationPanel);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
index 945d9b9..2340786 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
@@ -19,6 +19,7 @@
import android.animation.ArgbEvaluator;
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -35,6 +36,7 @@
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.util.FloatProperty;
+import android.view.ContextThemeWrapper;
import com.android.settingslib.Utils;
import com.android.systemui.R;
@@ -388,6 +390,23 @@
}
}
+ /**
+ * Creates a KeyButtonDrawable with a shadow given its icon. The tint applied to the drawable
+ * is determined by the dark and light theme given by the context.
+ * @param ctx Context to get the drawable and determine the dark and light theme
+ * @param icon the icon resource id
+ * @param hasShadow if a shadow will appear with the drawable
+ * @return KeyButtonDrawable
+ */
+ public static KeyButtonDrawable create(@NonNull Context ctx, @DrawableRes int icon,
+ boolean hasShadow) {
+ final int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme);
+ final int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme);
+ Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme);
+ Context darkContext = new ContextThemeWrapper(ctx, dualToneDarkTheme);
+ return KeyButtonDrawable.create(lightContext, darkContext, icon, hasShadow);
+ }
+
public static KeyButtonDrawable create(Context lightContext, Context darkContext,
@DrawableRes int iconResId, boolean hasShadow) {
return create(lightContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
index 04441ab..19974f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
@@ -64,6 +64,7 @@
@RunWith(AndroidJUnit4.class)
public class PluginInstanceManagerTest extends SysuiTestCase {
+ private static final String WHITELISTED_PACKAGE = "com.android.systemui";
// Static since the plugin needs to be generated by the PluginInstanceManager using newInstance.
private static Plugin sMockPlugin;
@@ -88,7 +89,7 @@
mMockVersionInfo = mock(VersionInfo.class);
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
- mMockManager, true);
+ mMockManager, true, new String[0]);
sMockPlugin = mock(Plugin.class);
when(sMockPlugin.getVersion()).thenReturn(1);
}
@@ -186,7 +187,7 @@
// Create a version that thinks the build is not debuggable.
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
- mMockManager, false);
+ mMockManager, false, new String[0]);
setupFakePmQuery();
mPluginInstanceManager.loadAll();
@@ -199,6 +200,25 @@
}
@Test
+ public void testNonDebuggable_whitelist() throws Exception {
+ // Create a version that thinks the build is not debuggable.
+ mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
+ mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
+ mMockManager, false, new String[] {WHITELISTED_PACKAGE});
+ setupFakePmQuery();
+
+ mPluginInstanceManager.loadAll();
+
+ waitForIdleSync(mPluginInstanceManager.mPluginHandler);
+ waitForIdleSync(mPluginInstanceManager.mMainHandler);
+
+ // Verify startup lifecycle
+ verify(sMockPlugin).onCreate(ArgumentCaptor.forClass(Context.class).capture(),
+ ArgumentCaptor.forClass(Context.class).capture());
+ verify(mMockListener).onPluginConnected(any(), any());
+ }
+
+ @Test
public void testCheckAndDisable() throws Exception {
createPlugin(); // Get into valid created state.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
index 94dbc2a..438f9e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
@@ -13,8 +13,9 @@
*/
package com.android.systemui.plugins;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertSame;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -26,8 +27,6 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -36,11 +35,10 @@
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.annotations.ProvidesInterface;
import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
import com.android.systemui.plugins.PluginManagerImpl.PluginInstanceManagerFactory;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -54,6 +52,8 @@
@RunWithLooper
public class PluginManagerTest extends SysuiTestCase {
+ private static final String WHITELISTED_PACKAGE = "com.android.systemui";
+
private PluginInstanceManagerFactory mMockFactory;
private PluginInstanceManager mMockPluginInstance;
private PluginManagerImpl mPluginManager;
@@ -74,7 +74,7 @@
when(mMockFactory.createPluginInstanceManager(Mockito.any(), Mockito.any(), Mockito.any(),
Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.any()))
.thenReturn(mMockPluginInstance);
- mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, true,
+ mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, true, new String[0],
mMockExceptionHandler);
resetExceptionHandler();
mMockListener = mock(PluginListener.class);
@@ -87,7 +87,7 @@
when(mMockPluginInstance.getPlugin()).thenReturn(new PluginInfo(null, null, mockPlugin,
null, null));
Plugin result = mPluginManager.getOneShotPlugin("myAction", TestPlugin.class);
- assertTrue(result == mockPlugin);
+ assertSame(mockPlugin, result);
}
@Test
@@ -106,16 +106,27 @@
}
@Test
- public void testNonDebuggable() {
+ @RunWithLooper(setAsMainLooper = true)
+ public void testNonDebuggable_noWhitelist() {
mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, false,
- mMockExceptionHandler);
+ new String[0], mMockExceptionHandler);
resetExceptionHandler();
mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
- verify(mMockPluginInstance, Mockito.never()).loadAll();
-
assertNull(mPluginManager.getOneShotPlugin("myPlugin", TestPlugin.class));
- verify(mMockPluginInstance, Mockito.never()).getPlugin();
+ assertNull(mPluginManager.getClassLoader("myPlugin", WHITELISTED_PACKAGE));
+ }
+
+ @Test
+ @RunWithLooper(setAsMainLooper = true)
+ public void testNonDebuggable_whitelistedPkg() {
+ mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, false,
+ new String[] {WHITELISTED_PACKAGE}, mMockExceptionHandler);
+ resetExceptionHandler();
+
+ mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
+ assertNotNull(mPluginManager.getClassLoader("myPlugin", WHITELISTED_PACKAGE));
+ assertNull(mPluginManager.getClassLoader("myPlugin", "com.android.invalidpackage"));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
index 06265e5..18dd1fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
@@ -15,10 +15,15 @@
package com.android.systemui.statusbar.notification.row;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.doNothing;
import android.app.Notification;
import android.service.notification.StatusBarNotification;
@@ -27,7 +32,6 @@
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.testing.ViewUtils;
-import android.testing.ViewUtils;
import android.view.ViewGroup;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -36,6 +40,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mockito;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
@@ -72,6 +77,7 @@
row.resetMenu();
}
+
@Test
public void testNoAppOpsInSlowSwipe() {
NotificationMenuRow row = new NotificationMenuRow(mContext);
@@ -86,4 +92,255 @@
// one for snooze and one for noti blocking
assertEquals(2, container.getChildCount());
}
+
+ @Test
+ public void testIsSnappedAndOnSameSide() {
+ NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+
+ when(row.isMenuVisible()).thenReturn(true);
+ when(row.isMenuSnapped()).thenReturn(true);
+ when(row.isMenuOnLeft()).thenReturn(true);
+ when(row.isMenuSnappedOnLeft()).thenReturn(true);
+
+ assertTrue("Showing on left and on left", row.isSnappedAndOnSameSide());
+
+
+ when(row.isMenuOnLeft()).thenReturn(false);
+ when(row.isMenuSnappedOnLeft()).thenReturn(false);
+ assertTrue("Snapped to right and on right", row.isSnappedAndOnSameSide());
+
+ when(row.isMenuOnLeft()).thenReturn(true);
+ when(row.isMenuSnapped()).thenReturn(false);
+ assertFalse("Snapped to right and on left", row.isSnappedAndOnSameSide());
+
+ when(row.isMenuOnLeft()).thenReturn(true);
+ when(row.isMenuSnappedOnLeft()).thenReturn(true);
+ when(row.isMenuVisible()).thenReturn(false);
+ assertFalse("Snapped to left and on left, but menu not visible",
+ row.isSnappedAndOnSameSide());
+
+ when(row.isMenuVisible()).thenReturn(true);
+ when(row.isMenuSnapped()).thenReturn(false);
+ assertFalse("Snapped to left and on left, but not actually snapped to",
+ row.isSnappedAndOnSameSide());
+ }
+
+ @Test
+ public void testGetMenuSnapTarget() {
+ NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+ when(row.isMenuOnLeft()).thenReturn(true);
+ doReturn(30).when(row).getSpaceForMenu();
+
+ assertEquals("When on left, snap target is space for menu",
+ 30, row.getMenuSnapTarget());
+
+ when(row.isMenuOnLeft()).thenReturn(false);
+ assertEquals("When on right, snap target is negative space for menu",
+ -30, row.getMenuSnapTarget());
+ }
+
+ @Test
+ public void testIsSwipedEnoughToShowMenu() {
+ NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+ when(row.isMenuVisible()).thenReturn(true);
+ when(row.isMenuOnLeft()).thenReturn(true);
+ doReturn(40f).when(row).getMinimumSwipeDistance();
+
+ when(row.getTranslation()).thenReturn(30f);
+ assertFalse("on left, translation is less than min", row.isSwipedEnoughToShowMenu());
+
+ when(row.getTranslation()).thenReturn(50f);
+ assertTrue("on left, translation is greater than min", row.isSwipedEnoughToShowMenu());
+
+ when(row.isMenuOnLeft()).thenReturn(false);
+ when(row.getTranslation()).thenReturn(-30f);
+ assertFalse("on right, translation is greater than -min", row.isSwipedEnoughToShowMenu());
+
+ when(row.getTranslation()).thenReturn(-50f);
+ assertTrue("on right, translation is less than -min", row.isSwipedEnoughToShowMenu());
+
+ when(row.isMenuVisible()).thenReturn(false);
+ when(row.getTranslation()).thenReturn(30f);
+ assertFalse("on left, translation greater than min, but not visible",
+ row.isSwipedEnoughToShowMenu());
+ }
+
+ @Test
+ public void testIsWithinSnapMenuThreshold() {
+ NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+ doReturn(30f).when(row).getSnapBackThreshold();
+ doReturn(50f).when(row).getDismissThreshold();
+
+ when(row.isMenuOnLeft()).thenReturn(true);
+ when(row.getTranslation()).thenReturn(40f);
+ assertTrue("When on left, translation is between min and max",
+ row.isWithinSnapMenuThreshold());
+
+ when(row.getTranslation()).thenReturn(20f);
+ assertFalse("When on left, translation is less than min",
+ row.isWithinSnapMenuThreshold());
+
+ when(row.getTranslation()).thenReturn(60f);
+ assertFalse("When on left, translation is greater than max",
+ row.isWithinSnapMenuThreshold());
+
+ when(row.isMenuOnLeft()).thenReturn(false);
+ when(row.getTranslation()).thenReturn(-40f);
+ assertTrue("When on right, translation is between -min and -max",
+ row.isWithinSnapMenuThreshold());
+
+ when(row.getTranslation()).thenReturn(-20f);
+ assertFalse("When on right, translation is greater than -min",
+ row.isWithinSnapMenuThreshold());
+
+ when(row.getTranslation()).thenReturn(-60f);
+ assertFalse("When on right, translation is less than -max",
+ row.isWithinSnapMenuThreshold());
+ }
+
+ @Test
+ public void testShouldSnapBack() {
+ NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+ doReturn(40f).when(row).getSnapBackThreshold();
+ when(row.isMenuVisible()).thenReturn(false);
+ when(row.isMenuOnLeft()).thenReturn(true);
+
+ when(row.getTranslation()).thenReturn(50f);
+ assertFalse("On left, translation greater than minimum target", row.shouldSnapBack());
+
+ when(row.getTranslation()).thenReturn(30f);
+ assertTrue("On left, translation less than minimum target", row.shouldSnapBack());
+
+ when(row.isMenuOnLeft()).thenReturn(false);
+ when(row.getTranslation()).thenReturn(-50f);
+ assertFalse("On right, translation less than minimum target", row.shouldSnapBack());
+
+ when(row.getTranslation()).thenReturn(-30f);
+ assertTrue("On right, translation greater than minimum target", row.shouldSnapBack());
+ }
+
+ @Test
+ public void testCanBeDismissed() {
+ NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+ ExpandableNotificationRow parent = mock(ExpandableNotificationRow.class);
+
+ when(row.getParent()).thenReturn(parent);
+ when(parent.canViewBeDismissed()).thenReturn(true);
+
+ assertTrue("Row can be dismissed if parent can be dismissed", row.canBeDismissed());
+
+ when(parent.canViewBeDismissed()).thenReturn(false);
+ assertFalse("Row cannot be dismissed if parent cannot be dismissed",
+ row.canBeDismissed());
+ }
+
+ @Test
+ public void testIsTowardsMenu() {
+ NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+ when(row.isMenuVisible()).thenReturn(true);
+ when(row.isMenuOnLeft()).thenReturn(true);
+
+ assertTrue("menu on left, movement is negative", row.isTowardsMenu(-30f));
+ assertFalse("menu on left, movement is positive", row.isTowardsMenu(30f));
+ assertTrue("menu on left, movement is 0", row.isTowardsMenu(0f));
+
+ when(row.isMenuOnLeft()).thenReturn(false);
+ assertTrue("menu on right, movement is positive", row.isTowardsMenu(30f));
+ assertFalse("menu on right, movement is negative", row.isTowardsMenu(-30f));
+ assertTrue("menu on right, movement is 0", row.isTowardsMenu(0f));
+
+ when(row.isMenuVisible()).thenReturn(false);
+ assertFalse("menu on left, movement is negative, but menu not visible",
+ row.isTowardsMenu(-30f));
+ }
+
+ @Test
+ public void onSnapBack() {
+ NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+ NotificationMenuRowPlugin.OnMenuEventListener listener = mock(NotificationMenuRowPlugin
+ .OnMenuEventListener.class);
+ row.setMenuClickListener(listener);
+ ExpandableNotificationRow parent = mock(ExpandableNotificationRow.class);
+ when(row.getParent()).thenReturn(parent);
+ doNothing().when(row).cancelDrag();
+
+ row.onSnapOpen();
+
+ assertTrue("before onSnapClosed, row is snapped to", row.isMenuSnapped());
+ assertFalse("before onSnapClosed, row is not snapping", row.isSnapping());
+
+ row.onSnapClosed();
+
+ assertFalse("after onSnapClosed, row is not snapped to", row.isMenuSnapped());
+ assertTrue("after onSnapClosed, row is snapping", row.isSnapping());
+ }
+
+ @Test
+ public void testOnSnap() {
+ NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+ when(row.isMenuOnLeft()).thenReturn(true);
+ NotificationMenuRowPlugin.OnMenuEventListener listener = mock(NotificationMenuRowPlugin
+ .OnMenuEventListener.class);
+ row.setMenuClickListener(listener);
+ ExpandableNotificationRow parent = mock(ExpandableNotificationRow.class);
+ when(row.getParent()).thenReturn(parent);
+
+ assertFalse("before onSnapOpen, row is not snapped to", row.isMenuSnapped());
+ assertFalse("before onSnapOpen, row is not snapped on left", row.isMenuSnappedOnLeft());
+
+ row.onSnapOpen();
+
+ assertTrue("after onSnapOpen, row is snapped to", row.isMenuSnapped());
+ assertTrue("after onSnapOpen, row is snapped on left", row.isMenuSnapped());
+ verify(listener, times(1)).onMenuShown(parent);
+ }
+
+ @Test
+ public void testOnDismiss() {
+ NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+ doNothing().when(row).cancelDrag();
+ row.onSnapOpen();
+
+ assertFalse("before onDismiss, row is not dismissing", row.isDismissing());
+ assertTrue("before onDismiss, row is showing", row.isMenuSnapped());
+
+ row.onDismiss();
+
+ verify(row, times(1)).cancelDrag();
+ assertTrue("after onDismiss, row is dismissing", row.isDismissing());
+ assertFalse("after onDismiss, row is not showing", row.isMenuSnapped());
+ }
+
+ @Test
+ public void testOnDown() {
+ NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+ doNothing().when(row).beginDrag();
+
+ row.onTouchStart();
+
+ verify(row, times(1)).beginDrag();
+ }
+
+ @Test
+ public void testOnUp() {
+ NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+ row.onTouchStart();
+
+ assertTrue("before onTouchEnd, isUserTouching is true", row.isUserTouching());
+
+ row.onTouchEnd();
+
+ assertFalse("after onTouchEnd, isUserTouching is false", row.isUserTouching());
+ }
+
+ @Test
+ public void testIsMenuVisible() {
+ NotificationMenuRow row = Mockito.spy(new NotificationMenuRow((mContext)));
+ row.setMenuAlpha(0);
+
+ assertFalse("when alpha is 0, menu is not visible", row.isMenuVisible());
+
+ row.setMenuAlpha(0.5f);
+ assertTrue("when alpha is .5, menu is visible", row.isMenuVisible());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
new file mode 100644
index 0000000..c792459
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
@@ -0,0 +1,199 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.doReturn;
+
+import android.graphics.drawable.Drawable;
+import android.support.test.filters.SmallTest;
+import android.view.View;
+import com.android.systemui.statusbar.policy.KeyButtonDrawable;
+import com.android.systemui.SysuiTestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.support.test.runner.AndroidJUnit4;
+
+/** atest NavigationBarContextTest */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NavigationBarContextTest extends SysuiTestCase {
+ private static final int GROUP_ID = 1;
+ private static final int BUTTON_0_ID = GROUP_ID + 1;
+ private static final int BUTTON_1_ID = GROUP_ID + 2;
+ private static final int BUTTON_2_ID = GROUP_ID + 3;
+
+ private static final float TEST_DARK_INTENSITY = 0.6f;
+ private static final float DARK_INTENSITY_ERR = 0.0002f;
+ private static final int ICON_RES_ID = 1;
+
+ private ContextualButtonGroup mGroup;
+ private ContextualButton mBtn0;
+ private ContextualButton mBtn1;
+ private ContextualButton mBtn2;
+
+ @Before
+ public void setup() {
+ mGroup = new ContextualButtonGroup(GROUP_ID);
+ mBtn0 = new ContextualButton(BUTTON_0_ID, ICON_RES_ID);
+ mBtn1 = new ContextualButton(BUTTON_1_ID, ICON_RES_ID);
+ mBtn2 = new ContextualButton(BUTTON_2_ID, ICON_RES_ID);
+
+ // Order of adding buttons to group determines the priority, ascending priority order
+ mGroup.addButton(mBtn0);
+ mGroup.addButton(mBtn1);
+ mGroup.addButton(mBtn2);
+ }
+
+ @Test
+ public void testAddGetContextButtons() throws Exception {
+ assertEquals(mBtn0, mGroup.getContextButton(BUTTON_0_ID));
+ assertEquals(mBtn1, mGroup.getContextButton(BUTTON_1_ID));
+ assertEquals(mBtn2, mGroup.getContextButton(BUTTON_2_ID));
+ }
+
+ @Test
+ public void testSetButtonVisibility() throws Exception {
+ assertFalse("By default the group should be invisible.", mGroup.isVisible());
+
+ // Set button 1 to be visible, make sure it is the only visible button
+ showButton(mBtn1);
+ assertFalse(mBtn0.isVisible());
+ assertTrue(mBtn1.isVisible());
+ assertFalse(mBtn2.isVisible());
+
+ // Hide button 1 and make sure the group is also invisible
+ assertNotEquals(mGroup.setButtonVisiblity(BUTTON_1_ID, false /* visible */), View.VISIBLE);
+ assertFalse("No buttons are visible, group should also be hidden", mGroup.isVisible());
+ assertNull("No buttons should be visible", mGroup.getVisibleContextButton());
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testSetButtonVisibilityUnaddedButton() throws Exception {
+ int id = mBtn2.getId() + 1;
+ mGroup.setButtonVisiblity(id, true /* visible */);
+ fail("Did not throw when setting a button with an invalid id");
+ }
+
+ @Test
+ public void testSetHigherPriorityButton() throws Exception {
+ // Show button 0
+ showButton(mBtn0);
+
+ // Show button 1
+ showButton(mBtn1);
+ assertTrue("Button 0 should be visible behind",
+ mGroup.isButtonVisibleWithinGroup(mBtn0.getId()));
+
+ // Show button 2
+ showButton(mBtn2);
+ assertTrue("Button 1 should be visible behind",
+ mGroup.isButtonVisibleWithinGroup(mBtn1.getId()));
+ assertTrue(mGroup.isButtonVisibleWithinGroup(mBtn0.getId()));
+ assertTrue(mGroup.isButtonVisibleWithinGroup(mBtn1.getId()));
+ assertTrue(mGroup.isButtonVisibleWithinGroup(mBtn2.getId()));
+
+ // Hide button 2
+ assertNotEquals(mGroup.setButtonVisiblity(BUTTON_2_ID, false /* visible */), View.VISIBLE);
+ assertEquals("Hiding button 2 should show button 1", mBtn1,
+ mGroup.getVisibleContextButton());
+
+ // Hide button 1
+ assertNotEquals(mGroup.setButtonVisiblity(BUTTON_1_ID, false /* visible */), View.VISIBLE);
+ assertEquals("Hiding button 1 should show button 0", mBtn0,
+ mGroup.getVisibleContextButton());
+
+ // Hide button 0, all buttons are now invisible
+ assertNotEquals(mGroup.setButtonVisiblity(BUTTON_0_ID, false /* visible */), View.VISIBLE);
+ assertFalse("No buttons are visible, group should also be invisible", mGroup.isVisible());
+ assertNull(mGroup.getVisibleContextButton());
+ assertFalse(mGroup.isButtonVisibleWithinGroup(mBtn0.getId()));
+ assertFalse(mGroup.isButtonVisibleWithinGroup(mBtn1.getId()));
+ assertFalse(mGroup.isButtonVisibleWithinGroup(mBtn2.getId()));
+ }
+
+ @Test
+ public void testSetLowerPriorityButton() throws Exception {
+ // Show button 2
+ showButton(mBtn2);
+
+ // Show button 1
+ assertNotEquals(mGroup.setButtonVisiblity(BUTTON_1_ID, true /* visible */), View.VISIBLE);
+ assertTrue("Showing button 1 lower priority should be hidden but visible underneath",
+ mGroup.isButtonVisibleWithinGroup(BUTTON_1_ID));
+ assertFalse(mBtn0.isVisible());
+ assertFalse(mBtn1.isVisible());
+ assertTrue(mBtn2.isVisible());
+
+ // Hide button 1
+ assertNotEquals(mGroup.setButtonVisiblity(BUTTON_1_ID, false /* visible */), View.VISIBLE);
+ assertFalse("Hiding button 1 with lower priority hides itself underneath",
+ mGroup.isButtonVisibleWithinGroup(BUTTON_1_ID));
+ assertTrue("A button still visible, group should also be visible", mGroup.isVisible());
+ assertEquals(mBtn2, mGroup.getVisibleContextButton());
+ }
+
+ @Test
+ public void testSetSamePriorityButton() throws Exception {
+ // Show button 1
+ showButton(mBtn1);
+
+ // Show button 1 again
+ showButton(mBtn1);
+
+ // The original button should still be visible
+ assertEquals(mBtn1, mGroup.getVisibleContextButton());
+ assertFalse(mGroup.isButtonVisibleWithinGroup(mBtn0.getId()));
+ assertFalse(mGroup.isButtonVisibleWithinGroup(mBtn2.getId()));
+ }
+
+ @Test
+ public void testUpdateIconsDarkIntensity() throws Exception {
+ final int unusedColor = 0;
+ final Drawable d = mock(Drawable.class);
+ final ContextualButton button = spy(mBtn0);
+ final KeyButtonDrawable kbd1 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor));
+ final KeyButtonDrawable kbd2 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor));
+ kbd1.setDarkIntensity(TEST_DARK_INTENSITY);
+ kbd2.setDarkIntensity(0f);
+
+ // Update icon returns the drawable intensity to half
+ doReturn(kbd1).when(button).getNewDrawable();
+ button.updateIcon();
+ assertEquals(TEST_DARK_INTENSITY, kbd1.getDarkIntensity(), DARK_INTENSITY_ERR);
+
+ // Return old dark intensity on new drawable after update icon
+ doReturn(kbd2).when(button).getNewDrawable();
+ button.updateIcon();
+ assertEquals(TEST_DARK_INTENSITY, kbd2.getDarkIntensity(), DARK_INTENSITY_ERR);
+ }
+
+ private void showButton(ContextualButton button) {
+ assertEquals(View.VISIBLE, mGroup.setButtonVisiblity(button.getId(), true /* visible */));
+ assertTrue("After set a button visible, group should also be visible", mGroup.isVisible());
+ assertEquals(button, mGroup.getVisibleContextButton());
+ }
+}
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 41b3feb..de85dcb 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -4026,6 +4026,8 @@
// - AUTOFILL_DATASET_AUTHENTICATED
// - AUTOFILL_INVALID_AUTHENTICATION
// - AUTOFILL_INVALID_DATASET_AUTHENTICATION
+ // NOTE: starting on OS Q, it also added the following fields:
+ // Tag FIELD_AUTOFILL_TEXT_LEN: length of the error message provided by the service
AUTOFILL_REQUEST = 907;
// Tag of a field for a package of an autofill service
@@ -4102,6 +4104,8 @@
// Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
// Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
// Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+ // NOTE: starting on OS Q, it also added the following fields:
+ // Tag FIELD_AUTOFILL_TEXT_LEN: length of the error message provided by the service
AUTOFILL_DATA_SAVE_REQUEST = 918;
// An auto-fill session was finished
@@ -6517,6 +6521,9 @@
// OS: Q
MOBILE_NETWORK = 1571;
+ // Tag of a field for the length of a text
+ FIELD_AUTOFILL_TEXT_LEN = 1572;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 8c8352f..78facf8 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -235,6 +235,13 @@
}
}
+ int getTargedSdkLocked() {
+ if (mInfo == null) {
+ return 0;
+ }
+ return mInfo.getServiceInfo().applicationInfo.targetSdkVersion;
+ }
+
private boolean isSetupCompletedLocked() {
final String setupComplete = Settings.Secure.getStringForUser(
mContext.getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, mUserId);
@@ -953,6 +960,7 @@
pw.println();
mInfo.dump(prefix2, pw);
pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabel());
+ pw.print(prefix); pw.print("Target SDK: "); pw.println(getTargedSdkLocked());
}
pw.print(prefix); pw.print("Component from settings: ");
pw.println(getComponentNameFromSettings());
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 2671327..d1b09ca 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -29,6 +29,7 @@
import android.content.Intent;
import android.content.IntentSender;
import android.content.ServiceConnection;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index c9eb2d2..cf323fb 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -50,6 +50,7 @@
import android.graphics.Rect;
import android.metrics.LogMaker;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -63,6 +64,7 @@
import android.service.autofill.Dataset;
import android.service.autofill.FieldClassification;
import android.service.autofill.FieldClassification.Match;
+import android.text.TextUtils;
import android.service.autofill.FillContext;
import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
@@ -744,12 +746,17 @@
private void onFillRequestFailureOrTimeout(int requestId, boolean timedOut,
@Nullable CharSequence message) {
+ boolean showMessage = !TextUtils.isEmpty(message);
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#onFillRequestFailureOrTimeout(req=" + requestId
+ ") rejected - session: " + id + " destroyed");
return;
}
+ if (sDebug) {
+ Slog.d(TAG, "finishing session due to service "
+ + (timedOut ? "timeout" : "failure"));
+ }
mService.resetLastResponse();
final LogMaker requestLog = mRequestLogs.get(requestId);
if (requestLog == null) {
@@ -757,8 +764,21 @@
} else {
requestLog.setType(timedOut ? MetricsEvent.TYPE_CLOSE : MetricsEvent.TYPE_FAILURE);
}
+ if (showMessage) {
+ final int targetSdk = mService.getTargedSdkLocked();
+ if (targetSdk >= Build.VERSION_CODES.Q) {
+ showMessage = false;
+ Slog.w(TAG, "onFillRequestFailureOrTimeout(): not showing '" + message
+ + "' because service's targetting API " + targetSdk);
+ }
+ if (message != null) {
+ requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_TEXT_LEN,
+ message.length());
+ }
+ }
}
- if (message != null) {
+ notifyUnavailableToClient(AutofillManager.STATE_UNKNOWN_FAILED);
+ if (showMessage) {
getUiForShowing().showError(message, this);
}
removeSelf();
@@ -793,6 +813,7 @@
@Override
public void onSaveRequestFailure(@Nullable CharSequence message,
@NonNull String servicePackageName) {
+ boolean showMessage = !TextUtils.isEmpty(message);
synchronized (mLock) {
mIsSaving = false;
@@ -801,12 +822,26 @@
+ id + " destroyed");
return;
}
+ if (showMessage) {
+ final int targetSdk = mService.getTargedSdkLocked();
+ if (targetSdk >= Build.VERSION_CODES.Q) {
+ showMessage = false;
+ Slog.w(TAG, "onSaveRequestFailure(): not showing '" + message
+ + "' because service's targetting API " + targetSdk);
+ }
+ }
}
- LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName)
+ final LogMaker log =
+ newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName)
.setType(MetricsEvent.TYPE_FAILURE);
+ if (message != null) {
+ log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_TEXT_LEN, message.length());
+ }
mMetricsLogger.write(log);
- getUiForShowing().showError(message, this);
+ if (showMessage) {
+ getUiForShowing().showError(message, this);
+ }
removeSelf();
}
@@ -1206,7 +1241,7 @@
// - not autofilled but matches a dataset value -> manuallyFilledIds
if ((state & ViewState.STATE_CHANGED) != 0) {
// Check if autofilled value was changed
- if ((state & ViewState.STATE_AUTOFILLED) != 0) {
+ if ((state & ViewState.STATE_AUTOFILLED_ONCE) != 0) {
final String datasetId = viewState.getDatasetId();
if (datasetId == null) {
// Sanity check - should never happen.
@@ -2181,12 +2216,28 @@
// Must check if this update was caused by autofilling the view, in which
// case we just update the value, but not the UI.
final AutofillValue filledValue = viewState.getAutofilledValue();
- if (filledValue != null && filledValue.equals(value)) {
- if (sVerbose) {
- Slog.v(TAG, "ignoring autofilled change on id " + id);
+ if (filledValue != null) {
+ if (filledValue.equals(value)) {
+ if (sVerbose) {
+ Slog.v(TAG, "ignoring autofilled change on id " + id);
+ }
+ viewState.resetState(ViewState.STATE_CHANGED);
+ return;
}
- return;
+ else {
+ if ((viewState.id.equals(this.mCurrentViewId)) &&
+ (viewState.getState() & ViewState.STATE_AUTOFILLED) != 0) {
+ // Remove autofilled state once field is changed after autofilling.
+ if (sVerbose) {
+ Slog.v(TAG, "field changed after autofill on id " + id);
+ }
+ viewState.resetState(ViewState.STATE_AUTOFILLED);
+ final ViewState currentView = mViewStates.get(mCurrentViewId);
+ currentView.maybeCallOnFillReady(flags);
+ }
+ }
}
+
// Update the internal state...
viewState.setState(ViewState.STATE_CHANGED);
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index e6cd7e0..a8dae03 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -69,8 +69,10 @@
public static final int STATE_RESTARTED_SESSION = 0x100;
/** View is the URL bar of a package on compat mode. */
public static final int STATE_URL_BAR = 0x200;
- /** View was asked to autofil but failed to do so. */
+ /** View was asked to autofill but failed to do so. */
public static final int STATE_AUTOFILL_FAILED = 0x400;
+ /** View has been autofilled at least once. */
+ public static final int STATE_AUTOFILLED_ONCE = 0x800;
public final AutofillId id;
@@ -161,6 +163,9 @@
} else {
mState |= state;
}
+ if (state == STATE_AUTOFILLED) {
+ mState |= STATE_AUTOFILLED_ONCE;
+ }
}
void resetState(int state) {
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 998e441..c2aec29 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -16,6 +16,15 @@
package com.android.server;
+import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
+import static android.app.AppOpsManager.UID_STATE_CACHED;
+import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
+import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
+import static android.app.AppOpsManager.UID_STATE_LAST_NON_RESTRICTED;
+import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
+import static android.app.AppOpsManager.UID_STATE_TOP;
+import static android.app.AppOpsManager._NUM_UID_STATE;
+
import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityThread;
@@ -98,15 +107,6 @@
import java.util.List;
import java.util.Map;
-import static android.app.AppOpsManager._NUM_UID_STATE;
-import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
-import static android.app.AppOpsManager.UID_STATE_CACHED;
-import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
-import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
-import static android.app.AppOpsManager.UID_STATE_LAST_NON_RESTRICTED;
-import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
-import static android.app.AppOpsManager.UID_STATE_TOP;
-
public class AppOpsService extends IAppOpsService.Stub {
static final String TAG = "AppOps";
static final boolean DEBUG = false;
@@ -1016,7 +1016,7 @@
scheduleWriteLocked();
}
} else {
- if (uidState.opModes.get(code) == mode) {
+ if (uidState.opModes.indexOfKey(code) >= 0 && uidState.opModes.get(code) == mode) {
return;
}
if (mode == defaultMode) {
@@ -1971,6 +1971,7 @@
continue;
}
boolean doAllPackages = uidState.opModes != null
+ && uidState.opModes.indexOfKey(code) >= 0
&& uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
if (uidState.pkgOps != null) {
for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7602090..e41a09e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -35,6 +35,9 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.os.Process.INVALID_UID;
+import static android.system.OsConstants.IPPROTO_TCP;
+import static android.system.OsConstants.IPPROTO_UDP;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -49,6 +52,7 @@
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.database.ContentObserver;
+import android.net.ConnectionInfo;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.PacketKeepalive;
import android.net.IConnectivityManager;
@@ -75,7 +79,6 @@
import android.net.NetworkState;
import android.net.NetworkUtils;
import android.net.NetworkWatchlistManager;
-import android.net.Proxy;
import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.UidRange;
@@ -83,6 +86,7 @@
import android.net.VpnService;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
+import android.net.netlink.InetDiagMessage;
import android.net.util.MultinetworkPolicyTracker;
import android.os.Binder;
import android.os.Build;
@@ -153,7 +157,6 @@
import com.android.server.connectivity.NetworkMonitor;
import com.android.server.connectivity.NetworkNotificationManager;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
-import com.android.server.connectivity.PacManager;
import com.android.server.connectivity.PermissionMonitor;
import com.android.server.connectivity.ProxyTracker;
import com.android.server.connectivity.Tethering;
@@ -1680,6 +1683,11 @@
"ConnectivityService");
}
+ private boolean checkNetworkStackPermission() {
+ return PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.NETWORK_STACK);
+ }
+
private void enforceConnectivityRestrictedNetworksPermission() {
try {
mContext.enforceCallingOrSelfPermission(
@@ -5922,4 +5930,49 @@
pw.println(" Get airplane mode.");
}
}
+
+ /**
+ * Caller either needs to be an active VPN, or hold the NETWORK_STACK permission
+ * for testing.
+ */
+ private Vpn enforceActiveVpnOrNetworkStackPermission() {
+ if (checkNetworkStackPermission()) {
+ return null;
+ }
+ final int uid = Binder.getCallingUid();
+ final int user = UserHandle.getUserId(uid);
+ synchronized (mVpns) {
+ Vpn vpn = mVpns.get(user);
+ try {
+ if (vpn.getVpnInfo().ownerUid == uid) return vpn;
+ } catch (NullPointerException e) {
+ /* vpn is null, or VPN is not connected and getVpnInfo() is null. */
+ }
+ }
+ throw new SecurityException("App must either be an active VPN or have the NETWORK_STACK "
+ + "permission");
+ }
+
+ /**
+ * @param connectionInfo the connection to resolve.
+ * @return {@code uid} if the connection is found and the app has permission to observe it
+ * (e.g., if it is associated with the calling VPN app's tunnel) or {@code INVALID_UID} if the
+ * connection is not found.
+ */
+ public int getConnectionOwnerUid(ConnectionInfo connectionInfo) {
+ final Vpn vpn = enforceActiveVpnOrNetworkStackPermission();
+ if (connectionInfo.protocol != IPPROTO_TCP && connectionInfo.protocol != IPPROTO_UDP) {
+ throw new IllegalArgumentException("Unsupported protocol " + connectionInfo.protocol);
+ }
+
+ final int uid = InetDiagMessage.getConnectionOwnerUid(connectionInfo.protocol,
+ connectionInfo.local, connectionInfo.remote);
+
+ /* Filter out Uids not associated with the VPN. */
+ if (vpn != null && !vpn.appliesToUid(uid)) {
+ return INVALID_UID;
+ }
+
+ return uid;
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f7fe9e2..8c7fc84 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5895,7 +5895,8 @@
PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
- + processName + " with config " + getGlobalConfiguration());
+ + processName + " with config "
+ + app.getWindowProcessController().getConfiguration());
ApplicationInfo appInfo = instr != null ? instr.mTargetInfo : app.info;
app.compat = compatibilityInfoForPackage(appInfo);
@@ -6008,8 +6009,8 @@
instr2.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
- new Configuration(getGlobalConfiguration()), app.compat,
- getCommonServicesLocked(app.isolated),
+ new Configuration(app.getWindowProcessController().getConfiguration()),
+ app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, isAutofillCompatEnabled);
} else {
@@ -6017,8 +6018,8 @@
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
- new Configuration(getGlobalConfiguration()), app.compat,
- getCommonServicesLocked(app.isolated),
+ new Configuration(app.getWindowProcessController().getConfiguration()),
+ app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, isAutofillCompatEnabled);
}
@@ -8718,7 +8719,7 @@
StatsLog.write(StatsLog.ISOLATED_UID_CHANGED, info.uid, uid,
StatsLog.ISOLATED_UID_CHANGED__EVENT__CREATED);
}
- final ProcessRecord r = new ProcessRecord(this, info, proc, uid);
+ final ProcessRecord r = new ProcessRecord(this, info, proc, uid, getGlobalConfiguration());
if (!mBooted && !mBooting
&& userId == UserHandle.USER_SYSTEM
&& (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
@@ -17082,30 +17083,6 @@
}
}
- // =========================================================
- // CONFIGURATION
- // =========================================================
-
- public ConfigurationInfo getDeviceConfigurationInfo() {
- ConfigurationInfo config = new ConfigurationInfo();
- synchronized (this) {
- final Configuration globalConfig = getGlobalConfiguration();
- config.reqTouchScreen = globalConfig.touchscreen;
- config.reqKeyboardType = globalConfig.keyboard;
- config.reqNavigation = globalConfig.navigation;
- if (globalConfig.navigation == Configuration.NAVIGATION_DPAD
- || globalConfig.navigation == Configuration.NAVIGATION_TRACKBALL) {
- config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
- }
- if (globalConfig.keyboard != Configuration.KEYBOARD_UNDEFINED
- && globalConfig.keyboard != Configuration.KEYBOARD_NOKEYS) {
- config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
- }
- config.reqGlEsVersion = GL_ES_VERSION;
- }
- return config;
- }
-
@Override
public StackInfo getFocusedStackInfo() throws RemoteException {
return mActivityTaskManager.getFocusedStackInfo();
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index b24c36a..4bcaf71 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2063,7 +2063,12 @@
pw.print("has-secure-screen-lock: "); pw.println(kgm.isDeviceSecure());
}
- ConfigurationInfo configInfo = mInternal.getDeviceConfigurationInfo();
+ ConfigurationInfo configInfo = null;
+ try {
+ configInfo = mTaskInterface.getDeviceConfigurationInfo();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
if (configInfo.reqGlEsVersion != ConfigurationInfo.GL_ES_VERSION_UNDEFINED) {
if (protoOutputStream != null) {
protoOutputStream.write(DeviceConfigurationProto.OPENGL_VERSION,
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c887370..877c856 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1558,7 +1558,8 @@
// we have to always create a new Configuration here.
final MergedConfiguration mergedConfiguration = new MergedConfiguration(
- mService.getGlobalConfiguration(), r.getMergedOverrideConfiguration());
+ app.getWindowProcessController().getConfiguration(),
+ r.getMergedOverrideConfiguration());
r.setLastReportedConfiguration(mergedConfiguration);
logIfTransactionTooLarge(r.intent, r.icicle);
@@ -3187,10 +3188,10 @@
// Kill the running processes. Post on handle since we don't want to hold the service lock
// while calling into AM.
- final Runnable r = PooledLambda.obtainRunnable(
+ final Message m = PooledLambda.obtainMessage(
ActivityManagerInternal::killProcessesForRemovedTask, mService.mAmInternal,
procsToKill);
- mService.mH.post(r);
+ mService.mH.sendMessage(m);
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index 9acb04b..4dc2851 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -149,6 +149,7 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
@@ -649,6 +650,11 @@
mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
}
+ int increaseConfigurationSeqLocked() {
+ mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
+ return mConfigurationSeq;
+ }
+
protected ActivityStackSupervisor createStackSupervisor() {
final ActivityStackSupervisor supervisor = new ActivityStackSupervisor(this, mH.getLooper());
supervisor.initialize();
@@ -704,6 +710,46 @@
return mLockTaskController;
}
+ /**
+ * Return the global configuration used by the process corresponding to the input pid. This is
+ * usually the global configuration with some overrides specific to that process.
+ */
+ Configuration getGlobalConfigurationForCallingPid() {
+ final int pid = Binder.getCallingPid();
+ if (pid == MY_PID || pid < 0) {
+ return getGlobalConfiguration();
+ }
+ synchronized (mGlobalLock) {
+ final WindowProcessController app = mPidMap.get(pid);
+ return app != null ? app.getConfiguration() : getGlobalConfiguration();
+ }
+ }
+
+ /**
+ * Return the device configuration info used by the process corresponding to the input pid.
+ * The value is consistent with the global configuration for the process.
+ */
+ @Override
+ public ConfigurationInfo getDeviceConfigurationInfo() {
+ ConfigurationInfo config = new ConfigurationInfo();
+ synchronized (mGlobalLock) {
+ final Configuration globalConfig = getGlobalConfigurationForCallingPid();
+ config.reqTouchScreen = globalConfig.touchscreen;
+ config.reqKeyboardType = globalConfig.keyboard;
+ config.reqNavigation = globalConfig.navigation;
+ if (globalConfig.navigation == Configuration.NAVIGATION_DPAD
+ || globalConfig.navigation == Configuration.NAVIGATION_TRACKBALL) {
+ config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
+ }
+ if (globalConfig.keyboard != Configuration.KEYBOARD_UNDEFINED
+ && globalConfig.keyboard != Configuration.KEYBOARD_NOKEYS) {
+ config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
+ }
+ config.reqGlEsVersion = mAm.GL_ES_VERSION;
+ }
+ return config;
+ }
+
private void start() {
mInternal = new LocalService();
LocalServices.addService(ActivityTaskManagerInternal.class, mInternal);
@@ -4264,7 +4310,7 @@
public Configuration getConfiguration() {
Configuration ci;
synchronized(mGlobalLock) {
- ci = new Configuration(getGlobalConfiguration());
+ ci = new Configuration(getGlobalConfigurationForCallingPid());
ci.userSetLocale = false;
}
return ci;
@@ -4420,8 +4466,7 @@
locales.get(bestLocaleIndex)));
}
- mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
- mTempConfig.seq = mConfigurationSeq;
+ mTempConfig.seq = increaseConfigurationSeqLocked();
// Update stored global config and notify everyone about the change.
mStackSupervisor.onConfigurationChanged(mTempConfig);
@@ -4455,6 +4500,7 @@
mAm.mHandler.sendMessage(msg);
}
+ // TODO: Consider using mPidMap to update configurations for processes.
for (int i = mAm.mLruProcesses.size() - 1; i >= 0; i--) {
ProcessRecord app = mAm.mLruProcesses.get(i);
try {
@@ -5596,5 +5642,47 @@
}
}
+ /**
+ * Set the corresponding display information for the process global configuration. To be
+ * called when we need to show IME on a different display.
+ *
+ * @param pid The process id associated with the IME window.
+ * @param displayId The ID of the display showing the IME.
+ */
+ @Override
+ public void onImeWindowSetOnDisplay(int pid, int displayId) {
+ if (pid == MY_PID || pid < 0) {
+ if (DEBUG_CONFIGURATION) {
+ Slog.w(TAG,
+ "Trying to update display configuration for system/invalid process.");
+ }
+ return;
+ }
+ mH.post(() -> {
+ synchronized (mGlobalLock) {
+ // Check if display is initialized in AM.
+ if (!mStackSupervisor.isDisplayAdded(displayId)) {
+ // Call come when display is not yet added or has already been removed.
+ if (DEBUG_CONFIGURATION) {
+ Slog.w(TAG, "Trying to update display configuration for non-existing "
+ + "displayId=" + displayId);
+ }
+ return;
+ }
+ final WindowProcessController imeProcess = mPidMap.get(pid);
+ if (imeProcess == null) {
+ if (DEBUG_CONFIGURATION) {
+ Slog.w(TAG, "Trying to update display configuration for invalid pid: "
+ + pid);
+ }
+ return;
+ }
+ // Fetch the current override configuration of the display and set it to the
+ // process global configuration.
+ imeProcess.onConfigurationChanged(
+ mStackSupervisor.getDisplayOverrideConfiguration(displayId));
+ }
+ });
+ }
}
}
diff --git a/services/core/java/com/android/server/am/OomAdjProfiler.java b/services/core/java/com/android/server/am/OomAdjProfiler.java
index 6230e0d..71f0db5 100644
--- a/services/core/java/com/android/server/am/OomAdjProfiler.java
+++ b/services/core/java/com/android/server/am/OomAdjProfiler.java
@@ -91,9 +91,9 @@
return;
}
mSystemServerCpuTimeUpdateScheduled = true;
- BackgroundThread.getHandler().post(PooledLambda.obtainRunnable(
+ BackgroundThread.getHandler().sendMessage(PooledLambda.obtainMessage(
OomAdjProfiler::updateSystemServerCpuTime,
- this, mOnBattery, mScreenOff).recycleOnUse());
+ this, mOnBattery, mScreenOff));
}
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index d3dc0f3..667d3fa 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -17,18 +17,10 @@
package com.android.server.am;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import android.os.Debug;
-import android.util.ArraySet;
-import android.util.DebugUtils;
-import android.util.EventLog;
-import android.util.Slog;
-import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.app.procstats.ProcessState;
-import com.android.internal.os.BatteryStatsImpl;
-
import android.app.ActivityManager;
import android.app.Dialog;
import android.app.IApplicationThread;
@@ -36,7 +28,9 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
import android.os.Binder;
+import android.os.Debug;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
@@ -44,10 +38,18 @@
import android.os.Trace;
import android.os.UserHandle;
import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.DebugUtils;
+import android.util.EventLog;
+import android.util.Slog;
import android.util.StatsLog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.app.procstats.ProcessState;
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.os.BatteryStatsImpl;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -307,6 +309,7 @@
pw.print(prefix); pw.print("manageSpaceActivityName=");
pw.println(info.manageSpaceActivityName);
}
+
pw.print(prefix); pw.print("dir="); pw.print(info.sourceDir);
pw.print(" publicDir="); pw.print(info.publicSourceDir);
pw.print(" data="); pw.println(info.dataDir);
@@ -520,7 +523,7 @@
}
ProcessRecord(ActivityManagerService _service, ApplicationInfo _info, String _processName,
- int _uid) {
+ int _uid, Configuration config) {
mService = _service;
info = _info;
isolated = _info.uid != _uid;
@@ -534,7 +537,7 @@
removed = false;
lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis();
mWindowProcessController = new WindowProcessController(
- mService.mActivityTaskManager, info, processName, uid, userId, this, this);
+ mService.mActivityTaskManager, info, processName, uid, userId, this, this, config);
pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.longVersionCode));
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index bd412fc..8154062 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -850,10 +850,16 @@
}
void scheduleStartProfiles() {
- if (!mHandler.hasMessages(START_PROFILES_MSG)) {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(START_PROFILES_MSG),
- DateUtils.SECOND_IN_MILLIS);
- }
+ // Parent user transition to RUNNING_UNLOCKING happens on FgThread, so it is busy, there is
+ // a chance the profile will reach RUNNING_LOCKED while parent is still locked, so no
+ // attempt will be made to unlock the profile. If we go via FgThread, this will be executed
+ // after the parent had chance to unlock fully.
+ FgThread.getHandler().post(() -> {
+ if (!mHandler.hasMessages(START_PROFILES_MSG)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(START_PROFILES_MSG),
+ DateUtils.SECOND_IN_MILLIS);
+ }
+ });
}
void startProfiles() {
diff --git a/services/core/java/com/android/server/am/WindowProcessController.java b/services/core/java/com/android/server/am/WindowProcessController.java
index e5551b5..f6f4db6 100644
--- a/services/core/java/com/android/server/am/WindowProcessController.java
+++ b/services/core/java/com/android/server/am/WindowProcessController.java
@@ -17,7 +17,10 @@
package com.android.server.am;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -29,11 +32,13 @@
import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
import android.app.Activity;
-import android.app.ActivityTaskManager;
import android.app.ActivityThread;
import android.app.IApplicationThread;
+import android.app.servertransaction.ConfigurationChangeItem;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
+import android.os.Message;
import android.os.RemoteException;
import android.util.ArraySet;
import android.util.Log;
@@ -41,7 +46,7 @@
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.internal.util.function.pooled.PooledRunnable;
+import com.android.server.wm.ConfigurationContainer;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -57,9 +62,10 @@
* window manager so the window manager lock is held and appropriate permissions are checked before
* calls are allowed to proceed.
*/
-public class WindowProcessController {
+public class WindowProcessController extends ConfigurationContainer<ConfigurationContainer> {
private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowProcessController" : TAG_AM;
private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE;
+ private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
// all about the first app in the process
final ApplicationInfo mInfo;
@@ -108,8 +114,12 @@
// any tasks this process had run root activities in
private final ArrayList<TaskRecord> mRecentTasks = new ArrayList<>();
+ // Last configuration that was reported to the process.
+ private final Configuration mLastReportedConfiguration;
+
WindowProcessController(ActivityTaskManagerService atm, ApplicationInfo info, String name,
- int uid, int userId, Object owner, WindowProcessListener listener) {
+ int uid, int userId, Object owner, WindowProcessListener listener,
+ Configuration config) {
mInfo = info;
mName = name;
mUid = uid;
@@ -117,6 +127,10 @@
mOwner = owner;
mListener = listener;
mAtm = atm;
+ mLastReportedConfiguration = new Configuration();
+ if (config != null) {
+ onConfigurationChanged(config);
+ }
}
public void setPid(int pid) {
@@ -219,6 +233,21 @@
return mInstrumenting;
}
+ @Override
+ protected int getChildCount() {
+ return 0;
+ }
+
+ @Override
+ protected ConfigurationContainer getChildAt(int index) {
+ return null;
+ }
+
+ @Override
+ protected ConfigurationContainer getParent() {
+ return null;
+ }
+
public void addPackage(String packageName) {
synchronized (mAtm.mGlobalLock) {
mPkgList.add(packageName);
@@ -482,48 +511,94 @@
void clearProfilerIfNeeded() {
if (mListener == null) return;
// Posting on handler so WM lock isn't held when we call into AM.
- mAtm.mH.post(() -> mListener.clearProfilerIfNeeded());
+ mAtm.mH.sendMessage(PooledLambda.obtainMessage(
+ WindowProcessListener::clearProfilerIfNeeded, mListener));
}
void updateProcessInfo(boolean updateServiceConnectionActivities, boolean updateLru,
boolean activityChange, boolean updateOomAdj) {
if (mListener == null) return;
// Posting on handler so WM lock isn't held when we call into AM.
- final Runnable r = PooledLambda.obtainRunnable(WindowProcessListener::updateProcessInfo,
+ final Message m = PooledLambda.obtainMessage(WindowProcessListener::updateProcessInfo,
mListener, updateServiceConnectionActivities, updateLru, activityChange,
updateOomAdj);
- mAtm.mH.post(r);
+ mAtm.mH.sendMessage(m);
}
void updateServiceConnectionActivities() {
if (mListener == null) return;
// Posting on handler so WM lock isn't held when we call into AM.
- mAtm.mH.post(() -> mListener.updateServiceConnectionActivities());
+ mAtm.mH.sendMessage(PooledLambda.obtainMessage(
+ WindowProcessListener::updateServiceConnectionActivities, mListener));
}
void setPendingUiClean(boolean pendingUiClean) {
if (mListener == null) return;
// Posting on handler so WM lock isn't held when we call into AM.
- final Runnable r = PooledLambda.obtainRunnable(
+ final Message m = PooledLambda.obtainMessage(
WindowProcessListener::setPendingUiClean, mListener, pendingUiClean);
- mAtm.mH.post(r);
+ mAtm.mH.sendMessage(m);
}
void setPendingUiCleanAndForceProcessStateUpTo(int newState) {
if (mListener == null) return;
// Posting on handler so WM lock isn't held when we call into AM.
- final Runnable r = PooledLambda.obtainRunnable(
+ final Message m = PooledLambda.obtainMessage(
WindowProcessListener::setPendingUiCleanAndForceProcessStateUpTo,
mListener, newState);
- mAtm.mH.post(r);
+ mAtm.mH.sendMessage(m);
}
void setRemoved(boolean removed) {
if (mListener == null) return;
// Posting on handler so WM lock isn't held when we call into AM.
- final Runnable r = PooledLambda.obtainRunnable(
+ final Message m = PooledLambda.obtainMessage(
WindowProcessListener::setRemoved, mListener, removed);
- mAtm.mH.post(r);
+ mAtm.mH.sendMessage(m);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newGlobalConfig) {
+ super.onConfigurationChanged(newGlobalConfig);
+ updateConfiguration();
+ }
+
+ @Override
+ public void onOverrideConfigurationChanged(Configuration newOverrideConfig) {
+ super.onOverrideConfigurationChanged(newOverrideConfig);
+ updateConfiguration();
+ }
+
+ private void updateConfiguration() {
+ final Configuration config = getConfiguration();
+ if (mLastReportedConfiguration.diff(config) == 0) {
+ // Nothing changed.
+ return;
+ }
+
+ try {
+ if (mThread == null) {
+ return;
+ }
+ if (DEBUG_CONFIGURATION) {
+ Slog.v(TAG_CONFIGURATION, "Sending to proc " + mName
+ + " new config " + config);
+ }
+ config.seq = mAtm.increaseConfigurationSeqLocked();
+ mAtm.getLifecycleManager().scheduleTransaction(mThread,
+ ConfigurationChangeItem.obtain(config));
+ setLastReportedConfiguration(config);
+ } catch (Exception e) {
+ Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change", e);
+ }
+ }
+
+ private void setLastReportedConfiguration(Configuration config) {
+ mLastReportedConfiguration.setTo(config);
+ }
+
+ Configuration getLastReportedConfiguration() {
+ return mLastReportedConfiguration;
}
/** Returns the total time (in milliseconds) spent executing in both user and system code. */
@@ -574,6 +649,9 @@
pw.print(prefix); pw.print("mVrThreadTid="); pw.println(mVrThreadTid);
}
}
+ pw.println(prefix + " Configuration=" + getConfiguration());
+ pw.println(prefix + " OverrideConfiguration=" + getOverrideConfiguration());
+ pw.println(prefix + " mLastReportedConfiguration=" + mLastReportedConfiguration);
}
}
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index 6b09f1b..aa4d34e 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -26,10 +26,13 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.security.KeyStore;
import android.util.Slog;
import com.android.internal.statusbar.IStatusBarService;
+import java.util.ArrayList;
+
/**
* A class to keep track of the authentication state for a given client.
*/
@@ -50,28 +53,68 @@
public static final int LOCKOUT_TIMED = 1;
public static final int LOCKOUT_PERMANENT = 2;
+ private final boolean mRequireConfirmation;
// Callback mechanism received from the client
// (BiometricPrompt -> BiometricPromptService -> <Biometric>Service -> AuthenticationClient)
private IBiometricPromptReceiver mDialogReceiverFromClient;
private Bundle mBundle;
private IStatusBarService mStatusBarService;
private boolean mInLockout;
+ private TokenEscrow mEscrow;
protected boolean mDialogDismissed;
+ /**
+ * Container that holds the identifier and authToken. For biometrics that require user
+ * confirmation, these should not be sent to their final destinations until the user confirms.
+ */
+ class TokenEscrow {
+ final BiometricAuthenticator.Identifier mIdentifier;
+ final ArrayList<Byte> mToken;
+
+ TokenEscrow(BiometricAuthenticator.Identifier identifier, ArrayList<Byte> token) {
+ mIdentifier = identifier;
+ mToken = token;
+ }
+
+ BiometricAuthenticator.Identifier getIdentifier() {
+ return mIdentifier;
+ }
+
+ ArrayList<Byte> getToken() {
+ return mToken;
+ }
+ }
+
// Receives events from SystemUI and handles them before forwarding them to BiometricDialog
protected IBiometricPromptReceiver mDialogReceiver = new IBiometricPromptReceiver.Stub() {
@Override // binder call
public void onDialogDismissed(int reason) {
if (mBundle != null && mDialogReceiverFromClient != null) {
try {
- mDialogReceiverFromClient.onDialogDismissed(reason);
+ if (reason != BiometricPrompt.DISMISSED_REASON_POSITIVE) {
+ // Positive button is used by passive modalities as a "confirm" button,
+ // do not send to client
+ mDialogReceiverFromClient.onDialogDismissed(reason);
+ }
if (reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL) {
onError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
0 /* vendorCode */);
+ } else if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) {
+ // Have the service send the token to KeyStore, and send onAuthenticated
+ // to the application.
+ if (mEscrow != null) {
+ if (DEBUG) Slog.d(getLogTag(), "Confirmed");
+ addTokenToKeyStore(mEscrow.getToken());
+ notifyClientAuthenticationSucceeded(mEscrow.getIdentifier());
+ mEscrow = null;
+ onAuthenticationConfirmed();
+ } else {
+ Slog.e(getLogTag(), "Escrow is null!!!");
+ }
}
mDialogDismissed = true;
} catch (RemoteException e) {
- Slog.e(getLogTag(), "Unable to notify dialog dismissed", e);
+ Slog.e(getLogTag(), "Remote exception", e);
}
stop(true /* initiatedByClient */);
}
@@ -89,11 +132,18 @@
*/
public abstract void onStop();
+ /**
+ * This method is called when biometric authentication was confirmed by the user. The client
+ * should be removed.
+ */
+ public abstract void onAuthenticationConfirmed();
+
public AuthenticationClient(Context context, Metrics metrics,
- BiometricService.DaemonWrapper daemon, long halDeviceId, IBinder token,
- BiometricService.ServiceListener listener, int targetUserId, int groupId, long opId,
+ BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
+ BiometricServiceBase.ServiceListener listener, int targetUserId, int groupId, long opId,
boolean restricted, String owner, Bundle bundle,
- IBiometricPromptReceiver dialogReceiver, IStatusBarService statusBarService) {
+ IBiometricPromptReceiver dialogReceiver, IStatusBarService statusBarService,
+ boolean requireConfirmation) {
super(context, metrics, daemon, halDeviceId, token, listener, targetUserId, groupId,
restricted, owner);
mOpId = opId;
@@ -101,6 +151,7 @@
mDialogReceiverFromClient = dialogReceiver;
mStatusBarService = statusBarService;
mHandler = new Handler(Looper.getMainLooper());
+ mRequireConfirmation = requireConfirmation;
}
@Override
@@ -154,9 +205,41 @@
return super.onError(deviceId, error, vendorCode);
}
+ private void notifyClientAuthenticationSucceeded(BiometricAuthenticator.Identifier identifier)
+ throws RemoteException {
+ final BiometricServiceBase.ServiceListener listener = getListener();
+ // Explicitly have if/else here to make it super obvious in case the code is
+ // touched in the future.
+ if (!getIsRestricted()) {
+ listener.onAuthenticationSucceeded(
+ getHalDeviceId(), identifier, getTargetUserId());
+ } else {
+ listener.onAuthenticationSucceeded(
+ getHalDeviceId(), null, getTargetUserId());
+ }
+ }
+
+ private void addTokenToKeyStore(ArrayList<Byte> token) {
+ // Send the token to KeyStore
+ final byte[] byteToken = new byte[token.size()];
+ for (int i = 0; i < token.size(); i++) {
+ byteToken[i] = token.get(i);
+ }
+ KeyStore.getInstance().addAuthToken(byteToken);
+ }
+
@Override
public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
- boolean authenticated) {
+ boolean authenticated, ArrayList<Byte> token) {
+ if (authenticated) {
+ if (mRequireConfirmation) {
+ // Store the token so it can be sent to keystore after the user presses confirm
+ mEscrow = new TokenEscrow(identifier, token);
+ } else {
+ addTokenToKeyStore(token);
+ }
+ }
+
boolean result = false;
// If the biometric dialog is showing, notify authentication succeeded
@@ -173,7 +256,7 @@
}
}
- final BiometricService.ServiceListener listener = getListener();
+ final BiometricServiceBase.ServiceListener listener = getListener();
if (listener != null) {
try {
mMetricsLogger.action(mMetrics.actionBiometricAuth(), authenticated);
@@ -184,15 +267,8 @@
Slog.v(getLogTag(), "onAuthenticated(owner=" + getOwnerString()
+ ", id=" + identifier.getBiometricId());
}
-
- // Explicitly have if/else here to make it super obvious in case the code is
- // touched in the future.
- if (!getIsRestricted()) {
- listener.onAuthenticationSucceeded(
- getHalDeviceId(), identifier, getTargetUserId());
- } else {
- listener.onAuthenticationSucceeded(
- getHalDeviceId(), null, getTargetUserId());
+ if (!mRequireConfirmation) {
+ notifyClientAuthenticationSucceeded(identifier);
}
}
} catch (RemoteException e) {
@@ -241,7 +317,8 @@
if (listener != null) {
vibrateSuccess();
}
- result |= true; // we have a valid biometric, done
+ // we have a valid biometric that doesn't require confirmation, done
+ result |= !mRequireConfirmation;
resetFailedAttempts();
onStop();
}
@@ -269,7 +346,7 @@
if (mBundle != null) {
try {
mStatusBarService.showBiometricDialog(mBundle, mDialogReceiver,
- getBiometricType());
+ getBiometricType(), mRequireConfirmation);
} catch (RemoteException e) {
Slog.e(getLogTag(), "Unable to show biometric dialog", e);
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricPromptService.java b/services/core/java/com/android/server/biometrics/BiometricPromptService.java
deleted file mode 100644
index d1371d1..0000000
--- a/services/core/java/com/android/server/biometrics/BiometricPromptService.java
+++ /dev/null
@@ -1,345 +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.server.biometrics;
-
-import static android.Manifest.permission.USE_BIOMETRIC;
-import static android.Manifest.permission.USE_FINGERPRINT;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.hardware.biometrics.BiometricAuthenticator;
-import android.hardware.biometrics.BiometricConstants;
-import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.IBiometricPromptService;
-import android.hardware.biometrics.IBiometricPromptServiceReceiver;
-import android.hardware.face.FaceManager;
-import android.hardware.face.IFaceService;
-import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.IFingerprintService;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.util.Slog;
-
-import com.android.internal.R;
-import com.android.server.SystemService;
-
-import java.util.ArrayList;
-
-/**
- * System service that arbitrates the modality for BiometricPrompt to use.
- */
-public class BiometricPromptService extends SystemService {
-
- private static final String TAG = "BiometricPromptService";
-
- /**
- * No biometric methods or nothing has been enrolled.
- * Move/expose these in BiometricPrompt if we ever want to allow applications to "blacklist"
- * modalities when calling authenticate().
- */
- private static final int BIOMETRIC_NONE = 0;
-
- /**
- * Constant representing fingerprint.
- */
- private static final int BIOMETRIC_FINGERPRINT = 1 << 0;
-
- /**
- * Constant representing iris.
- */
- private static final int BIOMETRIC_IRIS = 1 << 1;
-
- /**
- * Constant representing face.
- */
- private static final int BIOMETRIC_FACE = 1 << 2;
-
- private static final int[] FEATURE_ID = {
- BIOMETRIC_FINGERPRINT,
- BIOMETRIC_IRIS,
- BIOMETRIC_FACE
- };
-
- private final Handler mHandler;
- private final boolean mHasFeatureFingerprint;
- private final boolean mHasFeatureIris;
- private final boolean mHasFeatureFace;
-
- private IFingerprintService mFingerprintService;
- private IFaceService mFaceService;
-
- // Get and cache the available authenticator (manager) classes. Used since aidl doesn't support
- // polymorphism :/
- final ArrayList<Authenticator> mAuthenticators = new ArrayList<>();
-
- // Cache the current service that's being used. This is the service which
- // cancelAuthentication() must be forwarded to. This is just a cache, and the actual
- // check (is caller the current client) is done in the <Biometric>Service.
- // Since Settings/System (not application) is responsible for changing preference, this
- // should be safe.
- private int mCurrentModality;
-
- private final class Authenticator {
- int mType;
- BiometricAuthenticator mAuthenticator;
-
- Authenticator(int type, BiometricAuthenticator authenticator) {
- mType = type;
- mAuthenticator = authenticator;
- }
-
- int getType() {
- return mType;
- }
-
- BiometricAuthenticator getAuthenticator() {
- return mAuthenticator;
- }
- }
-
- /**
- * This is just a pass-through service that wraps Fingerprint, Iris, Face services. This service
- * should not carry any state. The reality is we need to keep a tiny amount of state so that
- * cancelAuthentication() can go to the right place.
- */
- private final class BiometricPromptServiceWrapper extends IBiometricPromptService.Stub {
-
- @Override // Binder call
- public void authenticate(IBinder token, long sessionId, int userId,
- IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
- Bundle bundle, IBiometricPromptReceiver dialogReceiver) throws RemoteException {
- // Check the USE_BIOMETRIC permission here. In the BiometricService, check do the
- // AppOps and foreground check.
- checkPermission();
-
- if (token == null || receiver == null || opPackageName == null || bundle == null
- || dialogReceiver == null) {
- Slog.e(TAG, "Unable to authenticate, one or more null arguments");
- return;
- }
-
- final int callingUid = Binder.getCallingUid();
- final int callingPid = Binder.getCallingPid();
- final int callingUserId = UserHandle.getCallingUserId();
-
- mHandler.post(() -> {
- mCurrentModality = checkAndGetBiometricModality(receiver);
-
- try {
- // No polymorphism :(
- if (mCurrentModality == BIOMETRIC_FINGERPRINT) {
- mFingerprintService.authenticateFromService(token, sessionId, userId,
- receiver, flags, opPackageName, bundle, dialogReceiver,
- callingUid, callingPid, callingUserId);
- } else if (mCurrentModality == BIOMETRIC_IRIS) {
- Slog.w(TAG, "Unsupported modality");
- } else if (mCurrentModality == BIOMETRIC_FACE) {
- mFaceService.authenticateFromService(token, sessionId, userId,
- receiver, flags, opPackageName, bundle, dialogReceiver,
- callingUid, callingPid, callingUserId);
- } else {
- Slog.w(TAG, "Unsupported modality");
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to start authentication", e);
- }
- });
- }
-
- @Override // Binder call
- public void cancelAuthentication(IBinder token, String opPackageName)
- throws RemoteException {
- checkPermission();
-
- if (token == null || opPackageName == null) {
- Slog.e(TAG, "Unable to cancel, one or more null arguments");
- return;
- }
-
- final int callingUid = Binder.getCallingUid();
- final int callingPid = Binder.getCallingPid();
- final int callingUserId = UserHandle.getCallingUserId();
-
- mHandler.post(() -> {
- try {
- if (mCurrentModality == BIOMETRIC_FINGERPRINT) {
- mFingerprintService.cancelAuthenticationFromService(token, opPackageName,
- callingUid, callingPid, callingUserId);
- } else if (mCurrentModality == BIOMETRIC_IRIS) {
- Slog.w(TAG, "Unsupported modality");
- } else if (mCurrentModality == BIOMETRIC_FACE) {
- mFaceService.cancelAuthenticationFromService(token, opPackageName,
- callingUid, callingPid, callingUserId);
- } else {
- Slog.w(TAG, "Unsupported modality");
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to cancel authentication");
- }
- });
- }
- }
-
- private void checkPermission() {
- if (getContext().checkCallingPermission(USE_FINGERPRINT)
- != PackageManager.PERMISSION_GRANTED) {
- getContext().enforceCallingPermission(USE_BIOMETRIC,
- "Must have USE_BIOMETRIC permission");
- }
- }
-
- /**
- * Initializes the system service.
- * <p>
- * Subclasses must define a single argument constructor that accepts the context
- * and passes it to super.
- * </p>
- *
- * @param context The system server context.
- */
- public BiometricPromptService(Context context) {
- super(context);
-
- mHandler = new Handler(Looper.getMainLooper());
-
- final PackageManager pm = context.getPackageManager();
- mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
- mHasFeatureIris = pm.hasSystemFeature(PackageManager.FEATURE_IRIS);
- mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
- }
-
- @Override
- public void onStart() {
- // TODO: maybe get these on-demand
- if (mHasFeatureFingerprint) {
- mFingerprintService = IFingerprintService.Stub.asInterface(
- ServiceManager.getService(Context.FINGERPRINT_SERVICE));
- }
- if (mHasFeatureFace) {
- mFaceService = IFaceService.Stub.asInterface(
- ServiceManager.getService(Context.FACE_SERVICE));
- }
-
- // Cache the authenticators
- for (int i = 0; i < FEATURE_ID.length; i++) {
- if (hasFeature(FEATURE_ID[i])) {
- Authenticator authenticator =
- new Authenticator(FEATURE_ID[i], getAuthenticator(FEATURE_ID[i]));
- mAuthenticators.add(authenticator);
- }
- }
-
- publishBinderService(Context.BIOMETRIC_PROMPT_SERVICE, new BiometricPromptServiceWrapper());
- }
-
- /**
- * Checks if there are any available biometrics, and returns the modality. This method also
- * returns errors through the callback (no biometric feature, hardware not detected, no
- * templates enrolled, etc). This service must not start authentication if errors are sent.
- */
- private int checkAndGetBiometricModality(IBiometricPromptServiceReceiver receiver) {
- int modality = BIOMETRIC_NONE;
- final String hardwareUnavailable =
- getContext().getString(R.string.biometric_error_hw_unavailable);
-
- // No biometric features, send error
- if (mAuthenticators.isEmpty()) {
- try {
- receiver.onError(0 /* deviceId */,
- BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT,
- hardwareUnavailable);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to send error", e);
- }
- return BIOMETRIC_NONE;
- }
-
- // Find first authenticator that's both detected and enrolled
- boolean isHardwareDetected = false;
- boolean hasTemplatesEnrolled = false;
- for (int i = 0; i < mAuthenticators.size(); i++) {
- int featureId = mAuthenticators.get(i).getType();
- BiometricAuthenticator authenticator = mAuthenticators.get(i).getAuthenticator();
- if (authenticator.isHardwareDetected()) {
- isHardwareDetected = true;
- if (authenticator.hasEnrolledTemplates()) {
- hasTemplatesEnrolled = true;
- modality = featureId;
- break;
- }
- }
- }
-
- // Check error conditions
- if (!isHardwareDetected) {
- try {
- receiver.onError(0 /* deviceId */,
- BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
- hardwareUnavailable);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to send error", e);
- }
- return BIOMETRIC_NONE;
- }
- if (!hasTemplatesEnrolled) {
- try {
- receiver.onError(0 /* deviceId */,
- BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS,
- hardwareUnavailable);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to send error", e);
- }
- return BIOMETRIC_NONE;
- }
-
- return modality;
- }
-
- private BiometricAuthenticator getAuthenticator(int type) {
- switch (type) {
- case BIOMETRIC_FINGERPRINT:
- return (FingerprintManager)
- getContext().getSystemService(Context.FINGERPRINT_SERVICE);
- case BIOMETRIC_IRIS:
- return null;
- case BIOMETRIC_FACE:
- return (FaceManager)
- getContext().getSystemService(Context.FACE_SERVICE);
- default:
- return null;
- }
- }
-
- private boolean hasFeature(int type) {
- switch (type) {
- case BIOMETRIC_FINGERPRINT:
- return mHasFeatureFingerprint;
- case BIOMETRIC_IRIS:
- return mHasFeatureIris;
- case BIOMETRIC_FACE:
- return mHasFeatureFace;
- default:
- return false;
- }
- }
-}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 73c4223..fa22b84 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -11,508 +11,221 @@
* 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
+ * limitations under the License.
*/
package com.android.server.biometrics;
-import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+import static android.Manifest.permission.USE_BIOMETRIC;
+import static android.Manifest.permission.USE_FINGERPRINT;
-import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
-import android.app.AlarmManager;
-import android.app.AppOpsManager;
-import android.app.IActivityTaskManager;
-import android.app.PendingIntent;
-import android.app.SynchronousUserSwitchObserver;
-import android.app.TaskStackListener;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
-import android.hardware.fingerprint.Fingerprint;
+import android.hardware.biometrics.IBiometricService;
+import android.hardware.biometrics.IBiometricServiceReceiver;
+import android.hardware.face.FaceManager;
+import android.hardware.face.IFaceService;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IFingerprintService;
import android.os.Binder;
import android.os.Bundle;
-import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
-import android.os.IHwBinder;
-import android.os.IRemoteCallback;
-import android.os.PowerManager;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemClock;
import android.os.UserHandle;
-import android.os.UserManager;
-import android.security.KeyStore;
import android.util.Slog;
-import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.R;
import com.android.server.SystemService;
-import com.android.server.biometrics.fingerprint.FingerprintService;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
/**
- * Abstract base class containing all of the business logic for biometric services, e.g.
- * Fingerprint, Face, Iris.
- *
- * @hide
+ * System service that arbitrates the modality for BiometricPrompt to use.
*/
-public abstract class BiometricService extends SystemService implements IHwBinder.DeathRecipient {
+public class BiometricService extends SystemService {
- protected static final boolean DEBUG = true;
+ private static final String TAG = "BiometricPromptService";
- private static final String KEY_LOCKOUT_RESET_USER = "lockout_reset_user";
- private static final int MSG_USER_SWITCHING = 10;
- private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30 * 1000;
- private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
+ /**
+ * No biometric methods or nothing has been enrolled.
+ * Move/expose these in BiometricPrompt if we ever want to allow applications to "blacklist"
+ * modalities when calling authenticate().
+ */
+ private static final int BIOMETRIC_NONE = 0;
- private final Context mContext;
- private final String mKeyguardPackage;
- private final AppOpsManager mAppOps;
- private final SparseBooleanArray mTimedLockoutCleared;
- private final SparseIntArray mFailedAttempts;
- private final IActivityTaskManager mActivityTaskManager;
- private final AlarmManager mAlarmManager;
- private final PowerManager mPowerManager;
- private final UserManager mUserManager;
- private final MetricsLogger mMetricsLogger;
- private final BiometricTaskStackListener mTaskStackListener = new BiometricTaskStackListener();
- private final ResetClientStateRunnable mResetClientState = new ResetClientStateRunnable();
- private final LockoutReceiver mLockoutReceiver = new LockoutReceiver();
- private final ArrayList<LockoutResetMonitor> mLockoutMonitors = new ArrayList<>();
+ /**
+ * Constant representing fingerprint.
+ */
+ private static final int BIOMETRIC_FINGERPRINT = 1 << 0;
- protected final IStatusBarService mStatusBarService;
- protected final Map<Integer, Long> mAuthenticatorIds =
- Collections.synchronizedMap(new HashMap<>());
- protected final ResetFailedAttemptsForUserRunnable mResetFailedAttemptsForCurrentUserRunnable =
- new ResetFailedAttemptsForUserRunnable();
- protected final H mHandler = new H();
+ /**
+ * Constant representing iris.
+ */
+ private static final int BIOMETRIC_IRIS = 1 << 1;
- private ClientMonitor mCurrentClient;
- private ClientMonitor mPendingClient;
- private PerformanceStats mPerformanceStats;
- protected int mCurrentUserId = UserHandle.USER_NULL;
- // Tracks if the current authentication makes use of CryptoObjects.
- protected boolean mIsCrypto;
- // Normal authentications are tracked by mPerformanceMap.
- protected HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
- // Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
- protected HashMap<Integer, PerformanceStats> mCryptoPerformanceMap = new HashMap<>();
+ /**
+ * Constant representing face.
+ */
+ private static final int BIOMETRIC_FACE = 1 << 2;
- protected class PerformanceStats {
- public int accept; // number of accepted biometrics
- public int reject; // number of rejected biometrics
- public int acquire; // total number of acquisitions. Should be >= accept+reject due to poor
- // image acquisition in some cases (too fast, too slow, dirty sensor, etc.)
- public int lockout; // total number of lockouts
- public int permanentLockout; // total number of permanent lockouts
+ private static final int[] FEATURE_ID = {
+ BIOMETRIC_FINGERPRINT,
+ BIOMETRIC_IRIS,
+ BIOMETRIC_FACE
+ };
+
+ private final Handler mHandler;
+ private final boolean mHasFeatureFingerprint;
+ private final boolean mHasFeatureIris;
+ private final boolean mHasFeatureFace;
+
+ private IFingerprintService mFingerprintService;
+ private IFaceService mFaceService;
+
+ // Get and cache the available authenticator (manager) classes. Used since aidl doesn't support
+ // polymorphism :/
+ final ArrayList<Authenticator> mAuthenticators = new ArrayList<>();
+
+ // Cache the current service that's being used. This is the service which
+ // cancelAuthentication() must be forwarded to. This is just a cache, and the actual
+ // check (is caller the current client) is done in the <Biometric>Service.
+ // Since Settings/System (not application) is responsible for changing preference, this
+ // should be safe.
+ private int mCurrentModality;
+
+ private final class Authenticator {
+ int mType;
+ BiometricAuthenticator mAuthenticator;
+
+ Authenticator(int type, BiometricAuthenticator authenticator) {
+ mType = type;
+ mAuthenticator = authenticator;
+ }
+
+ int getType() {
+ return mType;
+ }
+
+ BiometricAuthenticator getAuthenticator() {
+ return mAuthenticator;
+ }
}
/**
- * @return the log tag.
+ * This is just a pass-through service that wraps Fingerprint, Iris, Face services. This service
+ * should not carry any state. The reality is we need to keep a tiny amount of state so that
+ * cancelAuthentication() can go to the right place.
*/
- protected abstract String getTag();
+ private final class BiometricPromptServiceWrapper extends IBiometricService.Stub {
- /**
- * @return the biometric utilities for a specific implementation.
- */
- protected abstract BiometricUtils getBiometricUtils();
+ @Override // Binder call
+ public void authenticate(IBinder token, long sessionId, int userId,
+ IBiometricServiceReceiver receiver, int flags, String opPackageName,
+ Bundle bundle, IBiometricPromptReceiver dialogReceiver) throws RemoteException {
+ // Check the USE_BIOMETRIC permission here. In the BiometricService, check do the
+ // AppOps and foreground check.
+ checkPermission();
- /**
- * @return the number of failed attempts after which the user will be temporarily locked out
- * from using the biometric. A strong auth (pin/pattern/pass) clears this counter.
- */
- protected abstract int getFailedAttemptsLockoutTimed();
-
- /**
- * @return the number of failed attempts after which the user will be permanently locked out
- * from using the biometric. A strong auth (pin/pattern/pass) clears this counter.
- */
- protected abstract int getFailedAttemptsLockoutPermanent();
-
- /**
- * @return the metrics constants for a biometric implementation.
- */
- protected abstract Metrics getMetrics();
-
- /**
- * @param userId
- * @return true if the enrollment limit has been reached.
- */
- protected abstract boolean hasReachedEnrollmentLimit(int userId);
-
- /**
- * Notifies the HAL that the user has changed.
- * @param userId
- * @param clientPackage
- */
- protected abstract void updateActiveGroup(int userId, String clientPackage);
-
- /**
- * @return The protected intent to reset lockout for a specific biometric.
- */
- protected abstract String getLockoutResetIntent();
-
- /**
- * @return The permission the sender is required to have in order for the lockout reset intent
- * to be received by the BiometricService implementation.
- */
- protected abstract String getLockoutBroadcastPermission();
-
- /**
- * @return The HAL ID.
- */
- protected abstract long getHalDeviceId();
-
- /**
- * This method is called when the user switches. Implementations should probably notify the
- * HAL.
- * @param userId
- */
- protected abstract void handleUserSwitching(int userId);
-
- /**
- * @param userId
- * @return Returns true if the user has any enrolled biometrics.
- */
- protected abstract boolean hasEnrolledBiometrics(int userId);
-
- /**
- * @return Returns the MANAGE_* permission string, which is required for enrollment, removal
- * etc.
- */
- protected abstract String getManageBiometricPermission();
-
- /**
- * Checks if the caller has permission to use the biometric service - throws a SecurityException
- * if not.
- */
- protected abstract void checkUseBiometricPermission();
-
- /**
- * @return Returns one of the {@link AppOpsManager} constants which pertains to the specific
- * biometric service.
- */
- protected abstract int getAppOp();
-
-
- /**
- * Notifies clients of any change in the biometric state (active / idle). This is mainly for
- * Fingerprint navigation gestures.
- * @param isActive
- */
- protected void notifyClientActiveCallbacks(boolean isActive) {}
-
- protected abstract class AuthenticationClientImpl extends AuthenticationClient {
-
- public AuthenticationClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
- IBinder token, ServiceListener listener, int targetUserId, int groupId, long opId,
- boolean restricted, String owner, Bundle bundle,
- IBiometricPromptReceiver dialogReceiver,
- IStatusBarService statusBarService) {
- super(context, getMetrics(), daemon, halDeviceId, token, listener,
- targetUserId, groupId, opId, restricted, owner, bundle, dialogReceiver,
- statusBarService);
- }
-
- @Override
- public void onStart() {
- try {
- mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- Slog.e(getTag(), "Could not register task stack listener", e);
- }
- }
-
- @Override
- public void onStop() {
- try {
- mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- Slog.e(getTag(), "Could not unregister task stack listener", e);
- }
- }
-
- @Override
- public void resetFailedAttempts() {
- resetFailedAttemptsForUser(true /* clearAttemptCounter */,
- ActivityManager.getCurrentUser());
- }
-
- @Override
- public void notifyUserActivity() {
- userActivity();
- }
-
- @Override
- public int handleFailedAttempt() {
- final int currentUser = ActivityManager.getCurrentUser();
- mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
- mTimedLockoutCleared.put(ActivityManager.getCurrentUser(), false);
- final int lockoutMode = getLockoutMode();
- if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
- mPerformanceStats.permanentLockout++;
- } else if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
- mPerformanceStats.lockout++;
+ if (token == null || receiver == null || opPackageName == null || bundle == null
+ || dialogReceiver == null) {
+ Slog.e(TAG, "Unable to authenticate, one or more null arguments");
+ return;
}
- // Failing multiple times will continue to push out the lockout time
- if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
- scheduleLockoutResetForUser(currentUser);
- return lockoutMode;
- }
- return AuthenticationClient.LOCKOUT_NONE;
- }
- }
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int callingUserId = UserHandle.getCallingUserId();
- protected class EnrollClientImpl extends EnrollClient {
+ mHandler.post(() -> {
+ mCurrentModality = checkAndGetBiometricModality(receiver);
- public EnrollClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
- IBinder token, ServiceListener listener, int userId, int groupId,
- byte[] cryptoToken, boolean restricted, String owner) {
- super(context, getMetrics(), daemon, halDeviceId, token, listener,
- userId, groupId, cryptoToken, restricted, owner, getBiometricUtils());
- }
-
- @Override
- public void notifyUserActivity() {
- userActivity();
- }
- }
-
- protected class RemovalClientImpl extends RemovalClient {
- private boolean mShouldNotify;
-
- public RemovalClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
- IBinder token, ServiceListener listener, int fingerId, int groupId, int userId,
- boolean restricted, String owner) {
- super(context, getMetrics(), daemon, halDeviceId, token, listener, fingerId, groupId,
- userId, restricted, owner, getBiometricUtils());
- }
-
- public void setShouldNotifyUserActivity(boolean shouldNotify) {
- mShouldNotify = shouldNotify;
- }
-
- @Override
- public void notifyUserActivity() {
- if (mShouldNotify) {
- userActivity();
- }
- }
- }
-
- protected class EnumerateClientImpl extends EnumerateClient {
-
- public EnumerateClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
- IBinder token, ServiceListener listener, int groupId, int userId,
- boolean restricted, String owner) {
- super(context, getMetrics(), daemon, halDeviceId, token, listener, groupId, userId,
- restricted, owner);
- }
-
- @Override
- public void notifyUserActivity() {
- userActivity();
- }
- }
-
- /**
- * Wraps the callback interface from Service -> Manager
- */
- protected interface ServiceListener {
- default void onEnrollResult(BiometricAuthenticator.Identifier identifier,
- int remaining) throws RemoteException {};
-
- void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
- throws RemoteException;
-
- void onAuthenticationSucceeded(long deviceId,
- BiometricAuthenticator.Identifier biometric, int userId)
- throws RemoteException;
-
- void onAuthenticationFailed(long deviceId)
- throws RemoteException;
-
- void onError(long deviceId, int error, int vendorCode)
- throws RemoteException;
-
- default void onRemoved(BiometricAuthenticator.Identifier identifier,
- int remaining) throws RemoteException {};
-
- default void onEnumerated(BiometricAuthenticator.Identifier identifier,
- int remaining) throws RemoteException {};
- }
-
- /**
- * Wraps a portion of the interface from Service -> Daemon that is used by the ClientMonitor
- * subclasses.
- */
- protected interface DaemonWrapper {
- int ERROR_ESRCH = 3; // Likely fingerprint HAL is dead. see errno.h.
- int authenticate(long operationId, int groupId) throws RemoteException;
- int cancel() throws RemoteException;
- int remove(int groupId, int biometricId) throws RemoteException;
- int enumerate() throws RemoteException;
- int enroll(byte[] cryptoToken, int groupId, int timeout) throws RemoteException;
- }
-
- /**
- * Handler which all subclasses should post events to.
- */
- protected final class H extends Handler {
- @Override
- public void handleMessage(android.os.Message msg) {
- switch (msg.what) {
- case MSG_USER_SWITCHING:
- handleUserSwitching(msg.arg1);
- break;
-
- default:
- Slog.w(getTag(), "Unknown message:" + msg.what);
- }
- }
- }
-
- private final class BiometricTaskStackListener extends TaskStackListener {
- @Override
- public void onTaskStackChanged() {
- try {
- if (!(mCurrentClient instanceof AuthenticationClient)) {
- return;
+ try {
+ // No polymorphism :(
+ if (mCurrentModality == BIOMETRIC_FINGERPRINT) {
+ mFingerprintService.authenticateFromService(token, sessionId, userId,
+ receiver, flags, opPackageName, bundle, dialogReceiver,
+ callingUid, callingPid, callingUserId);
+ } else if (mCurrentModality == BIOMETRIC_IRIS) {
+ Slog.w(TAG, "Unsupported modality");
+ } else if (mCurrentModality == BIOMETRIC_FACE) {
+ mFaceService.authenticateFromService(true /* requireConfirmation */, token,
+ sessionId, userId, receiver, flags, opPackageName, bundle,
+ dialogReceiver, callingUid, callingPid, callingUserId);
+ } else {
+ Slog.w(TAG, "Unsupported modality");
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to start authentication", e);
}
- final String currentClient = mCurrentClient.getOwnerString();
- if (isKeyguard(currentClient)) {
- return; // Keyguard is always allowed
+ });
+ }
+
+ @Override // Binder call
+ public void cancelAuthentication(IBinder token, String opPackageName)
+ throws RemoteException {
+ checkPermission();
+
+ if (token == null || opPackageName == null) {
+ Slog.e(TAG, "Unable to cancel, one or more null arguments");
+ return;
+ }
+
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int callingUserId = UserHandle.getCallingUserId();
+
+ mHandler.post(() -> {
+ try {
+ if (mCurrentModality == BIOMETRIC_FINGERPRINT) {
+ mFingerprintService.cancelAuthenticationFromService(token, opPackageName,
+ callingUid, callingPid, callingUserId);
+ } else if (mCurrentModality == BIOMETRIC_IRIS) {
+ Slog.w(TAG, "Unsupported modality");
+ } else if (mCurrentModality == BIOMETRIC_FACE) {
+ mFaceService.cancelAuthenticationFromService(token, opPackageName,
+ callingUid, callingPid, callingUserId);
+ } else {
+ Slog.w(TAG, "Unsupported modality");
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to cancel authentication");
}
- List<ActivityManager.RunningTaskInfo> runningTasks =
- mActivityTaskManager.getTasks(1);
- if (!runningTasks.isEmpty()) {
- final String topPackage = runningTasks.get(0).topActivity.getPackageName();
- if (!topPackage.contentEquals(currentClient)) {
- Slog.e(getTag(), "Stopping background authentication, top: " + topPackage
- + " currentClient: " + currentClient);
- mCurrentClient.stop(false /* initiatedByClient */);
+ });
+ }
+
+ @Override // Binder call
+ public boolean hasEnrolledBiometrics() {
+ checkPermission();
+
+ boolean hasEnrolled = false;
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ // Note: On devices with multi-modal authentication, the selection logic will need to
+ // be updated.
+ for (int i = 0; i < mAuthenticators.size(); i++) {
+ if (mAuthenticators.get(i).getAuthenticator().hasEnrolledTemplates()) {
+ hasEnrolled = true;
+ break;
}
}
- } catch (RemoteException e) {
- Slog.e(getTag(), "Unable to get running tasks", e);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
+ return hasEnrolled;
}
}
- private final class ResetClientStateRunnable implements Runnable {
- @Override
- public void run() {
- /**
- * Warning: if we get here, the driver never confirmed our call to cancel the current
- * operation (authenticate, enroll, remove, enumerate, etc), which is
- * really bad. The result will be a 3-second delay in starting each new client.
- * If you see this on a device, make certain the driver notifies with
- * {@link BiometricConstants#BIOMETRIC_ERROR_CANCELED} in response to cancel()
- * once it has successfully switched to the IDLE state in the HAL.
- * Additionally,{@link BiometricConstants#BIOMETRIC_ERROR_CANCELED} should only be sent
- * in response to an actual cancel() call.
- */
- Slog.w(getTag(), "Client "
- + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null")
- + " failed to respond to cancel, starting client "
- + (mPendingClient != null ? mPendingClient.getOwnerString() : "null"));
-
- mCurrentClient = null;
- startClient(mPendingClient, false);
- }
- }
-
- private final class LockoutReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Slog.v(getTag(), "Resetting lockout: " + intent.getAction());
- if (getLockoutResetIntent().equals(intent.getAction())) {
- final int user = intent.getIntExtra(KEY_LOCKOUT_RESET_USER, 0);
- resetFailedAttemptsForUser(false /* clearAttemptCounter */, user);
- }
- }
- }
-
- private final class ResetFailedAttemptsForUserRunnable implements Runnable {
- @Override
- public void run() {
- resetFailedAttemptsForUser(true /* clearAttemptCounter */,
- ActivityManager.getCurrentUser());
- }
- }
-
- private final class LockoutResetMonitor implements IBinder.DeathRecipient {
- private static final long WAKELOCK_TIMEOUT_MS = 2000;
- private final IBiometricServiceLockoutResetCallback mCallback;
- private final PowerManager.WakeLock mWakeLock;
-
- public LockoutResetMonitor(IBiometricServiceLockoutResetCallback callback) {
- mCallback = callback;
- mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
- "lockout reset callback");
- try {
- mCallback.asBinder().linkToDeath(LockoutResetMonitor.this, 0);
- } catch (RemoteException e) {
- Slog.w(getTag(), "caught remote exception in linkToDeath", e);
- }
- }
-
- public void sendLockoutReset() {
- if (mCallback != null) {
- try {
- mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
- mCallback.onLockoutReset(getHalDeviceId(), new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle data) throws RemoteException {
- releaseWakelock();
- }
- });
- } catch (DeadObjectException e) {
- Slog.w(getTag(), "Death object while invoking onLockoutReset: ", e);
- mHandler.post(mRemoveCallbackRunnable);
- } catch (RemoteException e) {
- Slog.w(getTag(), "Failed to invoke onLockoutReset: ", e);
- releaseWakelock();
- }
- }
- }
-
- private final Runnable mRemoveCallbackRunnable = new Runnable() {
- @Override
- public void run() {
- releaseWakelock();
- removeLockoutResetCallback(LockoutResetMonitor.this);
- }
- };
-
- @Override
- public void binderDied() {
- Slog.e(getTag(), "Lockout reset callback binder died");
- mHandler.post(mRemoveCallbackRunnable);
- }
-
- private void releaseWakelock() {
- if (mWakeLock.isHeld()) {
- mWakeLock.release();
- }
+ private void checkPermission() {
+ if (getContext().checkCallingPermission(USE_FINGERPRINT)
+ != PackageManager.PERMISSION_GRANTED) {
+ getContext().enforceCallingPermission(USE_BIOMETRIC,
+ "Must have USE_BIOMETRIC permission");
}
}
@@ -527,589 +240,129 @@
*/
public BiometricService(Context context) {
super(context);
- mContext = context;
- mStatusBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
- mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
- com.android.internal.R.string.config_keyguardComponent)).getPackageName();
- mAppOps = context.getSystemService(AppOpsManager.class);
- mTimedLockoutCleared = new SparseBooleanArray();
- mFailedAttempts = new SparseIntArray();
- mActivityTaskManager = ((ActivityTaskManager) context.getSystemService(
- Context.ACTIVITY_TASK_SERVICE)).getService();
- mPowerManager = mContext.getSystemService(PowerManager.class);
- mAlarmManager = mContext.getSystemService(AlarmManager.class);
- mUserManager = UserManager.get(mContext);
- mMetricsLogger = new MetricsLogger();
- mContext.registerReceiver(mLockoutReceiver, new IntentFilter(getLockoutResetIntent()),
- getLockoutBroadcastPermission(), null /* handler */);
+
+ mHandler = new Handler(Looper.getMainLooper());
+
+ final PackageManager pm = context.getPackageManager();
+ mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
+ mHasFeatureIris = pm.hasSystemFeature(PackageManager.FEATURE_IRIS);
+ mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
}
@Override
public void onStart() {
- listenForUserSwitches();
- }
+ // TODO: maybe get these on-demand
+ if (mHasFeatureFingerprint) {
+ mFingerprintService = IFingerprintService.Stub.asInterface(
+ ServiceManager.getService(Context.FINGERPRINT_SERVICE));
+ }
+ if (mHasFeatureFace) {
+ mFaceService = IFaceService.Stub.asInterface(
+ ServiceManager.getService(Context.FACE_SERVICE));
+ }
- @Override
- public void serviceDied(long cookie) {
- Slog.e(getTag(), "HAL died");
- mMetricsLogger.count(getMetrics().tagHalDied(), 1);
- handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
- 0 /*vendorCode */);
- }
+ // Cache the authenticators
+ for (int i = 0; i < FEATURE_ID.length; i++) {
+ if (hasFeature(FEATURE_ID[i])) {
+ Authenticator authenticator =
+ new Authenticator(FEATURE_ID[i], getAuthenticator(FEATURE_ID[i]));
+ mAuthenticators.add(authenticator);
+ }
+ }
- protected ClientMonitor getCurrentClient() {
- return mCurrentClient;
- }
-
- protected ClientMonitor getPendingClient() {
- return mPendingClient;
+ publishBinderService(Context.BIOMETRIC_SERVICE, new BiometricPromptServiceWrapper());
}
/**
- * Callback handlers from the daemon. The caller must put this on a handler.
+ * Checks if there are any available biometrics, and returns the modality. This method also
+ * returns errors through the callback (no biometric feature, hardware not detected, no
+ * templates enrolled, etc). This service must not start authentication if errors are sent.
*/
+ private int checkAndGetBiometricModality(IBiometricServiceReceiver receiver) {
+ int modality = BIOMETRIC_NONE;
+ final String hardwareUnavailable =
+ getContext().getString(R.string.biometric_error_hw_unavailable);
- protected void handleAcquired(long deviceId, int acquiredInfo, int vendorCode) {
- ClientMonitor client = mCurrentClient;
- if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
- removeClient(client);
- }
- if (mPerformanceStats != null && getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
- && client instanceof AuthenticationClient) {
- // ignore enrollment acquisitions or acquisitions when we're locked out
- mPerformanceStats.acquire++;
- }
- }
-
- protected void handleAuthenticated(BiometricAuthenticator.Identifier identifier,
- ArrayList<Byte> token) {
- ClientMonitor client = mCurrentClient;
- final boolean authenticated = identifier.getBiometricId() != 0;
-
- if (authenticated) {
- final byte[] byteToken = new byte[token.size()];
- for (int i = 0; i < token.size(); i++) {
- byteToken[i] = token.get(i);
+ // No biometric features, send error
+ if (mAuthenticators.isEmpty()) {
+ try {
+ receiver.onError(0 /* deviceId */,
+ BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT,
+ hardwareUnavailable);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to send error", e);
}
- KeyStore.getInstance().addAuthToken(byteToken);
- }
- if (client != null && client.onAuthenticated(identifier, authenticated)) {
- removeClient(client);
- }
- if (authenticated) {
- mPerformanceStats.accept++;
- } else {
- mPerformanceStats.reject++;
- }
- }
-
- protected void handleEnrollResult(BiometricAuthenticator.Identifier identifier,
- int remaining) {
- ClientMonitor client = mCurrentClient;
- if (client != null && client.onEnrollResult(identifier, remaining)) {
- removeClient(client);
- // When enrollment finishes, update this group's authenticator id, as the HAL has
- // already generated a new authenticator id when the new biometric is enrolled.
- if (identifier instanceof Fingerprint) {
- updateActiveGroup(((Fingerprint)identifier).getGroupId(), null);
- } else {
- updateActiveGroup(mCurrentUserId, null);
- }
-
- }
- }
-
- protected void handleError(long deviceId, int error, int vendorCode) {
- final ClientMonitor client = mCurrentClient;
-
- if (DEBUG) Slog.v(getTag(), "handleError(client="
- + (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
-
- if (client != null && client.onError(deviceId, error, vendorCode)) {
- removeClient(client);
+ return BIOMETRIC_NONE;
}
- if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
- mHandler.removeCallbacks(mResetClientState);
- if (mPendingClient != null) {
- if (DEBUG) Slog.v(getTag(), "start pending client " + mPendingClient.getOwnerString());
- startClient(mPendingClient, false);
- mPendingClient = null;
- }
- }
- }
-
- protected void handleRemoved(BiometricAuthenticator.Identifier identifier,
- final int remaining) {
- if (DEBUG) Slog.w(getTag(), "Removed: fid=" + identifier.getBiometricId()
- + ", dev=" + identifier.getDeviceId()
- + ", rem=" + remaining);
-
- ClientMonitor client = mCurrentClient;
- if (client != null && client.onRemoved(identifier, remaining)) {
- removeClient(client);
- // When the last biometric of a group is removed, update the authenticator id
- int userId = mCurrentUserId;
- if (identifier instanceof Fingerprint) {
- userId = ((Fingerprint) identifier).getGroupId();
- }
- if (!hasEnrolledBiometrics(userId)) {
- updateActiveGroup(userId, null);
- }
- }
- }
-
- /**
- * Calls from the Manager. These are still on the calling binder's thread.
- */
-
- protected void enrollInternal(EnrollClientImpl client, int userId) {
- if (hasReachedEnrollmentLimit(userId)) {
- return;
- }
-
- // Group ID is arbitrarily set to parent profile user ID. It just represents
- // the default biometrics for the user.
- if (!isCurrentUserOrProfile(userId)) {
- return;
- }
-
- mHandler.post(() -> {
- startClient(client, true /* initiatedByClient */);
- });
- }
-
- protected void cancelEnrollmentInternal(IBinder token) {
- mHandler.post(() -> {
- ClientMonitor client = mCurrentClient;
- if (client instanceof EnrollClient && client.getToken() == token) {
- client.stop(client.getToken() == token);
- }
- });
- }
-
- protected void authenticateInternal(AuthenticationClientImpl client, long opId,
- String opPackageName) {
- final int callingUid = Binder.getCallingUid();
- final int callingPid = Binder.getCallingPid();
- final int callingUserId = UserHandle.getCallingUserId();
- authenticateInternal(client, opId, opPackageName, callingUid, callingPid, callingUserId);
- }
-
- protected void authenticateInternal(AuthenticationClientImpl client, long opId,
- String opPackageName, int callingUid, int callingPid, int callingUserId) {
- if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
- callingUserId)) {
- if (DEBUG) Slog.v(getTag(), "authenticate(): reject " + opPackageName);
- return;
- }
-
- mHandler.post(() -> {
- mMetricsLogger.histogram(getMetrics().tagAuthToken(), opId != 0L ? 1 : 0);
-
- // Get performance stats object for this user.
- HashMap<Integer, PerformanceStats> pmap
- = (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap;
- PerformanceStats stats = pmap.get(mCurrentUserId);
- if (stats == null) {
- stats = new PerformanceStats();
- pmap.put(mCurrentUserId, stats);
- }
- mPerformanceStats = stats;
- mIsCrypto = (opId != 0);
-
- startAuthentication(client, opPackageName);
- });
- }
-
- protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName) {
- final int callingUid = Binder.getCallingUid();
- final int callingPid = Binder.getCallingPid();
- final int callingUserId = UserHandle.getCallingUserId();
- cancelAuthenticationInternal(token, opPackageName, callingUid, callingPid, callingUserId);
- }
-
- protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName,
- int callingUid, int callingPid, int callingUserId) {
- if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
- callingUserId)) {
- if (DEBUG) Slog.v(getTag(), "cancelAuthentication(): reject " + opPackageName);
- return;
- }
-
- mHandler.post(() -> {
- ClientMonitor client = mCurrentClient;
- if (client instanceof AuthenticationClient) {
- if (client.getToken() == token) {
- if (DEBUG) Slog.v(getTag(), "stop client " + client.getOwnerString());
- client.stop(client.getToken() == token);
- } else {
- if (DEBUG) Slog.v(getTag(), "can't stop client "
- + client.getOwnerString() + " since tokens don't match");
- }
- } else if (client != null) {
- if (DEBUG) Slog.v(getTag(), "can't cancel non-authenticating client "
- + client.getOwnerString());
- }
- });
- }
-
- protected void setActiveUserInternal(int userId) {
- mHandler.post(() -> {
- updateActiveGroup(userId, null /* clientPackage */);
- });
- }
-
- protected void removeInternal(RemovalClientImpl client) {
- mHandler.post(() -> {
- startClient(client, true /* initiatedByClient */);
- });
- }
-
- protected void enumerateInternal(EnumerateClientImpl client) {
- mHandler.post(() -> {
- startClient(client, true /* initiatedByClient */);
- });
- }
-
- // Should be done on a handler thread - not on the Binder's thread.
- private void startAuthentication(AuthenticationClientImpl client, String opPackageName) {
- updateActiveGroup(client.getGroupId(), opPackageName);
-
- if (DEBUG) Slog.v(getTag(), "startAuthentication(" + opPackageName + ")");
-
- int lockoutMode = getLockoutMode();
- if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
- Slog.v(getTag(), "In lockout mode(" + lockoutMode +
- ") ; disallowing authentication");
- int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?
- BiometricConstants.BIOMETRIC_ERROR_LOCKOUT :
- BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
- if (!client.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */)) {
- Slog.w(getTag(), "Cannot send permanent lockout message to client");
- }
- return;
- }
- startClient(client, true /* initiatedByClient */);
- }
-
- protected void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback) {
- mHandler.post(() -> {
- final LockoutResetMonitor monitor = new LockoutResetMonitor(callback);
- if (!mLockoutMonitors.contains(monitor)) {
- mLockoutMonitors.add(monitor);
- }
- });
- }
-
- /**
- * Helper methods.
- */
-
- /**
- * @param opPackageName name of package for caller
- * @param requireForeground only allow this call while app is in the foreground
- * @return true if caller can use the biometric API
- */
- protected boolean canUseBiometric(String opPackageName, boolean requireForeground, int uid,
- int pid, int userId) {
- checkUseBiometricPermission();
-
- if (isKeyguard(opPackageName)) {
- return true; // Keyguard is always allowed
- }
- if (!isCurrentUserOrProfile(userId)) {
- Slog.w(getTag(), "Rejecting " + opPackageName + "; not a current user or profile");
- return false;
- }
- if (mAppOps.noteOp(getAppOp(), uid, opPackageName) != AppOpsManager.MODE_ALLOWED) {
- Slog.w(getTag(), "Rejecting " + opPackageName + "; permission denied");
- return false;
- }
- if (requireForeground && !(isForegroundActivity(uid, pid) || isCurrentClient(
- opPackageName))) {
- Slog.w(getTag(), "Rejecting " + opPackageName + "; not in foreground");
- return false;
- }
- return true;
- }
-
- /**
- * @param opPackageName package of the caller
- * @return true if this is the same client currently using the biometric
- */
- private boolean isCurrentClient(String opPackageName) {
- return mCurrentClient != null && mCurrentClient.getOwnerString().equals(opPackageName);
- }
-
- /**
- * @return true if this is keyguard package
- */
- private boolean isKeyguard(String clientPackage) {
- return mKeyguardPackage.equals(clientPackage);
- }
-
- protected int getLockoutMode() {
- final int currentUser = ActivityManager.getCurrentUser();
- final int failedAttempts = mFailedAttempts.get(currentUser, 0);
- if (failedAttempts >= getFailedAttemptsLockoutPermanent()) {
- return AuthenticationClient.LOCKOUT_PERMANENT;
- } else if (failedAttempts > 0 &&
- mTimedLockoutCleared.get(currentUser, false) == false
- && (failedAttempts % getFailedAttemptsLockoutTimed() == 0)) {
- return AuthenticationClient.LOCKOUT_TIMED;
- }
- return AuthenticationClient.LOCKOUT_NONE;
- }
-
- private boolean isForegroundActivity(int uid, int pid) {
- try {
- List<ActivityManager.RunningAppProcessInfo> procs =
- ActivityManager.getService().getRunningAppProcesses();
- int N = procs.size();
- for (int i = 0; i < N; i++) {
- ActivityManager.RunningAppProcessInfo proc = procs.get(i);
- if (proc.pid == pid && proc.uid == uid
- && proc.importance <= IMPORTANCE_FOREGROUND_SERVICE) {
- return true;
+ // Find first authenticator that's both detected and enrolled
+ boolean isHardwareDetected = false;
+ boolean hasTemplatesEnrolled = false;
+ for (int i = 0; i < mAuthenticators.size(); i++) {
+ int featureId = mAuthenticators.get(i).getType();
+ BiometricAuthenticator authenticator = mAuthenticators.get(i).getAuthenticator();
+ if (authenticator.isHardwareDetected()) {
+ isHardwareDetected = true;
+ if (authenticator.hasEnrolledTemplates()) {
+ hasTemplatesEnrolled = true;
+ modality = featureId;
+ break;
}
}
- } catch (RemoteException e) {
- Slog.w(getTag(), "am.getRunningAppProcesses() failed");
}
- return false;
- }
- /**
- * Calls the HAL to switch states to the new task. If there's already a current task,
- * it calls cancel() and sets mPendingClient to begin when the current task finishes
- * ({@link BiometricConstants#BIOMETRIC_ERROR_CANCELED}).
- *
- * @param newClient the new client that wants to connect
- * @param initiatedByClient true for authenticate, remove and enroll
- */
- private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
- ClientMonitor currentClient = mCurrentClient;
- if (currentClient != null) {
- if (DEBUG) Slog.v(getTag(), "request stop current client " +
- currentClient.getOwnerString());
-
- // This check only matters for FingerprintService, since enumerate may call back
- // multiple times.
- if (currentClient instanceof FingerprintService.EnumerateClientImpl ||
- currentClient instanceof FingerprintService.RemovalClientImpl) {
- // This condition means we're currently running internal diagnostics to
- // remove extra fingerprints in the hardware and/or the software
- // TODO: design an escape hatch in case client never finishes
- if (newClient != null) {
- Slog.w(getTag(), "Internal cleanup in progress but trying to start client "
- + newClient.getClass().getSuperclass().getSimpleName()
- + "(" + newClient.getOwnerString() + ")"
- + ", initiatedByClient = " + initiatedByClient);
- }
- } else {
- currentClient.stop(initiatedByClient);
+ // Check error conditions
+ if (!isHardwareDetected) {
+ try {
+ receiver.onError(0 /* deviceId */,
+ BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ hardwareUnavailable);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to send error", e);
}
- mPendingClient = newClient;
- mHandler.removeCallbacks(mResetClientState);
- mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
- } else if (newClient != null) {
- mCurrentClient = newClient;
- if (DEBUG) Slog.v(getTag(), "starting client "
- + newClient.getClass().getSuperclass().getSimpleName()
- + "(" + newClient.getOwnerString() + ")"
- + ", initiatedByClient = " + initiatedByClient);
- notifyClientActiveCallbacks(true);
-
- newClient.start();
+ return BIOMETRIC_NONE;
}
- }
-
- protected void removeClient(ClientMonitor client) {
- if (client != null) {
- client.destroy();
- if (client != mCurrentClient && mCurrentClient != null) {
- Slog.w(getTag(), "Unexpected client: " + client.getOwnerString() + "expected: "
- + mCurrentClient.getOwnerString());
+ if (!hasTemplatesEnrolled) {
+ try {
+ receiver.onError(0 /* deviceId */,
+ BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS,
+ FaceManager.getErrorString(getContext(),
+ BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS,
+ 0 /* vendorCode */));
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to send error", e);
}
+ return BIOMETRIC_NONE;
}
- if (mCurrentClient != null) {
- if (DEBUG) Slog.v(getTag(), "Done with client: " + client.getOwnerString());
- mCurrentClient = null;
- }
- if (mPendingClient == null) {
- notifyClientActiveCallbacks(false);
+
+ return modality;
+ }
+
+ private BiometricAuthenticator getAuthenticator(int type) {
+ switch (type) {
+ case BIOMETRIC_FINGERPRINT:
+ return (FingerprintManager)
+ getContext().getSystemService(Context.FINGERPRINT_SERVICE);
+ case BIOMETRIC_IRIS:
+ return null;
+ case BIOMETRIC_FACE:
+ return (FaceManager)
+ getContext().getSystemService(Context.FACE_SERVICE);
+ default:
+ return null;
}
}
- /**
- * Populates existing authenticator ids. To be used only during the start of the service.
- */
- protected void loadAuthenticatorIds() {
- // This operation can be expensive, so keep track of the elapsed time. Might need to move to
- // background if it takes too long.
- long t = System.currentTimeMillis();
- mAuthenticatorIds.clear();
- for (UserInfo user : UserManager.get(getContext()).getUsers(true /* excludeDying */)) {
- int userId = getUserOrWorkProfileId(null, user.id);
- if (!mAuthenticatorIds.containsKey(userId)) {
- updateActiveGroup(userId, null);
- }
+ private boolean hasFeature(int type) {
+ switch (type) {
+ case BIOMETRIC_FINGERPRINT:
+ return mHasFeatureFingerprint;
+ case BIOMETRIC_IRIS:
+ return mHasFeatureIris;
+ case BIOMETRIC_FACE:
+ return mHasFeatureFace;
+ default:
+ return false;
}
-
- t = System.currentTimeMillis() - t;
- if (t > 1000) {
- Slog.w(getTag(), "loadAuthenticatorIds() taking too long: " + t + "ms");
- }
- }
-
- /**
- * @param clientPackage the package of the caller
- * @return the profile id
- */
- protected int getUserOrWorkProfileId(String clientPackage, int userId) {
- if (!isKeyguard(clientPackage) && isWorkProfile(userId)) {
- return userId;
- }
- return getEffectiveUserId(userId);
- }
-
- protected boolean isRestricted() {
- // Only give privileged apps (like Settings) access to biometric info
- final boolean restricted = !hasPermission(getManageBiometricPermission());
- return restricted;
- }
-
- protected boolean hasPermission(String permission) {
- return getContext().checkCallingOrSelfPermission(permission)
- == PackageManager.PERMISSION_GRANTED;
- }
-
- protected void checkPermission(String permission) {
- getContext().enforceCallingOrSelfPermission(permission,
- "Must have " + permission + " permission.");
- }
-
- protected boolean isCurrentUserOrProfile(int userId) {
- UserManager um = UserManager.get(mContext);
- if (um == null) {
- Slog.e(getTag(), "Unable to acquire UserManager");
- return false;
- }
-
- final long token = Binder.clearCallingIdentity();
- try {
- // Allow current user or profiles of the current user...
- for (int profileId : um.getEnabledProfileIds(ActivityManager.getCurrentUser())) {
- if (profileId == userId) {
- return true;
- }
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
-
- return false;
- }
-
- /***
- * @param opPackageName the name of the calling package
- * @return authenticator id for the calling user
- */
- protected long getAuthenticatorId(String opPackageName) {
- final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
- return mAuthenticatorIds.getOrDefault(userId, 0L);
- }
-
- private void scheduleLockoutResetForUser(int userId) {
- mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS,
- getLockoutResetIntentForUser(userId));
- }
-
- private PendingIntent getLockoutResetIntentForUser(int userId) {
- return PendingIntent.getBroadcast(mContext, userId,
- new Intent(getLockoutResetIntent()).putExtra(KEY_LOCKOUT_RESET_USER, userId),
- PendingIntent.FLAG_UPDATE_CURRENT);
- }
-
- private void userActivity() {
- long now = SystemClock.uptimeMillis();
- mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
- }
-
- /**
- * @param userId
- * @return true if this is a work profile
- */
- private boolean isWorkProfile(int userId) {
- UserInfo userInfo = null;
- final long token = Binder.clearCallingIdentity();
- try {
- userInfo = mUserManager.getUserInfo(userId);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- return userInfo != null && userInfo.isManagedProfile();
- }
-
-
- private int getEffectiveUserId(int userId) {
- UserManager um = UserManager.get(mContext);
- if (um != null) {
- final long callingIdentity = Binder.clearCallingIdentity();
- userId = um.getCredentialOwnerProfile(userId);
- Binder.restoreCallingIdentity(callingIdentity);
- } else {
- Slog.e(getTag(), "Unable to acquire UserManager");
- }
- return userId;
- }
-
- // Attempt counter should only be cleared when Keyguard goes away or when
- // a biometric is successfully authenticated.
- private void resetFailedAttemptsForUser(boolean clearAttemptCounter, int userId) {
- if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
- Slog.v(getTag(), "Reset biometric lockout, clearAttemptCounter=" + clearAttemptCounter);
- }
- if (clearAttemptCounter) {
- mFailedAttempts.put(userId, 0);
- }
- mTimedLockoutCleared.put(userId, true);
- // If we're asked to reset failed attempts externally (i.e. from Keyguard),
- // the alarm might still be pending; remove it.
- cancelLockoutResetForUser(userId);
- notifyLockoutResetMonitors();
- }
-
- private void cancelLockoutResetForUser(int userId) {
- mAlarmManager.cancel(getLockoutResetIntentForUser(userId));
- }
-
- private void listenForUserSwitches() {
- try {
- ActivityManager.getService().registerUserSwitchObserver(
- new SynchronousUserSwitchObserver() {
- @Override
- public void onUserSwitching(int newUserId) throws RemoteException {
- mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
- .sendToTarget();
- }
- }, getTag());
- } catch (RemoteException e) {
- Slog.w(getTag(), "Failed to listen for user switching event" ,e);
- }
- }
-
- private void notifyLockoutResetMonitors() {
- for (int i = 0; i < mLockoutMonitors.size(); i++) {
- mLockoutMonitors.get(i).sendLockoutReset();
- }
- }
-
- private void removeLockoutResetCallback(
- LockoutResetMonitor monitor) {
- mLockoutMonitors.remove(monitor);
}
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
new file mode 100644
index 0000000..b3c7c19
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -0,0 +1,1114 @@
+/*
+ * 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.server.biometrics;
+
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.AlarmManager;
+import android.app.AppOpsManager;
+import android.app.IActivityTaskManager;
+import android.app.PendingIntent;
+import android.app.SynchronousUserSwitchObserver;
+import android.app.TaskStackListener;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.IBiometricPromptReceiver;
+import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.fingerprint.Fingerprint;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IHwBinder;
+import android.os.IRemoteCallback;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Slog;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.server.SystemService;
+import com.android.server.biometrics.fingerprint.FingerprintService;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Abstract base class containing all of the business logic for biometric services, e.g.
+ * Fingerprint, Face, Iris.
+ *
+ * @hide
+ */
+public abstract class BiometricServiceBase extends SystemService
+ implements IHwBinder.DeathRecipient {
+
+ protected static final boolean DEBUG = true;
+
+ private static final String KEY_LOCKOUT_RESET_USER = "lockout_reset_user";
+ private static final int MSG_USER_SWITCHING = 10;
+ private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30 * 1000;
+ private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
+
+ private final Context mContext;
+ private final String mKeyguardPackage;
+ private final AppOpsManager mAppOps;
+ private final SparseBooleanArray mTimedLockoutCleared;
+ private final SparseIntArray mFailedAttempts;
+ private final IActivityTaskManager mActivityTaskManager;
+ private final AlarmManager mAlarmManager;
+ private final PowerManager mPowerManager;
+ private final UserManager mUserManager;
+ private final MetricsLogger mMetricsLogger;
+ private final BiometricTaskStackListener mTaskStackListener = new BiometricTaskStackListener();
+ private final ResetClientStateRunnable mResetClientState = new ResetClientStateRunnable();
+ private final LockoutReceiver mLockoutReceiver = new LockoutReceiver();
+ private final ArrayList<LockoutResetMonitor> mLockoutMonitors = new ArrayList<>();
+
+ protected final IStatusBarService mStatusBarService;
+ protected final Map<Integer, Long> mAuthenticatorIds =
+ Collections.synchronizedMap(new HashMap<>());
+ protected final ResetFailedAttemptsForUserRunnable mResetFailedAttemptsForCurrentUserRunnable =
+ new ResetFailedAttemptsForUserRunnable();
+ protected final H mHandler = new H();
+
+ private ClientMonitor mCurrentClient;
+ private ClientMonitor mPendingClient;
+ private PerformanceStats mPerformanceStats;
+ protected int mCurrentUserId = UserHandle.USER_NULL;
+ // Tracks if the current authentication makes use of CryptoObjects.
+ protected boolean mIsCrypto;
+ // Normal authentications are tracked by mPerformanceMap.
+ protected HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
+ // Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
+ protected HashMap<Integer, PerformanceStats> mCryptoPerformanceMap = new HashMap<>();
+
+ protected class PerformanceStats {
+ public int accept; // number of accepted biometrics
+ public int reject; // number of rejected biometrics
+ public int acquire; // total number of acquisitions. Should be >= accept+reject due to poor
+ // image acquisition in some cases (too fast, too slow, dirty sensor, etc.)
+ public int lockout; // total number of lockouts
+ public int permanentLockout; // total number of permanent lockouts
+ }
+
+ /**
+ * @return the log tag.
+ */
+ protected abstract String getTag();
+
+ /**
+ * @return the biometric utilities for a specific implementation.
+ */
+ protected abstract BiometricUtils getBiometricUtils();
+
+ /**
+ * @return the number of failed attempts after which the user will be temporarily locked out
+ * from using the biometric. A strong auth (pin/pattern/pass) clears this counter.
+ */
+ protected abstract int getFailedAttemptsLockoutTimed();
+
+ /**
+ * @return the number of failed attempts after which the user will be permanently locked out
+ * from using the biometric. A strong auth (pin/pattern/pass) clears this counter.
+ */
+ protected abstract int getFailedAttemptsLockoutPermanent();
+
+ /**
+ * @return the metrics constants for a biometric implementation.
+ */
+ protected abstract Metrics getMetrics();
+
+ /**
+ * @param userId
+ * @return true if the enrollment limit has been reached.
+ */
+ protected abstract boolean hasReachedEnrollmentLimit(int userId);
+
+ /**
+ * Notifies the HAL that the user has changed.
+ * @param userId
+ * @param clientPackage
+ */
+ protected abstract void updateActiveGroup(int userId, String clientPackage);
+
+ /**
+ * @return The protected intent to reset lockout for a specific biometric.
+ */
+ protected abstract String getLockoutResetIntent();
+
+ /**
+ * @return The permission the sender is required to have in order for the lockout reset intent
+ * to be received by the BiometricService implementation.
+ */
+ protected abstract String getLockoutBroadcastPermission();
+
+ /**
+ * @return The HAL ID.
+ */
+ protected abstract long getHalDeviceId();
+
+ /**
+ * This method is called when the user switches. Implementations should probably notify the
+ * HAL.
+ * @param userId
+ */
+ protected abstract void handleUserSwitching(int userId);
+
+ /**
+ * @param userId
+ * @return Returns true if the user has any enrolled biometrics.
+ */
+ protected abstract boolean hasEnrolledBiometrics(int userId);
+
+ /**
+ * @return Returns the MANAGE_* permission string, which is required for enrollment, removal
+ * etc.
+ */
+ protected abstract String getManageBiometricPermission();
+
+ /**
+ * Checks if the caller has permission to use the biometric service - throws a SecurityException
+ * if not.
+ */
+ protected abstract void checkUseBiometricPermission();
+
+ /**
+ * @return Returns one of the {@link AppOpsManager} constants which pertains to the specific
+ * biometric service.
+ */
+ protected abstract int getAppOp();
+
+
+ /**
+ * Notifies clients of any change in the biometric state (active / idle). This is mainly for
+ * Fingerprint navigation gestures.
+ * @param isActive
+ */
+ protected void notifyClientActiveCallbacks(boolean isActive) {}
+
+ protected abstract class AuthenticationClientImpl extends AuthenticationClient {
+
+ public AuthenticationClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
+ IBinder token, ServiceListener listener, int targetUserId, int groupId, long opId,
+ boolean restricted, String owner, Bundle bundle,
+ IBiometricPromptReceiver dialogReceiver,
+ IStatusBarService statusBarService, boolean requireConfirmation) {
+ super(context, getMetrics(), daemon, halDeviceId, token, listener,
+ targetUserId, groupId, opId, restricted, owner, bundle, dialogReceiver,
+ statusBarService, requireConfirmation);
+ }
+
+ @Override
+ public void onStart() {
+ try {
+ mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Could not register task stack listener", e);
+ }
+ }
+
+ @Override
+ public void onStop() {
+ try {
+ mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Could not unregister task stack listener", e);
+ }
+ }
+
+ @Override
+ public void resetFailedAttempts() {
+ resetFailedAttemptsForUser(true /* clearAttemptCounter */,
+ ActivityManager.getCurrentUser());
+ }
+
+ @Override
+ public void notifyUserActivity() {
+ userActivity();
+ }
+
+ @Override
+ public int handleFailedAttempt() {
+ final int currentUser = ActivityManager.getCurrentUser();
+ mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
+ mTimedLockoutCleared.put(ActivityManager.getCurrentUser(), false);
+ final int lockoutMode = getLockoutMode();
+ if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
+ mPerformanceStats.permanentLockout++;
+ } else if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
+ mPerformanceStats.lockout++;
+ }
+
+ // Failing multiple times will continue to push out the lockout time
+ if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
+ scheduleLockoutResetForUser(currentUser);
+ return lockoutMode;
+ }
+ return AuthenticationClient.LOCKOUT_NONE;
+ }
+
+ @Override
+ public void onAuthenticationConfirmed() {
+ removeClient(mCurrentClient);
+ }
+ }
+
+ protected class EnrollClientImpl extends EnrollClient {
+
+ public EnrollClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
+ IBinder token, ServiceListener listener, int userId, int groupId,
+ byte[] cryptoToken, boolean restricted, String owner) {
+ super(context, getMetrics(), daemon, halDeviceId, token, listener,
+ userId, groupId, cryptoToken, restricted, owner, getBiometricUtils());
+ }
+
+ @Override
+ public void notifyUserActivity() {
+ userActivity();
+ }
+ }
+
+ protected class RemovalClientImpl extends RemovalClient {
+ private boolean mShouldNotify;
+
+ public RemovalClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
+ IBinder token, ServiceListener listener, int fingerId, int groupId, int userId,
+ boolean restricted, String owner) {
+ super(context, getMetrics(), daemon, halDeviceId, token, listener, fingerId, groupId,
+ userId, restricted, owner, getBiometricUtils());
+ }
+
+ public void setShouldNotifyUserActivity(boolean shouldNotify) {
+ mShouldNotify = shouldNotify;
+ }
+
+ @Override
+ public void notifyUserActivity() {
+ if (mShouldNotify) {
+ userActivity();
+ }
+ }
+ }
+
+ protected class EnumerateClientImpl extends EnumerateClient {
+
+ public EnumerateClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
+ IBinder token, ServiceListener listener, int groupId, int userId,
+ boolean restricted, String owner) {
+ super(context, getMetrics(), daemon, halDeviceId, token, listener, groupId, userId,
+ restricted, owner);
+ }
+
+ @Override
+ public void notifyUserActivity() {
+ userActivity();
+ }
+ }
+
+ /**
+ * Wraps the callback interface from Service -> Manager
+ */
+ protected interface ServiceListener {
+ default void onEnrollResult(BiometricAuthenticator.Identifier identifier,
+ int remaining) throws RemoteException {};
+
+ void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
+ throws RemoteException;
+
+ void onAuthenticationSucceeded(long deviceId,
+ BiometricAuthenticator.Identifier biometric, int userId)
+ throws RemoteException;
+
+ void onAuthenticationFailed(long deviceId)
+ throws RemoteException;
+
+ void onError(long deviceId, int error, int vendorCode)
+ throws RemoteException;
+
+ default void onRemoved(BiometricAuthenticator.Identifier identifier,
+ int remaining) throws RemoteException {};
+
+ default void onEnumerated(BiometricAuthenticator.Identifier identifier,
+ int remaining) throws RemoteException {};
+ }
+
+ /**
+ * Wraps a portion of the interface from Service -> Daemon that is used by the ClientMonitor
+ * subclasses.
+ */
+ protected interface DaemonWrapper {
+ int ERROR_ESRCH = 3; // Likely fingerprint HAL is dead. see errno.h.
+ int authenticate(long operationId, int groupId) throws RemoteException;
+ int cancel() throws RemoteException;
+ int remove(int groupId, int biometricId) throws RemoteException;
+ int enumerate() throws RemoteException;
+ int enroll(byte[] cryptoToken, int groupId, int timeout) throws RemoteException;
+ }
+
+ /**
+ * Handler which all subclasses should post events to.
+ */
+ protected final class H extends Handler {
+ @Override
+ public void handleMessage(android.os.Message msg) {
+ switch (msg.what) {
+ case MSG_USER_SWITCHING:
+ handleUserSwitching(msg.arg1);
+ break;
+
+ default:
+ Slog.w(getTag(), "Unknown message:" + msg.what);
+ }
+ }
+ }
+
+ private final class BiometricTaskStackListener extends TaskStackListener {
+ @Override
+ public void onTaskStackChanged() {
+ try {
+ if (!(mCurrentClient instanceof AuthenticationClient)) {
+ return;
+ }
+ final String currentClient = mCurrentClient.getOwnerString();
+ if (isKeyguard(currentClient)) {
+ return; // Keyguard is always allowed
+ }
+ List<ActivityManager.RunningTaskInfo> runningTasks =
+ mActivityTaskManager.getTasks(1);
+ if (!runningTasks.isEmpty()) {
+ final String topPackage = runningTasks.get(0).topActivity.getPackageName();
+ if (!topPackage.contentEquals(currentClient)) {
+ Slog.e(getTag(), "Stopping background authentication, top: " + topPackage
+ + " currentClient: " + currentClient);
+ mCurrentClient.stop(false /* initiatedByClient */);
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Unable to get running tasks", e);
+ }
+ }
+ }
+
+ private final class ResetClientStateRunnable implements Runnable {
+ @Override
+ public void run() {
+ /**
+ * Warning: if we get here, the driver never confirmed our call to cancel the current
+ * operation (authenticate, enroll, remove, enumerate, etc), which is
+ * really bad. The result will be a 3-second delay in starting each new client.
+ * If you see this on a device, make certain the driver notifies with
+ * {@link BiometricConstants#BIOMETRIC_ERROR_CANCELED} in response to cancel()
+ * once it has successfully switched to the IDLE state in the HAL.
+ * Additionally,{@link BiometricConstants#BIOMETRIC_ERROR_CANCELED} should only be sent
+ * in response to an actual cancel() call.
+ */
+ Slog.w(getTag(), "Client "
+ + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null")
+ + " failed to respond to cancel, starting client "
+ + (mPendingClient != null ? mPendingClient.getOwnerString() : "null"));
+
+ mCurrentClient = null;
+ startClient(mPendingClient, false);
+ }
+ }
+
+ private final class LockoutReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Slog.v(getTag(), "Resetting lockout: " + intent.getAction());
+ if (getLockoutResetIntent().equals(intent.getAction())) {
+ final int user = intent.getIntExtra(KEY_LOCKOUT_RESET_USER, 0);
+ resetFailedAttemptsForUser(false /* clearAttemptCounter */, user);
+ }
+ }
+ }
+
+ private final class ResetFailedAttemptsForUserRunnable implements Runnable {
+ @Override
+ public void run() {
+ resetFailedAttemptsForUser(true /* clearAttemptCounter */,
+ ActivityManager.getCurrentUser());
+ }
+ }
+
+ private final class LockoutResetMonitor implements IBinder.DeathRecipient {
+ private static final long WAKELOCK_TIMEOUT_MS = 2000;
+ private final IBiometricServiceLockoutResetCallback mCallback;
+ private final PowerManager.WakeLock mWakeLock;
+
+ public LockoutResetMonitor(IBiometricServiceLockoutResetCallback callback) {
+ mCallback = callback;
+ mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ "lockout reset callback");
+ try {
+ mCallback.asBinder().linkToDeath(LockoutResetMonitor.this, 0);
+ } catch (RemoteException e) {
+ Slog.w(getTag(), "caught remote exception in linkToDeath", e);
+ }
+ }
+
+ public void sendLockoutReset() {
+ if (mCallback != null) {
+ try {
+ mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
+ mCallback.onLockoutReset(getHalDeviceId(), new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ releaseWakelock();
+ }
+ });
+ } catch (DeadObjectException e) {
+ Slog.w(getTag(), "Death object while invoking onLockoutReset: ", e);
+ mHandler.post(mRemoveCallbackRunnable);
+ } catch (RemoteException e) {
+ Slog.w(getTag(), "Failed to invoke onLockoutReset: ", e);
+ releaseWakelock();
+ }
+ }
+ }
+
+ private final Runnable mRemoveCallbackRunnable = new Runnable() {
+ @Override
+ public void run() {
+ releaseWakelock();
+ removeLockoutResetCallback(LockoutResetMonitor.this);
+ }
+ };
+
+ @Override
+ public void binderDied() {
+ Slog.e(getTag(), "Lockout reset callback binder died");
+ mHandler.post(mRemoveCallbackRunnable);
+ }
+
+ private void releaseWakelock() {
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
+ }
+ }
+
+ /**
+ * Initializes the system service.
+ * <p>
+ * Subclasses must define a single argument constructor that accepts the context
+ * and passes it to super.
+ * </p>
+ *
+ * @param context The system server context.
+ */
+ public BiometricServiceBase(Context context) {
+ super(context);
+ mContext = context;
+ mStatusBarService = IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
+ com.android.internal.R.string.config_keyguardComponent)).getPackageName();
+ mAppOps = context.getSystemService(AppOpsManager.class);
+ mTimedLockoutCleared = new SparseBooleanArray();
+ mFailedAttempts = new SparseIntArray();
+ mActivityTaskManager = ((ActivityTaskManager) context.getSystemService(
+ Context.ACTIVITY_TASK_SERVICE)).getService();
+ mPowerManager = mContext.getSystemService(PowerManager.class);
+ mAlarmManager = mContext.getSystemService(AlarmManager.class);
+ mUserManager = UserManager.get(mContext);
+ mMetricsLogger = new MetricsLogger();
+ mContext.registerReceiver(mLockoutReceiver, new IntentFilter(getLockoutResetIntent()),
+ getLockoutBroadcastPermission(), null /* handler */);
+ }
+
+ @Override
+ public void onStart() {
+ listenForUserSwitches();
+ }
+
+ @Override
+ public void serviceDied(long cookie) {
+ Slog.e(getTag(), "HAL died");
+ mMetricsLogger.count(getMetrics().tagHalDied(), 1);
+ handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ 0 /*vendorCode */);
+ }
+
+ protected ClientMonitor getCurrentClient() {
+ return mCurrentClient;
+ }
+
+ protected ClientMonitor getPendingClient() {
+ return mPendingClient;
+ }
+
+ /**
+ * Callback handlers from the daemon. The caller must put this on a handler.
+ */
+
+ protected void handleAcquired(long deviceId, int acquiredInfo, int vendorCode) {
+ ClientMonitor client = mCurrentClient;
+ if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
+ removeClient(client);
+ }
+ if (mPerformanceStats != null && getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
+ && client instanceof AuthenticationClient) {
+ // ignore enrollment acquisitions or acquisitions when we're locked out
+ mPerformanceStats.acquire++;
+ }
+ }
+
+ protected void handleAuthenticated(BiometricAuthenticator.Identifier identifier,
+ ArrayList<Byte> token) {
+ ClientMonitor client = mCurrentClient;
+ final boolean authenticated = identifier.getBiometricId() != 0;
+
+ if (client != null && client.onAuthenticated(identifier, authenticated, token)) {
+ removeClient(client);
+ }
+ if (authenticated) {
+ mPerformanceStats.accept++;
+ } else {
+ mPerformanceStats.reject++;
+ }
+ }
+
+ protected void handleEnrollResult(BiometricAuthenticator.Identifier identifier,
+ int remaining) {
+ ClientMonitor client = mCurrentClient;
+ if (client != null && client.onEnrollResult(identifier, remaining)) {
+ removeClient(client);
+ // When enrollment finishes, update this group's authenticator id, as the HAL has
+ // already generated a new authenticator id when the new biometric is enrolled.
+ if (identifier instanceof Fingerprint) {
+ updateActiveGroup(((Fingerprint)identifier).getGroupId(), null);
+ } else {
+ updateActiveGroup(mCurrentUserId, null);
+ }
+
+ }
+ }
+
+ protected void handleError(long deviceId, int error, int vendorCode) {
+ final ClientMonitor client = mCurrentClient;
+
+ if (DEBUG) Slog.v(getTag(), "handleError(client="
+ + (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
+
+ if (client != null && client.onError(deviceId, error, vendorCode)) {
+ removeClient(client);
+ }
+
+ if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
+ mHandler.removeCallbacks(mResetClientState);
+ if (mPendingClient != null) {
+ if (DEBUG) Slog.v(getTag(), "start pending client " +
+ mPendingClient.getOwnerString());
+ startClient(mPendingClient, false);
+ mPendingClient = null;
+ }
+ }
+ }
+
+ protected void handleRemoved(BiometricAuthenticator.Identifier identifier,
+ final int remaining) {
+ if (DEBUG) Slog.w(getTag(), "Removed: fid=" + identifier.getBiometricId()
+ + ", dev=" + identifier.getDeviceId()
+ + ", rem=" + remaining);
+
+ ClientMonitor client = mCurrentClient;
+ if (client != null && client.onRemoved(identifier, remaining)) {
+ removeClient(client);
+ // When the last biometric of a group is removed, update the authenticator id
+ int userId = mCurrentUserId;
+ if (identifier instanceof Fingerprint) {
+ userId = ((Fingerprint) identifier).getGroupId();
+ }
+ if (!hasEnrolledBiometrics(userId)) {
+ updateActiveGroup(userId, null);
+ }
+ }
+ }
+
+ /**
+ * Calls from the Manager. These are still on the calling binder's thread.
+ */
+
+ protected void enrollInternal(EnrollClientImpl client, int userId) {
+ if (hasReachedEnrollmentLimit(userId)) {
+ return;
+ }
+
+ // Group ID is arbitrarily set to parent profile user ID. It just represents
+ // the default biometrics for the user.
+ if (!isCurrentUserOrProfile(userId)) {
+ return;
+ }
+
+ mHandler.post(() -> {
+ startClient(client, true /* initiatedByClient */);
+ });
+ }
+
+ protected void cancelEnrollmentInternal(IBinder token) {
+ mHandler.post(() -> {
+ ClientMonitor client = mCurrentClient;
+ if (client instanceof EnrollClient && client.getToken() == token) {
+ client.stop(client.getToken() == token);
+ }
+ });
+ }
+
+ protected void authenticateInternal(AuthenticationClientImpl client, long opId,
+ String opPackageName) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int callingUserId = UserHandle.getCallingUserId();
+ authenticateInternal(client, opId, opPackageName, callingUid, callingPid, callingUserId);
+ }
+
+ protected void authenticateInternal(AuthenticationClientImpl client, long opId,
+ String opPackageName, int callingUid, int callingPid, int callingUserId) {
+ if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
+ callingUserId)) {
+ if (DEBUG) Slog.v(getTag(), "authenticate(): reject " + opPackageName);
+ return;
+ }
+
+ mHandler.post(() -> {
+ mMetricsLogger.histogram(getMetrics().tagAuthToken(), opId != 0L ? 1 : 0);
+
+ // Get performance stats object for this user.
+ HashMap<Integer, PerformanceStats> pmap
+ = (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap;
+ PerformanceStats stats = pmap.get(mCurrentUserId);
+ if (stats == null) {
+ stats = new PerformanceStats();
+ pmap.put(mCurrentUserId, stats);
+ }
+ mPerformanceStats = stats;
+ mIsCrypto = (opId != 0);
+
+ startAuthentication(client, opPackageName);
+ });
+ }
+
+ protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int callingUserId = UserHandle.getCallingUserId();
+ cancelAuthenticationInternal(token, opPackageName, callingUid, callingPid, callingUserId);
+ }
+
+ protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName,
+ int callingUid, int callingPid, int callingUserId) {
+ if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
+ callingUserId)) {
+ if (DEBUG) Slog.v(getTag(), "cancelAuthentication(): reject " + opPackageName);
+ return;
+ }
+
+ mHandler.post(() -> {
+ ClientMonitor client = mCurrentClient;
+ if (client instanceof AuthenticationClient) {
+ if (client.getToken() == token) {
+ if (DEBUG) Slog.v(getTag(), "stop client " + client.getOwnerString());
+ client.stop(client.getToken() == token);
+ } else {
+ if (DEBUG) Slog.v(getTag(), "can't stop client "
+ + client.getOwnerString() + " since tokens don't match");
+ }
+ } else if (client != null) {
+ if (DEBUG) Slog.v(getTag(), "can't cancel non-authenticating client "
+ + client.getOwnerString());
+ }
+ });
+ }
+
+ protected void setActiveUserInternal(int userId) {
+ mHandler.post(() -> {
+ updateActiveGroup(userId, null /* clientPackage */);
+ });
+ }
+
+ protected void removeInternal(RemovalClientImpl client) {
+ mHandler.post(() -> {
+ startClient(client, true /* initiatedByClient */);
+ });
+ }
+
+ protected void enumerateInternal(EnumerateClientImpl client) {
+ mHandler.post(() -> {
+ startClient(client, true /* initiatedByClient */);
+ });
+ }
+
+ // Should be done on a handler thread - not on the Binder's thread.
+ private void startAuthentication(AuthenticationClientImpl client, String opPackageName) {
+ updateActiveGroup(client.getGroupId(), opPackageName);
+
+ if (DEBUG) Slog.v(getTag(), "startAuthentication(" + opPackageName + ")");
+
+ int lockoutMode = getLockoutMode();
+ if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
+ Slog.v(getTag(), "In lockout mode(" + lockoutMode +
+ ") ; disallowing authentication");
+ int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?
+ BiometricConstants.BIOMETRIC_ERROR_LOCKOUT :
+ BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
+ if (!client.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */)) {
+ Slog.w(getTag(), "Cannot send permanent lockout message to client");
+ }
+ return;
+ }
+ startClient(client, true /* initiatedByClient */);
+ }
+
+ protected void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback) {
+ mHandler.post(() -> {
+ final LockoutResetMonitor monitor = new LockoutResetMonitor(callback);
+ if (!mLockoutMonitors.contains(monitor)) {
+ mLockoutMonitors.add(monitor);
+ }
+ });
+ }
+
+ /**
+ * Helper methods.
+ */
+
+ /**
+ * @param opPackageName name of package for caller
+ * @param requireForeground only allow this call while app is in the foreground
+ * @return true if caller can use the biometric API
+ */
+ protected boolean canUseBiometric(String opPackageName, boolean requireForeground, int uid,
+ int pid, int userId) {
+ checkUseBiometricPermission();
+
+ if (isKeyguard(opPackageName)) {
+ return true; // Keyguard is always allowed
+ }
+ if (!isCurrentUserOrProfile(userId)) {
+ Slog.w(getTag(), "Rejecting " + opPackageName + "; not a current user or profile");
+ return false;
+ }
+ if (mAppOps.noteOp(getAppOp(), uid, opPackageName) != AppOpsManager.MODE_ALLOWED) {
+ Slog.w(getTag(), "Rejecting " + opPackageName + "; permission denied");
+ return false;
+ }
+ if (requireForeground && !(isForegroundActivity(uid, pid) || isCurrentClient(
+ opPackageName))) {
+ Slog.w(getTag(), "Rejecting " + opPackageName + "; not in foreground");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @param opPackageName package of the caller
+ * @return true if this is the same client currently using the biometric
+ */
+ private boolean isCurrentClient(String opPackageName) {
+ return mCurrentClient != null && mCurrentClient.getOwnerString().equals(opPackageName);
+ }
+
+ /**
+ * @return true if this is keyguard package
+ */
+ private boolean isKeyguard(String clientPackage) {
+ return mKeyguardPackage.equals(clientPackage);
+ }
+
+ protected int getLockoutMode() {
+ final int currentUser = ActivityManager.getCurrentUser();
+ final int failedAttempts = mFailedAttempts.get(currentUser, 0);
+ if (failedAttempts >= getFailedAttemptsLockoutPermanent()) {
+ return AuthenticationClient.LOCKOUT_PERMANENT;
+ } else if (failedAttempts > 0 &&
+ mTimedLockoutCleared.get(currentUser, false) == false
+ && (failedAttempts % getFailedAttemptsLockoutTimed() == 0)) {
+ return AuthenticationClient.LOCKOUT_TIMED;
+ }
+ return AuthenticationClient.LOCKOUT_NONE;
+ }
+
+ private boolean isForegroundActivity(int uid, int pid) {
+ try {
+ List<ActivityManager.RunningAppProcessInfo> procs =
+ ActivityManager.getService().getRunningAppProcesses();
+ int N = procs.size();
+ for (int i = 0; i < N; i++) {
+ ActivityManager.RunningAppProcessInfo proc = procs.get(i);
+ if (proc.pid == pid && proc.uid == uid
+ && proc.importance <= IMPORTANCE_FOREGROUND_SERVICE) {
+ return true;
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.w(getTag(), "am.getRunningAppProcesses() failed");
+ }
+ return false;
+ }
+
+ /**
+ * Calls the HAL to switch states to the new task. If there's already a current task,
+ * it calls cancel() and sets mPendingClient to begin when the current task finishes
+ * ({@link BiometricConstants#BIOMETRIC_ERROR_CANCELED}).
+ *
+ * @param newClient the new client that wants to connect
+ * @param initiatedByClient true for authenticate, remove and enroll
+ */
+ private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
+ ClientMonitor currentClient = mCurrentClient;
+ if (currentClient != null) {
+ if (DEBUG) Slog.v(getTag(), "request stop current client " +
+ currentClient.getOwnerString());
+
+ // This check only matters for FingerprintService, since enumerate may call back
+ // multiple times.
+ if (currentClient instanceof FingerprintService.EnumerateClientImpl ||
+ currentClient instanceof FingerprintService.RemovalClientImpl) {
+ // This condition means we're currently running internal diagnostics to
+ // remove extra fingerprints in the hardware and/or the software
+ // TODO: design an escape hatch in case client never finishes
+ if (newClient != null) {
+ Slog.w(getTag(), "Internal cleanup in progress but trying to start client "
+ + newClient.getClass().getSuperclass().getSimpleName()
+ + "(" + newClient.getOwnerString() + ")"
+ + ", initiatedByClient = " + initiatedByClient);
+ }
+ } else {
+ currentClient.stop(initiatedByClient);
+ }
+ mPendingClient = newClient;
+ mHandler.removeCallbacks(mResetClientState);
+ mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
+ } else if (newClient != null) {
+ mCurrentClient = newClient;
+ if (DEBUG) Slog.v(getTag(), "starting client "
+ + newClient.getClass().getSuperclass().getSimpleName()
+ + "(" + newClient.getOwnerString() + ")"
+ + ", initiatedByClient = " + initiatedByClient);
+ notifyClientActiveCallbacks(true);
+
+ newClient.start();
+ }
+ }
+
+ protected void removeClient(ClientMonitor client) {
+ if (client != null) {
+ client.destroy();
+ if (client != mCurrentClient && mCurrentClient != null) {
+ Slog.w(getTag(), "Unexpected client: " + client.getOwnerString() + "expected: "
+ + mCurrentClient.getOwnerString());
+ }
+ }
+ if (mCurrentClient != null) {
+ if (DEBUG) Slog.v(getTag(), "Done with client: " + client.getOwnerString());
+ mCurrentClient = null;
+ }
+ if (mPendingClient == null) {
+ notifyClientActiveCallbacks(false);
+ }
+ }
+
+ /**
+ * Populates existing authenticator ids. To be used only during the start of the service.
+ */
+ protected void loadAuthenticatorIds() {
+ // This operation can be expensive, so keep track of the elapsed time. Might need to move to
+ // background if it takes too long.
+ long t = System.currentTimeMillis();
+ mAuthenticatorIds.clear();
+ for (UserInfo user : UserManager.get(getContext()).getUsers(true /* excludeDying */)) {
+ int userId = getUserOrWorkProfileId(null, user.id);
+ if (!mAuthenticatorIds.containsKey(userId)) {
+ updateActiveGroup(userId, null);
+ }
+ }
+
+ t = System.currentTimeMillis() - t;
+ if (t > 1000) {
+ Slog.w(getTag(), "loadAuthenticatorIds() taking too long: " + t + "ms");
+ }
+ }
+
+ /**
+ * @param clientPackage the package of the caller
+ * @return the profile id
+ */
+ protected int getUserOrWorkProfileId(String clientPackage, int userId) {
+ if (!isKeyguard(clientPackage) && isWorkProfile(userId)) {
+ return userId;
+ }
+ return getEffectiveUserId(userId);
+ }
+
+ protected boolean isRestricted() {
+ // Only give privileged apps (like Settings) access to biometric info
+ final boolean restricted = !hasPermission(getManageBiometricPermission());
+ return restricted;
+ }
+
+ protected boolean hasPermission(String permission) {
+ return getContext().checkCallingOrSelfPermission(permission)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ protected void checkPermission(String permission) {
+ getContext().enforceCallingOrSelfPermission(permission,
+ "Must have " + permission + " permission.");
+ }
+
+ protected boolean isCurrentUserOrProfile(int userId) {
+ UserManager um = UserManager.get(mContext);
+ if (um == null) {
+ Slog.e(getTag(), "Unable to acquire UserManager");
+ return false;
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // Allow current user or profiles of the current user...
+ for (int profileId : um.getEnabledProfileIds(ActivityManager.getCurrentUser())) {
+ if (profileId == userId) {
+ return true;
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ return false;
+ }
+
+ /***
+ * @param opPackageName the name of the calling package
+ * @return authenticator id for the calling user
+ */
+ protected long getAuthenticatorId(String opPackageName) {
+ final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
+ return mAuthenticatorIds.getOrDefault(userId, 0L);
+ }
+
+ private void scheduleLockoutResetForUser(int userId) {
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS,
+ getLockoutResetIntentForUser(userId));
+ }
+
+ private PendingIntent getLockoutResetIntentForUser(int userId) {
+ return PendingIntent.getBroadcast(mContext, userId,
+ new Intent(getLockoutResetIntent()).putExtra(KEY_LOCKOUT_RESET_USER, userId),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+ private void userActivity() {
+ long now = SystemClock.uptimeMillis();
+ mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
+ }
+
+ /**
+ * @param userId
+ * @return true if this is a work profile
+ */
+ private boolean isWorkProfile(int userId) {
+ UserInfo userInfo = null;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ userInfo = mUserManager.getUserInfo(userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return userInfo != null && userInfo.isManagedProfile();
+ }
+
+
+ private int getEffectiveUserId(int userId) {
+ UserManager um = UserManager.get(mContext);
+ if (um != null) {
+ final long callingIdentity = Binder.clearCallingIdentity();
+ userId = um.getCredentialOwnerProfile(userId);
+ Binder.restoreCallingIdentity(callingIdentity);
+ } else {
+ Slog.e(getTag(), "Unable to acquire UserManager");
+ }
+ return userId;
+ }
+
+ // Attempt counter should only be cleared when Keyguard goes away or when
+ // a biometric is successfully authenticated.
+ private void resetFailedAttemptsForUser(boolean clearAttemptCounter, int userId) {
+ if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
+ Slog.v(getTag(), "Reset biometric lockout, clearAttemptCounter=" + clearAttemptCounter);
+ }
+ if (clearAttemptCounter) {
+ mFailedAttempts.put(userId, 0);
+ }
+ mTimedLockoutCleared.put(userId, true);
+ // If we're asked to reset failed attempts externally (i.e. from Keyguard),
+ // the alarm might still be pending; remove it.
+ cancelLockoutResetForUser(userId);
+ notifyLockoutResetMonitors();
+ }
+
+ private void cancelLockoutResetForUser(int userId) {
+ mAlarmManager.cancel(getLockoutResetIntentForUser(userId));
+ }
+
+ private void listenForUserSwitches() {
+ try {
+ ActivityManager.getService().registerUserSwitchObserver(
+ new SynchronousUserSwitchObserver() {
+ @Override
+ public void onUserSwitching(int newUserId) throws RemoteException {
+ mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
+ .sendToTarget();
+ }
+ }, getTag());
+ } catch (RemoteException e) {
+ Slog.w(getTag(), "Failed to listen for user switching event" ,e);
+ }
+ }
+
+ private void notifyLockoutResetMonitors() {
+ for (int i = 0; i < mLockoutMonitors.size(); i++) {
+ mLockoutMonitors.get(i).sendLockoutReset();
+ }
+ }
+
+ private void removeLockoutResetCallback(
+ LockoutResetMonitor monitor) {
+ mLockoutMonitors.remove(monitor);
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/ClientMonitor.java b/services/core/java/com/android/server/biometrics/ClientMonitor.java
index d30bed2..d1daad5 100644
--- a/services/core/java/com/android/server/biometrics/ClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/ClientMonitor.java
@@ -28,6 +28,7 @@
import com.android.internal.logging.MetricsLogger;
+import java.util.ArrayList;
import java.util.NoSuchElementException;
/**
@@ -37,7 +38,7 @@
*/
public abstract class ClientMonitor implements IBinder.DeathRecipient {
protected static final int ERROR_ESRCH = 3; // Likely HAL is dead. See errno.h.
- protected static final boolean DEBUG = BiometricService.DEBUG;
+ protected static final boolean DEBUG = BiometricServiceBase.DEBUG;
private static final AudioAttributes FINGERPRINT_SONFICATION_ATTRIBUTES =
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -53,10 +54,10 @@
private final String mOwner;
private final VibrationEffect mSuccessVibrationEffect;
private final VibrationEffect mErrorVibrationEffect;
- private final BiometricService.DaemonWrapper mDaemon;
+ private final BiometricServiceBase.DaemonWrapper mDaemon;
private IBinder mToken;
- private BiometricService.ServiceListener mListener;
+ private BiometricServiceBase.ServiceListener mListener;
protected final MetricsLogger mMetricsLogger;
protected final Metrics mMetrics;
@@ -75,9 +76,10 @@
* permission
* @param owner name of the client that owns this
*/
- public ClientMonitor(Context context, Metrics metrics, BiometricService.DaemonWrapper daemon,
- long halDeviceId, IBinder token, BiometricService.ServiceListener listener, int userId,
- int groupId, boolean restricted, String owner) {
+ public ClientMonitor(Context context, Metrics metrics,
+ BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
+ BiometricServiceBase.ServiceListener listener, int userId, int groupId,
+ boolean restricted, String owner) {
mContext = context;
mMetrics = metrics;
mDaemon = daemon;
@@ -128,7 +130,7 @@
public abstract boolean onEnrollResult(BiometricAuthenticator.Identifier identifier,
int remaining);
public abstract boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
- boolean authenticated);
+ boolean authenticated, ArrayList<Byte> token);
public abstract boolean onRemoved(BiometricAuthenticator.Identifier identifier,
int remaining);
public abstract boolean onEnumerationResult(
@@ -220,11 +222,11 @@
return mOwner;
}
- public final BiometricService.ServiceListener getListener() {
+ public final BiometricServiceBase.ServiceListener getListener() {
return mListener;
}
- public final BiometricService.DaemonWrapper getDaemonWrapper() {
+ public final BiometricServiceBase.DaemonWrapper getDaemonWrapper() {
return mDaemon;
}
diff --git a/services/core/java/com/android/server/biometrics/EnrollClient.java b/services/core/java/com/android/server/biometrics/EnrollClient.java
index c305eca6..76dc5a9 100644
--- a/services/core/java/com/android/server/biometrics/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/EnrollClient.java
@@ -23,6 +23,7 @@
import android.os.RemoteException;
import android.util.Slog;
+import java.util.ArrayList;
import java.util.Arrays;
/**
@@ -34,10 +35,10 @@
private final byte[] mCryptoToken;
private final BiometricUtils mBiometricUtils;
- public EnrollClient(Context context, Metrics metrics, BiometricService.DaemonWrapper daemon,
- long halDeviceId, IBinder token, BiometricService.ServiceListener listener, int userId,
- int groupId, byte[] cryptoToken, boolean restricted, String owner,
- BiometricUtils utils) {
+ public EnrollClient(Context context, Metrics metrics,
+ BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
+ BiometricServiceBase.ServiceListener listener, int userId, int groupId,
+ byte[] cryptoToken, boolean restricted, String owner, BiometricUtils utils) {
super(context, metrics, daemon, halDeviceId, token, listener, userId, groupId, restricted,
owner);
mBiometricUtils = utils;
@@ -126,7 +127,7 @@
@Override
public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
- boolean authenticated) {
+ boolean authenticated, ArrayList<Byte> token) {
if (DEBUG) Slog.w(getLogTag(), "onAuthenticated() called for enroll!");
return true; // Invalid for EnrollClient
}
diff --git a/services/core/java/com/android/server/biometrics/EnumerateClient.java b/services/core/java/com/android/server/biometrics/EnumerateClient.java
index b763769..47dc7ff 100644
--- a/services/core/java/com/android/server/biometrics/EnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/EnumerateClient.java
@@ -23,13 +23,16 @@
import android.os.RemoteException;
import android.util.Slog;
+import java.util.ArrayList;
+
/**
* A class to keep track of the enumeration state for a given client.
*/
public abstract class EnumerateClient extends ClientMonitor {
- public EnumerateClient(Context context, Metrics metrics, BiometricService.DaemonWrapper daemon,
- long halDeviceId, IBinder token, BiometricService.ServiceListener listener, int groupId,
- int userId, boolean restricted, String owner) {
+ public EnumerateClient(Context context, Metrics metrics,
+ BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
+ BiometricServiceBase.ServiceListener listener, int groupId, int userId,
+ boolean restricted, String owner) {
super(context, metrics, daemon, halDeviceId, token, listener, userId, groupId, restricted,
owner);
}
@@ -94,7 +97,7 @@
@Override
public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
- boolean authenticated) {
+ boolean authenticated, ArrayList<Byte> token) {
if (DEBUG) Slog.w(getLogTag(), "onAuthenticated() called for enumerate!");
return true; // Invalid for Enumerate.
}
diff --git a/services/core/java/com/android/server/biometrics/RemovalClient.java b/services/core/java/com/android/server/biometrics/RemovalClient.java
index 3bf7f04..15b3773 100644
--- a/services/core/java/com/android/server/biometrics/RemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/RemovalClient.java
@@ -23,6 +23,8 @@
import android.os.RemoteException;
import android.util.Slog;
+import java.util.ArrayList;
+
/**
* A class to keep track of the remove state for a given client.
*/
@@ -30,10 +32,10 @@
private final int mBiometricId;
private final BiometricUtils mBiometricUtils;
- public RemovalClient(Context context, Metrics metrics, BiometricService.DaemonWrapper daemon,
- long halDeviceId, IBinder token, BiometricService.ServiceListener listener,
- int biometricId, int groupId, int userId, boolean restricted, String owner,
- BiometricUtils utils) {
+ public RemovalClient(Context context, Metrics metrics,
+ BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
+ BiometricServiceBase.ServiceListener listener, int biometricId, int groupId, int userId,
+ boolean restricted, String owner, BiometricUtils utils) {
super(context, metrics, daemon, halDeviceId, token, listener, userId, groupId, restricted,
owner);
mBiometricId = biometricId;
@@ -111,7 +113,7 @@
@Override
public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
- boolean authenticated) {
+ boolean authenticated, ArrayList<Byte> token) {
if (DEBUG) Slog.w(getLogTag(), "onAuthenticated() called for remove!");
return true; // Invalid for Remove.
}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 660710e..75cdcf0 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -28,7 +28,7 @@
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.IBiometricPromptServiceReceiver;
+import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
@@ -52,7 +52,7 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemServerInitThreadPool;
-import com.android.server.biometrics.BiometricService;
+import com.android.server.biometrics.BiometricServiceBase;
import com.android.server.biometrics.BiometricUtils;
import com.android.server.biometrics.Metrics;
@@ -73,7 +73,7 @@
*
* @hide
*/
-public class FaceService extends BiometricService {
+public class FaceService extends BiometricServiceBase {
protected static final String TAG = "FaceService";
private static final boolean DEBUG = true;
@@ -88,10 +88,11 @@
DaemonWrapper daemon, long halDeviceId, IBinder token,
ServiceListener listener, int targetUserId, int groupId, long opId,
boolean restricted, String owner, Bundle bundle,
- IBiometricPromptReceiver dialogReceiver, IStatusBarService statusBarService) {
+ IBiometricPromptReceiver dialogReceiver, IStatusBarService statusBarService,
+ boolean requireConfirmation) {
super(context, daemon, halDeviceId, token, listener, targetUserId, groupId, opId,
- restricted,
- owner, bundle, dialogReceiver, statusBarService);
+ restricted, owner, bundle, dialogReceiver, statusBarService,
+ requireConfirmation);
}
@Override
@@ -159,15 +160,15 @@
final AuthenticationClientImpl client = new FaceAuthClient(getContext(),
mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName,
- null /* bundle */, null /* dialogReceiver */, mStatusBarService);
-
+ null /* bundle */, null /* dialogReceiver */, mStatusBarService,
+ false /* requireConfirmation */);
authenticateInternal(client, opId, opPackageName);
}
@Override // Binder call
- public void authenticateFromService(IBinder token, long opId, int groupId,
- IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
- Bundle bundle, IBiometricPromptReceiver dialogReceiver,
+ public void authenticateFromService(boolean requireConfirmation, IBinder token, long opId,
+ int groupId, IBiometricServiceReceiver receiver, int flags,
+ String opPackageName, Bundle bundle, IBiometricPromptReceiver dialogReceiver,
int callingUid, int callingPid, int callingUserId) {
checkPermission(USE_BIOMETRIC_INTERNAL);
final boolean restricted = true; // BiometricPrompt is always restricted
@@ -175,7 +176,7 @@
mDaemonWrapper, mHalDeviceId, token,
new BiometricPromptServiceListenerImpl(receiver),
mCurrentUserId, 0 /* groupId */, opId, restricted, opPackageName,
- bundle, dialogReceiver, mStatusBarService);
+ bundle, dialogReceiver, mStatusBarService, true /* requireConfirmation */);
authenticateInternal(client, opId, opPackageName, callingUid, callingPid,
callingUserId);
}
@@ -352,10 +353,10 @@
*/
private class BiometricPromptServiceListenerImpl implements ServiceListener {
- private IBiometricPromptServiceReceiver mBiometricPromptServiceReceiver;
+ private IBiometricServiceReceiver mBiometricServiceReceiver;
- public BiometricPromptServiceListenerImpl(IBiometricPromptServiceReceiver receiver) {
- mBiometricPromptServiceReceiver = receiver;
+ public BiometricPromptServiceListenerImpl(IBiometricServiceReceiver receiver) {
+ mBiometricServiceReceiver = receiver;
}
@Override
@@ -364,8 +365,8 @@
/**
* Map the acquired codes onto existing {@link BiometricConstants} acquired codes.
*/
- if (mBiometricPromptServiceReceiver != null) {
- mBiometricPromptServiceReceiver.onAcquired(deviceId,
+ if (mBiometricServiceReceiver != null) {
+ mBiometricServiceReceiver.onAcquired(deviceId,
FaceManager.getMappedAcquiredInfo(acquiredInfo, vendorCode),
FaceManager.getAcquiredString(getContext(), acquiredInfo, vendorCode));
}
@@ -374,22 +375,22 @@
@Override
public void onAuthenticationSucceeded(long deviceId,
BiometricAuthenticator.Identifier biometric, int userId) throws RemoteException {
- if (mBiometricPromptServiceReceiver != null) {
- mBiometricPromptServiceReceiver.onAuthenticationSucceeded(deviceId);
+ if (mBiometricServiceReceiver != null) {
+ mBiometricServiceReceiver.onAuthenticationSucceeded(deviceId);
}
}
@Override
public void onAuthenticationFailed(long deviceId) throws RemoteException {
- if (mBiometricPromptServiceReceiver != null) {
- mBiometricPromptServiceReceiver.onAuthenticationFailed(deviceId);
+ if (mBiometricServiceReceiver != null) {
+ mBiometricServiceReceiver.onAuthenticationFailed(deviceId);
}
}
@Override
public void onError(long deviceId, int error, int vendorCode) throws RemoteException {
- if (mBiometricPromptServiceReceiver != null) {
- mBiometricPromptServiceReceiver.onError(deviceId, error,
+ if (mBiometricServiceReceiver != null) {
+ mBiometricServiceReceiver.onError(deviceId, error,
FaceManager.getErrorString(getContext(), error, vendorCode));
}
}
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 9f4fff8..d3ae064 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -31,7 +31,7 @@
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.IBiometricPromptServiceReceiver;
+import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprintClientCallback;
@@ -59,7 +59,7 @@
import com.android.internal.util.DumpUtils;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.biometrics.AuthenticationClient;
-import com.android.server.biometrics.BiometricService;
+import com.android.server.biometrics.BiometricServiceBase;
import com.android.server.biometrics.BiometricUtils;
import com.android.server.biometrics.ClientMonitor;
import com.android.server.biometrics.EnumerateClient;
@@ -84,7 +84,7 @@
*
* @hide
*/
-public class FingerprintService extends BiometricService {
+public class FingerprintService extends BiometricServiceBase {
protected static final String TAG = "FingerprintService";
private static final boolean DEBUG = true;
@@ -110,10 +110,11 @@
DaemonWrapper daemon, long halDeviceId, IBinder token,
ServiceListener listener, int targetUserId, int groupId, long opId,
boolean restricted, String owner, Bundle bundle,
- IBiometricPromptReceiver dialogReceiver, IStatusBarService statusBarService) {
+ IBiometricPromptReceiver dialogReceiver, IStatusBarService statusBarService,
+ boolean requireConfirmation) {
super(context, daemon, halDeviceId, token, listener, targetUserId, groupId, opId,
- restricted,
- owner, bundle, dialogReceiver, statusBarService);
+ restricted, owner, bundle, dialogReceiver, statusBarService,
+ requireConfirmation);
}
@Override
@@ -182,14 +183,13 @@
final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(),
mDaemonWrapper, mHalDeviceId, token, new ServiceListenerImpl(receiver),
mCurrentUserId, groupId, opId, restricted, opPackageName, null /* bundle */,
- null /* dialogReceiver */, mStatusBarService);
-
+ null /* dialogReceiver */, mStatusBarService, false /* requireConfirmation */);
authenticateInternal(client, opId, opPackageName);
}
@Override // Binder call
public void authenticateFromService(IBinder token, long opId, int groupId,
- IBiometricPromptServiceReceiver receiver, int flags, String opPackageName,
+ IBiometricServiceReceiver receiver, int flags, String opPackageName,
Bundle bundle, IBiometricPromptReceiver dialogReceiver,
int callingUid, int callingPid, int callingUserId) {
checkPermission(MANAGE_BIOMETRIC);
@@ -198,7 +198,7 @@
mDaemonWrapper, mHalDeviceId, token,
new BiometricPromptServiceListenerImpl(receiver),
mCurrentUserId, groupId, opId, restricted, opPackageName, bundle,
- dialogReceiver, mStatusBarService);
+ dialogReceiver, mStatusBarService, false /* requireConfirmation */);
authenticateInternal(client, opId, opPackageName, callingUid, callingPid,
callingUserId);
}
@@ -390,17 +390,17 @@
*/
private class BiometricPromptServiceListenerImpl implements ServiceListener {
- private IBiometricPromptServiceReceiver mBiometricPromptServiceReceiver;
+ private IBiometricServiceReceiver mBiometricServiceReceiver;
- public BiometricPromptServiceListenerImpl(IBiometricPromptServiceReceiver receiver) {
- mBiometricPromptServiceReceiver = receiver;
+ public BiometricPromptServiceListenerImpl(IBiometricServiceReceiver receiver) {
+ mBiometricServiceReceiver = receiver;
}
@Override
public void onAcquired(long deviceId, int acquiredInfo, int vendorCode)
throws RemoteException {
- if (mBiometricPromptServiceReceiver != null) {
- mBiometricPromptServiceReceiver.onAcquired(deviceId, acquiredInfo,
+ if (mBiometricServiceReceiver != null) {
+ mBiometricServiceReceiver.onAcquired(deviceId, acquiredInfo,
FingerprintManager.getAcquiredString(
getContext(), acquiredInfo, vendorCode));
}
@@ -409,22 +409,22 @@
@Override
public void onAuthenticationSucceeded(long deviceId,
BiometricAuthenticator.Identifier biometric, int userId) throws RemoteException {
- if (mBiometricPromptServiceReceiver != null) {
- mBiometricPromptServiceReceiver.onAuthenticationSucceeded(deviceId);
+ if (mBiometricServiceReceiver != null) {
+ mBiometricServiceReceiver.onAuthenticationSucceeded(deviceId);
}
}
@Override
public void onAuthenticationFailed(long deviceId) throws RemoteException {
- if (mBiometricPromptServiceReceiver != null) {
- mBiometricPromptServiceReceiver.onAuthenticationFailed(deviceId);
+ if (mBiometricServiceReceiver != null) {
+ mBiometricServiceReceiver.onAuthenticationFailed(deviceId);
}
}
@Override
public void onError(long deviceId, int error, int vendorCode) throws RemoteException {
- if (mBiometricPromptServiceReceiver != null) {
- mBiometricPromptServiceReceiver.onError(deviceId, error,
+ if (mBiometricServiceReceiver != null) {
+ mBiometricServiceReceiver.onError(deviceId, error,
FingerprintManager.getErrorString(getContext(), error, vendorCode));
}
}
@@ -514,7 +514,7 @@
/**
* An internal class to help clean up unknown fingerprints in the hardware and software.
*/
- private final class InternalEnumerateClient extends BiometricService.EnumerateClientImpl {
+ private final class InternalEnumerateClient extends BiometricServiceBase.EnumerateClientImpl {
private List<Fingerprint> mEnrolledList;
private List<Fingerprint> mUnknownFingerprints = new ArrayList<>(); // list of fp to delete
@@ -577,7 +577,7 @@
/**
* An internal class to help clean up unknown fingerprints in hardware and software.
*/
- private final class InternalRemovalClient extends BiometricService.RemovalClientImpl {
+ private final class InternalRemovalClient extends BiometricServiceBase.RemovalClientImpl {
public InternalRemovalClient(Context context,
DaemonWrapper daemon, long halDeviceId, IBinder token,
ServiceListener listener, int fingerId, int groupId, int userId, boolean restricted,
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index a050aa9..0f28439 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1875,30 +1875,36 @@
// Read partner-provided list of excluded input devices
XmlPullParser parser = null;
// Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
- File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
- FileReader confreader = null;
- try {
- confreader = new FileReader(confFile);
- parser = Xml.newPullParser();
- parser.setInput(confreader);
- XmlUtils.beginDocument(parser, "devices");
+ final File[] baseDirs = {
+ Environment.getRootDirectory(),
+ Environment.getVendorDirectory()
+ };
+ for (File baseDir: baseDirs) {
+ File confFile = new File(baseDir, EXCLUDED_DEVICES_PATH);
+ FileReader confreader = null;
+ try {
+ confreader = new FileReader(confFile);
+ parser = Xml.newPullParser();
+ parser.setInput(confreader);
+ XmlUtils.beginDocument(parser, "devices");
- while (true) {
- XmlUtils.nextElement(parser);
- if (!"device".equals(parser.getName())) {
- break;
+ while (true) {
+ XmlUtils.nextElement(parser);
+ if (!"device".equals(parser.getName())) {
+ break;
+ }
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ names.add(name);
+ }
}
- String name = parser.getAttributeValue(null, "name");
- if (name != null) {
- names.add(name);
- }
+ } catch (FileNotFoundException e) {
+ // It's ok if the file does not exist.
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
+ } finally {
+ try { if (confreader != null) confreader.close(); } catch (IOException e) { }
}
- } catch (FileNotFoundException e) {
- // It's ok if the file does not exist.
- } catch (Exception e) {
- Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
- } finally {
- try { if (confreader != null) confreader.close(); } catch (IOException e) { }
}
return names.toArray(new String[names.size()]);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e53eeb0..e81b32c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2391,7 +2391,7 @@
String pkg) {
checkCallerIsSystemOrSameApp(pkg);
return mPreferencesHelper.getNotificationChannelGroups(
- pkg, Binder.getCallingUid(), false, false);
+ pkg, Binder.getCallingUid(), false, false, true);
}
@Override
@@ -2467,7 +2467,8 @@
public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
String pkg, int uid, boolean includeDeleted) {
checkCallerIsSystem();
- return mPreferencesHelper.getNotificationChannelGroups(pkg, uid, includeDeleted, true);
+ return mPreferencesHelper.getNotificationChannelGroups(
+ pkg, uid, includeDeleted, true, false);
}
@Override
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 13ff6e8..3a0ab77 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -755,7 +755,7 @@
@Override
public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
- int uid, boolean includeDeleted, boolean includeNonGrouped) {
+ int uid, boolean includeDeleted, boolean includeNonGrouped, boolean includeEmpty) {
Preconditions.checkNotNull(pkg);
Map<String, NotificationChannelGroup> groups = new ArrayMap<>();
PackagePreferences r = getPackagePreferences(pkg, uid);
@@ -786,6 +786,13 @@
if (includeNonGrouped && nonGrouped.getChannels().size() > 0) {
groups.put(null, nonGrouped);
}
+ if (includeEmpty) {
+ for (NotificationChannelGroup group : r.groups.values()) {
+ if (!groups.containsKey(group.getId())) {
+ groups.put(group.getId(), group);
+ }
+ }
+ }
return new ParceledListSlice<>(new ArrayList<>(groups.values()));
}
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index af64683..605348b 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -36,7 +36,7 @@
void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
boolean fromTargetApp);
ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
- int uid, boolean includeDeleted, boolean includeNonGrouped);
+ int uid, boolean includeDeleted, boolean includeNonGrouped, boolean includeEmpty);
void createNotificationChannel(String pkg, int uid, NotificationChannel channel,
boolean fromTargetApp, boolean hasDndAccess);
void updateNotificationChannel(String pkg, int uid, NotificationChannel channel, boolean fromUser);
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 25f52e7..9bf21c8 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1161,13 +1161,13 @@
final boolean showNotification = mIsBootComplete
&& zen != Global.ZEN_MODE_OFF
&& !isWatch
- && Settings.Global.getInt(mContext.getContentResolver(),
+ && Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0
- && Settings.Global.getInt(mContext.getContentResolver(),
+ && Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ZEN_SETTINGS_UPDATED, 0) != 1;
if (isWatch) {
- Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index c2d8188..79eab6b 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -565,11 +565,12 @@
}
@Override
- public void showBiometricDialog(Bundle bundle, IBiometricPromptReceiver receiver, int type) {
+ public void showBiometricDialog(Bundle bundle, IBiometricPromptReceiver receiver, int type,
+ boolean requireConfirmation) {
enforceBiometricDialog();
if (mBar != null) {
try {
- mBar.showBiometricDialog(bundle, receiver, type);
+ mBar.showBiometricDialog(bundle, receiver, type, requireConfirmation);
} catch (RemoteException ex) {
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 524ca17..7d2fc15 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -30,7 +30,6 @@
import android.os.SystemClock;
import android.service.voice.IVoiceInteractionSession;
import android.util.SparseIntArray;
-import android.view.RemoteAnimationAdapter;
import com.android.internal.app.IVoiceInteractor;
import com.android.server.am.WindowProcessController;
@@ -289,4 +288,13 @@
public abstract void onPackageAdded(String name, boolean replacing);
public abstract CompatibilityInfo compatibilityInfoForPackage(ApplicationInfo ai);
+
+ /**
+ * Set the corresponding display information for the process global configuration. To be called
+ * when we need to show IME on a different display.
+ *
+ * @param pid The process id associated with the IME window.
+ * @param displayId The ID of the display showing the IME.
+ */
+ public abstract void onImeWindowSetOnDisplay(int pid, int displayId);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6aca464..eaaf804 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -76,6 +76,7 @@
import static com.android.server.wm.DisplayContentProto.ROTATION;
import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
import static com.android.server.wm.DisplayContentProto.STACKS;
+import static com.android.server.wm.DisplayContentProto.SURFACE_SIZE;
import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
@@ -2409,6 +2410,7 @@
screenRotationAnimation.writeToProto(proto, SCREEN_ROTATION_ANIMATION);
}
mDisplayFrames.writeToProto(proto, DISPLAY_FRAMES);
+ proto.write(SURFACE_SIZE, mSurfaceSize);
proto.end(token);
}
@@ -3151,6 +3153,10 @@
}
}
+ int getSurfaceSize() {
+ return mSurfaceSize;
+ }
+
void performLayout(boolean initial, boolean updateInputWindows) {
if (!isLayoutNeeded()) {
return;
diff --git a/services/core/java/com/android/server/wm/SeamlessRotator.java b/services/core/java/com/android/server/wm/SeamlessRotator.java
index 6f597277..95ca0a6 100644
--- a/services/core/java/com/android/server/wm/SeamlessRotator.java
+++ b/services/core/java/com/android/server/wm/SeamlessRotator.java
@@ -16,12 +16,12 @@
package com.android.server.wm;
-import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import android.graphics.Matrix;
import android.view.DisplayInfo;
+import android.view.Surface;
import android.view.Surface.Rotation;
import android.view.SurfaceControl.Transaction;
@@ -33,10 +33,10 @@
/**
* Helper class for seamless rotation.
*
- * Works by transforming the window token back into the old display rotation.
+ * Works by transforming the {@link WindowState} back into the old display rotation.
*
- * Uses deferTransactionUntil instead of latching on the buffer size to allow for seamless 180
- * degree rotations.
+ * Uses {@link android.view.SurfaceControl#deferTransactionUntil(Surface, long)} instead of
+ * latching on the buffer size to allow for seamless 180 degree rotations.
*/
public class SeamlessRotator {
@@ -45,7 +45,7 @@
private final int mOldRotation;
private final int mNewRotation;
- public SeamlessRotator(int oldRotation, int newRotation, DisplayInfo info) {
+ public SeamlessRotator(@Rotation int oldRotation, @Rotation int newRotation, DisplayInfo info) {
mOldRotation = oldRotation;
mNewRotation = newRotation;
@@ -60,11 +60,16 @@
}
/**
- * Applies a transform to the window token's surface that undoes the effect of the global
+ * Applies a transform to the {@link WindowState} surface that undoes the effect of the global
* display rotation.
*/
- public void unrotate(Transaction transaction, WindowToken token) {
- transaction.setMatrix(token.getSurfaceControl(), mTransform, mFloat9);
+ public void unrotate(Transaction transaction, WindowState win) {
+ transaction.setMatrix(win.getSurfaceControl(), mTransform, mFloat9);
+
+ // WindowState sets the position of the window so transform the position and update it.
+ final float[] winSurfacePos = {win.mLastSurfacePosition.x, win.mLastSurfacePosition.y};
+ mTransform.mapPoints(winSurfacePos);
+ transaction.setPosition(win.getSurfaceControl(), winSurfacePos[0], winSurfacePos[1]);
}
/**
@@ -78,27 +83,23 @@
}
/**
- * Removes the transform to the window token's surface that undoes the effect of the global
- * display rotation.
+ * Removes the transform and sets the previously known surface position for {@link WindowState}
+ * surface that undoes the effect of the global display rotation.
*
- * Removing the transform and the result of the WindowState's layout are both tied to the
- * WindowState's next frame, such that they apply at the same time the client draws the
+ * Removing the transform and the result of the {@link WindowState} layout are both tied to the
+ * {@link WindowState} next frame, such that they apply at the same time the client draws the
* window in the new orientation.
*/
- public void finish(WindowToken token, WindowState win) {
+ public void finish(WindowState win) {
mTransform.reset();
- token.getPendingTransaction().setMatrix(token.mSurfaceControl, mTransform, mFloat9);
+ final Transaction t = win.getPendingTransaction();
+ t.setMatrix(win.mSurfaceControl, mTransform, mFloat9);
+ t.setPosition(win.mSurfaceControl, win.mLastSurfacePosition.x, win.mLastSurfacePosition.y);
if (win.mWinAnimator.mSurfaceController != null) {
- token.getPendingTransaction().deferTransactionUntil(token.mSurfaceControl,
- win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(),
- win.getFrameNumber());
- win.getPendingTransaction().deferTransactionUntil(win.mSurfaceControl,
- win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(),
- win.getFrameNumber());
- win.getPendingTransaction().deferTransactionUntil(
- win.mWinAnimator.mSurfaceController.mSurfaceControl,
- win.mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(),
- win.getFrameNumber());
+ t.deferTransactionUntil(win.mSurfaceControl,
+ win.mWinAnimator.mSurfaceController.getHandle(), win.getFrameNumber());
+ t.deferTransactionUntil(win.mWinAnimator.mSurfaceController.mSurfaceControl,
+ win.mWinAnimator.mSurfaceController.getHandle(), win.getFrameNumber());
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index eb419c9..cc23ab6 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -29,6 +29,8 @@
import static com.android.server.wm.TaskProto.DEFER_REMOVAL;
import static com.android.server.wm.TaskProto.FILLS_PARENT;
import static com.android.server.wm.TaskProto.ID;
+import static com.android.server.wm.TaskProto.SURFACE_HEIGHT;
+import static com.android.server.wm.TaskProto.SURFACE_WIDTH;
import static com.android.server.wm.TaskProto.TEMP_INSET_BOUNDS;
import static com.android.server.wm.TaskProto.WINDOW_CONTAINER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
@@ -297,6 +299,12 @@
return boundsChange;
}
+ @Override
+ void onDisplayChanged(DisplayContent dc) {
+ updateSurfaceSize(dc);
+ super.onDisplayChanged(dc);
+ }
+
/**
* Sets the bounds used to calculate the insets. See
* {@link android.app.IActivityTaskManager#resizeDockedStack} why this is needed.
@@ -703,6 +711,8 @@
getBounds().writeToProto(proto, BOUNDS);
mTempInsetBounds.writeToProto(proto, TEMP_INSET_BOUNDS);
proto.write(DEFER_REMOVAL, mDeferRemoval);
+ proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
+ proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
proto.end(token);
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 8e704a8..e860939 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -20,13 +20,14 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.SurfaceControl.Transaction;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
import static com.android.server.wm.WindowContainerProto.CONFIGURATION_CONTAINER;
import static com.android.server.wm.WindowContainerProto.ORIENTATION;
import static com.android.server.wm.WindowContainerProto.SURFACE_ANIMATOR;
import static com.android.server.wm.WindowContainerProto.VISIBLE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.CallSuper;
import android.annotation.IntDef;
@@ -503,6 +504,24 @@
}
}
+ /**
+ * Update the surface size when display changed in order to avoid children being bound by the
+ * old display size.
+ *
+ * Note that we don't want to apply this to all layers, but only limiting this to layers that
+ * don't set their own size ({@link Task}, {@link WindowState} and {@link WindowToken}).
+ */
+ void updateSurfaceSize(DisplayContent dc) {
+ if (mSurfaceControl == null) {
+ return;
+ }
+
+ final int newSurfaceSize = dc.getSurfaceSize();
+ if (mSurfaceControl.getWidth() != newSurfaceSize) {
+ getPendingTransaction().setSize(mSurfaceControl, newSurfaceSize, newSurfaceSize);
+ }
+ }
+
void setWaitingForDrawnIfResizingChanged() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 57cae39..27b623b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ClipData;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManagerInternal;
@@ -456,4 +457,11 @@
* Return the display Id for given window.
*/
public abstract int getDisplayIdForWindow(IBinder windowToken);
+
+ // TODO: use WindowProcessController once go/wm-unified is done.
+ /**
+ * Notifies the window manager that configuration of the process associated with the input pid
+ * changed.
+ */
+ public abstract void onProcessConfigurationChanged(int pid, Configuration newConfig);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 71ce1d9..017f667 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -182,6 +182,7 @@
import android.util.MergedConfiguration;
import android.util.Pair;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
@@ -480,6 +481,10 @@
*/
WindowState[] mPendingRemoveTmp = new WindowState[20];
+ // TODO: use WindowProcessController once go/wm-unified is done.
+ /** Mapping of process pids to configurations */
+ final SparseArray<Configuration> mProcessConfigurations = new SparseArray<>();
+
/**
* Windows whose surface should be destroyed.
*/
@@ -7430,6 +7435,19 @@
return Display.INVALID_DISPLAY;
}
}
+
+ @Override
+ public void onProcessConfigurationChanged(int pid, Configuration newConfig) {
+ synchronized (mWindowMap) {
+ Configuration currentConfig = mProcessConfigurations.get(pid);
+ if (currentConfig == null) {
+ currentConfig = new Configuration(newConfig);
+ } else {
+ currentConfig.setTo(newConfig);
+ }
+ mProcessConfigurations.put(pid, currentConfig);
+ }
+ }
}
void registerAppFreezeListener(AppFreezeListener listener) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f1ddda7..7161a70 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -304,6 +304,8 @@
*/
private final MergedConfiguration mLastReportedConfiguration = new MergedConfiguration();
+ private final Configuration mTempConfiguration = new Configuration();
+
/**
* The last content insets returned to the client in relayout. We use
* these in the bounds animation to ensure we only observe inset changes
@@ -591,14 +593,14 @@
if (mForceSeamlesslyRotate || requested) {
mPendingSeamlessRotate = new SeamlessRotator(oldRotation, rotation, getDisplayInfo());
- mPendingSeamlessRotate.unrotate(transaction, this.mToken);
+ mPendingSeamlessRotate.unrotate(transaction, this);
mService.markForSeamlessRotation(this, true);
}
}
void finishSeamlessRotation() {
if (mPendingSeamlessRotate != null) {
- mPendingSeamlessRotate.finish(this.mToken, this);
+ mPendingSeamlessRotate.finish(this);
mFinishSeamlessRotateFrameNumber = getFrameNumber();
mPendingSeamlessRotate = null;
mService.markForSeamlessRotation(this, false);
@@ -1259,6 +1261,7 @@
@Override
void onDisplayChanged(DisplayContent dc) {
+ updateSurfaceSize(dc);
super.onDisplayChanged(dc);
// Window was not laid out for this display yet, so make sure mLayoutSeq does not match.
if (dc != null) {
@@ -2249,8 +2252,17 @@
}
}
+ private Configuration getProcessGlobalConfiguration() {
+ // For child windows we want to use the pid for the parent window in case the the child
+ // window was added from another process.
+ final int pid = isChildWindow() ? getParentWindow().mSession.mPid : mSession.mPid;
+ mTempConfiguration.setTo(mService.mProcessConfigurations.get(
+ pid, mService.mRoot.getConfiguration()));
+ return mTempConfiguration;
+ }
+
void getMergedConfiguration(MergedConfiguration outConfiguration) {
- final Configuration globalConfig = mService.mRoot.getConfiguration();
+ final Configuration globalConfig = getProcessGlobalConfiguration();
final Configuration overrideConfig = getMergedOverrideConfiguration();
outConfiguration.setConfiguration(globalConfig, overrideConfig);
}
@@ -2853,7 +2865,11 @@
return mAppToken.mFrozenMergedConfig.peek();
}
- return super.getConfiguration();
+ // We use the process config this window is associated with as the based global config since
+ // the process can override it config, but isn't part of the window hierarchy.
+ final Configuration config = getProcessGlobalConfiguration();
+ config.updateFrom(getMergedOverrideConfiguration());
+ return config;
}
void reportResized() {
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index e411c0a..8972c38 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -18,6 +18,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
@@ -275,6 +276,7 @@
// to another display before the window behind
// it is ready.
+ updateSurfaceSize(dc);
super.onDisplayChanged(dc);
}
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 93c4829..6c2a894 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -390,7 +390,11 @@
[&result, &sidebandStream](Result res, const native_handle_t* handle) {
result = res;
if (res == Result::OK) {
- sidebandStream = handle;
+ if (handle) {
+ sidebandStream = native_handle_clone(handle);
+ } else {
+ result = Result::UNKNOWN;
+ }
}
});
if (result != Result::OK) {
@@ -398,7 +402,7 @@
result);
return UNKNOWN_ERROR;
}
- connection.mSourceHandle = NativeHandle::create((native_handle_t*)sidebandStream, false);
+ connection.mSourceHandle = NativeHandle::create((native_handle_t*)sidebandStream, true);
}
connection.mSurface = surface;
if (connection.mSurface != nullptr) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9d63305..fb95f59 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -63,11 +63,10 @@
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.EmergencyAffordanceManager;
import com.android.internal.widget.ILockSettings;
-import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.ActivityTaskManagerService;
import com.android.server.audio.AudioService;
-import com.android.server.biometrics.BiometricPromptService;
+import com.android.server.biometrics.BiometricService;
import com.android.server.broadcastradio.BroadcastRadioService;
import com.android.server.camera.CameraServiceProxy;
import com.android.server.clipboard.ClipboardService;
@@ -1590,7 +1589,7 @@
if (hasFeatureFace || hasFeatureFingerprint) {
// Start this service after all biometric services.
traceBeginAndSlog("StartBiometricPromptService");
- mSystemServiceManager.startService(BiometricPromptService.class);
+ mSystemServiceManager.startService(BiometricService.class);
traceEnd();
}
diff --git a/services/net/java/android/net/netlink/InetDiagMessage.java b/services/net/java/android/net/netlink/InetDiagMessage.java
new file mode 100644
index 0000000..af9e601
--- /dev/null
+++ b/services/net/java/android/net/netlink/InetDiagMessage.java
@@ -0,0 +1,187 @@
+/*
+ * 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 android.net.netlink;
+
+import static android.os.Process.INVALID_UID;
+import static android.net.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY;
+import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.IPPROTO_UDP;
+import static android.system.OsConstants.NETLINK_INET_DIAG;
+
+import android.os.Build;
+import android.os.Process;
+import android.system.ErrnoException;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.InterruptedIOException;
+import java.net.DatagramSocket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetSocketAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * A NetlinkMessage subclass for netlink inet_diag messages.
+ *
+ * see also: <linux_src>/include/uapi/linux/inet_diag.h
+ *
+ * @hide
+ */
+public class InetDiagMessage extends NetlinkMessage {
+ public static final String TAG = "InetDiagMessage";
+ private static final int TIMEOUT_MS = 500;
+
+ public static byte[] InetDiagReqV2(int protocol, InetSocketAddress local,
+ InetSocketAddress remote, int family, short flags) {
+ final byte[] bytes = new byte[StructNlMsgHdr.STRUCT_SIZE + StructInetDiagReqV2.STRUCT_SIZE];
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
+ byteBuffer.order(ByteOrder.nativeOrder());
+
+ final StructNlMsgHdr nlMsgHdr = new StructNlMsgHdr();
+ nlMsgHdr.nlmsg_len = bytes.length;
+ nlMsgHdr.nlmsg_type = SOCK_DIAG_BY_FAMILY;
+ nlMsgHdr.nlmsg_flags = flags;
+ nlMsgHdr.pack(byteBuffer);
+
+ final StructInetDiagReqV2 inetDiagReqV2 = new StructInetDiagReqV2(protocol, local, remote,
+ family);
+ inetDiagReqV2.pack(byteBuffer);
+ return bytes;
+ }
+
+ public StructInetDiagMsg mStructInetDiagMsg;
+
+ private InetDiagMessage(StructNlMsgHdr header) {
+ super(header);
+ mStructInetDiagMsg = new StructInetDiagMsg();
+ }
+
+ public static InetDiagMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) {
+ final InetDiagMessage msg = new InetDiagMessage(header);
+ msg.mStructInetDiagMsg = StructInetDiagMsg.parse(byteBuffer);
+ return msg;
+ }
+
+ private static int lookupUidByFamily(int protocol, InetSocketAddress local,
+ InetSocketAddress remote, int family, short flags,
+ FileDescriptor fd)
+ throws ErrnoException, InterruptedIOException {
+ byte[] msg = InetDiagReqV2(protocol, local, remote, family, flags);
+ NetlinkSocket.sendMessage(fd, msg, 0, msg.length, TIMEOUT_MS);
+ ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT_MS);
+
+ final NetlinkMessage nlMsg = NetlinkMessage.parse(response);
+ final StructNlMsgHdr hdr = nlMsg.getHeader();
+ if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) {
+ return INVALID_UID;
+ }
+ if (nlMsg instanceof InetDiagMessage) {
+ return ((InetDiagMessage) nlMsg).mStructInetDiagMsg.idiag_uid;
+ }
+ return INVALID_UID;
+ }
+
+ private static final int FAMILY[] = {AF_INET6, AF_INET};
+
+ private static int lookupUid(int protocol, InetSocketAddress local,
+ InetSocketAddress remote, FileDescriptor fd)
+ throws ErrnoException, InterruptedIOException {
+ int uid;
+
+ for (int family : FAMILY) {
+ /**
+ * For exact match lookup, swap local and remote for UDP lookups due to kernel
+ * bug which will not be fixed. See aosp/755889 and
+ * https://www.mail-archive.com/netdev@vger.kernel.org/msg248638.html
+ */
+ if (protocol == IPPROTO_UDP) {
+ uid = lookupUidByFamily(protocol, remote, local, family, NLM_F_REQUEST, fd);
+ } else {
+ uid = lookupUidByFamily(protocol, local, remote, family, NLM_F_REQUEST, fd);
+ }
+ if (uid != INVALID_UID) {
+ return uid;
+ }
+ }
+
+ /**
+ * For UDP it's possible for a socket to send packets to arbitrary destinations, even if the
+ * socket is not connected (and even if the socket is connected to a different destination).
+ * If we want this API to work for such packets, then on miss we need to do a second lookup
+ * with only the local address and port filled in.
+ * Always use flags == NLM_F_REQUEST | NLM_F_DUMP for wildcard.
+ */
+ if (protocol == IPPROTO_UDP) {
+ try {
+ InetSocketAddress wildcard = new InetSocketAddress(
+ Inet6Address.getByName("::"), 0);
+ uid = lookupUidByFamily(protocol, local, wildcard, AF_INET6,
+ (short) (NLM_F_REQUEST | NLM_F_DUMP), fd);
+ if (uid != INVALID_UID) {
+ return uid;
+ }
+ wildcard = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), 0);
+ uid = lookupUidByFamily(protocol, local, wildcard, AF_INET,
+ (short) (NLM_F_REQUEST | NLM_F_DUMP), fd);
+ if (uid != INVALID_UID) {
+ return uid;
+ }
+ } catch (UnknownHostException e) {
+ Log.e(TAG, e.toString());
+ }
+ }
+ return INVALID_UID;
+ }
+
+ /**
+ * Use an inet_diag socket to look up the UID associated with the input local and remote
+ * address/port and protocol of a connection.
+ */
+ public static int getConnectionOwnerUid(int protocol, InetSocketAddress local,
+ InetSocketAddress remote) {
+ try {
+ final FileDescriptor fd = NetlinkSocket.forProto(NETLINK_INET_DIAG);
+ NetlinkSocket.connectToKernel(fd);
+
+ return lookupUid(protocol, local, remote, fd);
+
+ } catch (ErrnoException | SocketException | IllegalArgumentException
+ | InterruptedIOException e) {
+ Log.e(TAG, e.toString());
+ }
+ return INVALID_UID;
+ }
+
+ @Override
+ public String toString() {
+ return "InetDiagMessage{ "
+ + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, "
+ + "inet_diag_msg{"
+ + (mStructInetDiagMsg == null ? "" : mStructInetDiagMsg.toString()) + "} "
+ + "}";
+ }
+}
diff --git a/services/net/java/android/net/netlink/NetlinkConstants.java b/services/net/java/android/net/netlink/NetlinkConstants.java
index e331701..fc1551c 100644
--- a/services/net/java/android/net/netlink/NetlinkConstants.java
+++ b/services/net/java/android/net/netlink/NetlinkConstants.java
@@ -54,6 +54,12 @@
return String.valueOf(family);
}
+ public static String stringForProtocol(int protocol) {
+ if (protocol == OsConstants.IPPROTO_TCP) { return "IPPROTO_TCP"; }
+ if (protocol == OsConstants.IPPROTO_UDP) { return "IPPROTO_UDP"; }
+ return String.valueOf(protocol);
+ }
+
public static String hexify(byte[] bytes) {
if (bytes == null) { return "(null)"; }
return HexDump.toHexString(bytes);
@@ -90,6 +96,9 @@
public static final short RTM_GETRULE = 34;
public static final short RTM_NEWNDUSEROPT = 68;
+ /* see <linux_src>/include/uapi/linux/sock_diag.h */
+ public static final short SOCK_DIAG_BY_FAMILY = 20;
+
public static String stringForNlMsgType(short nlm_type) {
switch (nlm_type) {
case NLMSG_NOOP: return "NLMSG_NOOP";
diff --git a/services/net/java/android/net/netlink/NetlinkMessage.java b/services/net/java/android/net/netlink/NetlinkMessage.java
index 3bf75ca..a325db8 100644
--- a/services/net/java/android/net/netlink/NetlinkMessage.java
+++ b/services/net/java/android/net/netlink/NetlinkMessage.java
@@ -69,6 +69,8 @@
case NetlinkConstants.RTM_DELNEIGH:
case NetlinkConstants.RTM_GETNEIGH:
return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer);
+ case NetlinkConstants.SOCK_DIAG_BY_FAMILY:
+ return (NetlinkMessage) InetDiagMessage.parse(nlmsghdr, byteBuffer);
default:
if (nlmsghdr.nlmsg_type <= NetlinkConstants.NLMSG_MAX_RESERVED) {
// Netlink control message. Just parse the header for now,
diff --git a/services/net/java/android/net/netlink/StructInetDiagMsg.java b/services/net/java/android/net/netlink/StructInetDiagMsg.java
new file mode 100644
index 0000000..da824ad
--- /dev/null
+++ b/services/net/java/android/net/netlink/StructInetDiagMsg.java
@@ -0,0 +1,67 @@
+/*
+ * 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 android.net.netlink;
+
+import static java.nio.ByteOrder.BIG_ENDIAN;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import java.net.Inet4Address;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import android.util.Log;
+
+/**
+ * struct inet_diag_msg
+ *
+ * see <linux_src>/include/uapi/linux/inet_diag.h
+ *
+ * struct inet_diag_msg {
+ * __u8 idiag_family;
+ * __u8 idiag_state;
+ * __u8 idiag_timer;
+ * __u8 idiag_retrans;
+ * struct inet_diag_sockid id;
+ * __u32 idiag_expires;
+ * __u32 idiag_rqueue;
+ * __u32 idiag_wqueue;
+ * __u32 idiag_uid;
+ * __u32 idiag_inode;
+ * };
+ *
+ * @hide
+ */
+public class StructInetDiagMsg {
+ public static final int STRUCT_SIZE = 4 + StructInetDiagSockId.STRUCT_SIZE + 20;
+ private static final int IDIAG_UID_OFFSET = StructNlMsgHdr.STRUCT_SIZE + 4 +
+ StructInetDiagSockId.STRUCT_SIZE + 12;
+ public int idiag_uid;
+
+ public static StructInetDiagMsg parse(ByteBuffer byteBuffer) {
+ StructInetDiagMsg struct = new StructInetDiagMsg();
+ struct.idiag_uid = byteBuffer.getInt(IDIAG_UID_OFFSET);
+ return struct;
+ }
+
+ @Override
+ public String toString() {
+ return "StructInetDiagMsg{ "
+ + "idiag_uid{" + idiag_uid + "}, "
+ + "}";
+ }
+}
diff --git a/services/net/java/android/net/netlink/StructInetDiagReqV2.java b/services/net/java/android/net/netlink/StructInetDiagReqV2.java
new file mode 100644
index 0000000..49a9325
--- /dev/null
+++ b/services/net/java/android/net/netlink/StructInetDiagReqV2.java
@@ -0,0 +1,80 @@
+/*
+ * 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 android.net.netlink;
+
+import static java.nio.ByteOrder.BIG_ENDIAN;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * struct inet_diag_req_v2
+ *
+ * see <linux_src>/include/uapi/linux/inet_diag.h
+ *
+ * struct inet_diag_req_v2 {
+ * __u8 sdiag_family;
+ * __u8 sdiag_protocol;
+ * __u8 idiag_ext;
+ * __u8 pad;
+ * __u32 idiag_states;
+ * struct inet_diag_sockid id;
+ * };
+ *
+ * @hide
+ */
+public class StructInetDiagReqV2 {
+ public static final int STRUCT_SIZE = 8 + StructInetDiagSockId.STRUCT_SIZE;
+
+ private final byte sdiag_family;
+ private final byte sdiag_protocol;
+ private final StructInetDiagSockId id;
+ private final int INET_DIAG_REQ_V2_ALL_STATES = (int) 0xffffffff;
+
+
+ public StructInetDiagReqV2(int protocol, InetSocketAddress local, InetSocketAddress remote,
+ int family) {
+ sdiag_family = (byte) family;
+ sdiag_protocol = (byte) protocol;
+ id = new StructInetDiagSockId(local, remote);
+ }
+
+ public void pack(ByteBuffer byteBuffer) {
+ // The ByteOrder must have already been set by the caller.
+ byteBuffer.put((byte) sdiag_family);
+ byteBuffer.put((byte) sdiag_protocol);
+ byteBuffer.put((byte) 0);
+ byteBuffer.put((byte) 0);
+ byteBuffer.putInt(INET_DIAG_REQ_V2_ALL_STATES);
+ id.pack(byteBuffer);
+ }
+
+ @Override
+ public String toString() {
+ final String familyStr = NetlinkConstants.stringForAddressFamily(sdiag_family);
+ final String protocolStr = NetlinkConstants.stringForAddressFamily(sdiag_protocol);
+
+ return "StructInetDiagReqV2{ "
+ + "sdiag_family{" + familyStr + "}, "
+ + "sdiag_protocol{" + protocolStr + "}, "
+ + "idiag_ext{" + 0 + ")}, "
+ + "pad{" + 0 + "}, "
+ + "idiag_states{" + Integer.toHexString(INET_DIAG_REQ_V2_ALL_STATES) + "}, "
+ + id.toString()
+ + "}";
+ }
+}
diff --git a/services/net/java/android/net/netlink/StructInetDiagSockId.java b/services/net/java/android/net/netlink/StructInetDiagSockId.java
new file mode 100644
index 0000000..2e9fa25
--- /dev/null
+++ b/services/net/java/android/net/netlink/StructInetDiagSockId.java
@@ -0,0 +1,86 @@
+/*
+ * 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 android.net.netlink;
+
+import static java.nio.ByteOrder.BIG_ENDIAN;
+
+import java.net.Inet4Address;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * struct inet_diag_req_v2
+ *
+ * see <linux_src>/include/uapi/linux/inet_diag.h
+ *
+ * struct inet_diag_sockid {
+ * __be16 idiag_sport;
+ * __be16 idiag_dport;
+ * __be32 idiag_src[4];
+ * __be32 idiag_dst[4];
+ * __u32 idiag_if;
+ * __u32 idiag_cookie[2];
+ * #define INET_DIAG_NOCOOKIE (~0U)
+ * };
+ *
+ * @hide
+ */
+public class StructInetDiagSockId {
+ public static final int STRUCT_SIZE = 48;
+
+ private final InetSocketAddress mLocSocketAddress;
+ private final InetSocketAddress mRemSocketAddress;
+ private final byte[] INET_DIAG_NOCOOKIE = new byte[]{
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
+ private final byte[] IPV4_PADDING = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ public StructInetDiagSockId(InetSocketAddress loc, InetSocketAddress rem) {
+ mLocSocketAddress = loc;
+ mRemSocketAddress = rem;
+ }
+
+ public void pack(ByteBuffer byteBuffer) {
+ byteBuffer.order(BIG_ENDIAN);
+ byteBuffer.putShort((short) mLocSocketAddress.getPort());
+ byteBuffer.putShort((short) mRemSocketAddress.getPort());
+ byteBuffer.put(mLocSocketAddress.getAddress().getAddress());
+ if (mLocSocketAddress.getAddress() instanceof Inet4Address) {
+ byteBuffer.put(IPV4_PADDING);
+ }
+ byteBuffer.put(mRemSocketAddress.getAddress().getAddress());
+ if (mRemSocketAddress.getAddress() instanceof Inet4Address) {
+ byteBuffer.put(IPV4_PADDING);
+ }
+ byteBuffer.order(ByteOrder.nativeOrder());
+ byteBuffer.putInt(0);
+ byteBuffer.put(INET_DIAG_NOCOOKIE);
+ }
+
+ @Override
+ public String toString() {
+ return "StructInetDiagSockId{ "
+ + "idiag_sport{" + mLocSocketAddress.getPort() + "}, "
+ + "idiag_dport{" + mRemSocketAddress.getPort() + "}, "
+ + "idiag_src{" + mLocSocketAddress.getAddress().getHostAddress() + "}, "
+ + "idiag_dst{" + mRemSocketAddress.getAddress().getHostAddress() + "}, "
+ + "idiag_if{" + 0 + "} "
+ + "idiag_cookie{INET_DIAG_NOCOOKIE}"
+ + "}";
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 47ce879..c44e492 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -258,7 +258,7 @@
uidRec.hasInternetPermission = true;
mAms.mActiveUids.put(uid, uidRec);
- final ProcessRecord appRec = new ProcessRecord(mAms, new ApplicationInfo(), TAG, uid);
+ final ProcessRecord appRec = new ProcessRecord(mAms, new ApplicationInfo(), TAG, uid, null);
appRec.thread = Mockito.mock(IApplicationThread.class);
mAms.mLruProcesses.add(appRec);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
index e1ebbcf..9192d6b 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
@@ -83,7 +83,7 @@
final WindowProcessController wpc = new WindowProcessController(mService,
mService.mContext.getApplicationInfo(), "name", 12345,
UserHandle.getUserId(12345), mock(Object.class),
- mock(WindowProcessListener.class));
+ mock(WindowProcessListener.class), null);
wpc.setThread(mock(IApplicationThread.class));
mController.addPendingActivityLaunch(
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
index 749403e..bac4a52 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -208,7 +208,7 @@
// If no caller app, return {@code null} {@link ProcessRecord}.
final ProcessRecord record = containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
- ? null : new ProcessRecord(service.mAm, mock(ApplicationInfo.class), null, 0);
+ ? null : new ProcessRecord(service.mAm, mock(ApplicationInfo.class), null, 0, null);
doReturn(record).when(service.mAm).getRecordForAppLocked(anyObject());
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 0e82009..22add01 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -281,7 +281,7 @@
final WindowProcessController wpc = new WindowProcessController(mService,
mService.mContext.getApplicationInfo(), "name", 12345,
UserHandle.getUserId(12345), mock(Object.class),
- mock(WindowProcessListener.class));
+ mock(WindowProcessListener.class), null);
wpc.setThread(mock(IApplicationThread.class));
activity.setProcess(wpc);
return activity;
diff --git a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
index 87d367f..3819e21 100644
--- a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
@@ -67,7 +67,7 @@
@UiThreadTest
public void testCreateWorks() throws Exception {
AppErrorDialog.Data data = new AppErrorDialog.Data();
- data.proc = new ProcessRecord(null, mContext.getApplicationInfo(), "name", 12345);
+ data.proc = new ProcessRecord(null, mContext.getApplicationInfo(), "name", 12345, null);
data.result = new AppErrorResult();
AppErrorDialog dialog = new AppErrorDialog(mContext, mService, data);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 750345b..79998a5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -284,8 +284,8 @@
compareChannels(channel2,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
- List<NotificationChannelGroup> actualGroups =
- mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, false, true).getList();
+ List<NotificationChannelGroup> actualGroups = mHelper.getNotificationChannelGroups(
+ PKG_N_MR1, UID_N_MR1, false, true, false).getList();
boolean foundNcg = false;
for (NotificationChannelGroup actual : actualGroups) {
if (ncg.getId().equals(actual.getId())) {
@@ -354,8 +354,8 @@
compareChannels(channel3,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), false));
- List<NotificationChannelGroup> actualGroups =
- mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, false, true).getList();
+ List<NotificationChannelGroup> actualGroups = mHelper.getNotificationChannelGroups(
+ PKG_N_MR1, UID_N_MR1, false, true, false).getList();
boolean foundNcg = false;
for (NotificationChannelGroup actual : actualGroups) {
if (ncg.getId().equals(actual.getId())) {
@@ -1350,8 +1350,8 @@
mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG_N_MR1}, new int[]{
UID_N_MR1});
- assertEquals(0,
- mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true).getList().size());
+ assertEquals(0, mHelper.getNotificationChannelGroups(
+ PKG_N_MR1, UID_N_MR1, true, true, false).getList().size());
}
@Test
@@ -1440,8 +1440,8 @@
new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH);
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false);
- List<NotificationChannelGroup> actual =
- mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true).getList();
+ List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(
+ PKG_N_MR1, UID_N_MR1, true, true, false).getList();
assertEquals(3, actual.size());
for (NotificationChannelGroup group : actual) {
if (group.getId() == null) {
@@ -1473,13 +1473,13 @@
new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
channel1.setGroup(ncg.getId());
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
- mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true).getList();
+ mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true, false).getList();
channel1.setImportance(IMPORTANCE_LOW);
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true);
- List<NotificationChannelGroup> actual =
- mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true).getList();
+ List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(
+ PKG_N_MR1, UID_N_MR1, true, true, false).getList();
assertEquals(2, actual.size());
for (NotificationChannelGroup group : actual) {
@@ -1490,6 +1490,32 @@
}
@Test
+ public void testGetChannelGroups_includeEmptyGroups() {
+ NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
+ mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
+ NotificationChannelGroup ncgEmpty = new NotificationChannelGroup("group2", "name2");
+ mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncgEmpty, true);
+
+ NotificationChannel channel1 =
+ new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+ channel1.setGroup(ncg.getId());
+ mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
+
+ List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups(
+ PKG_N_MR1, UID_N_MR1, false, false, true).getList();
+
+ assertEquals(2, actual.size());
+ for (NotificationChannelGroup group : actual) {
+ if (Objects.equals(group.getId(), ncg.getId())) {
+ assertEquals(1, group.getChannels().size());
+ }
+ if (Objects.equals(group.getId(), ncgEmpty.getId())) {
+ assertEquals(0, group.getChannels().size());
+ }
+ }
+ }
+
+ @Test
public void testCreateChannel_updateName() throws Exception {
NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false);
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 024bd30..a39e885 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -22,6 +22,8 @@
import android.os.Bundle;
import android.os.SystemClock;
import android.telecom.Connection.VideoProvider;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
import android.util.ArraySet;
import java.util.ArrayList;
@@ -573,6 +575,20 @@
}
/**
+ * Updates RIL voice radio technology used for current conference after its creation.
+ *
+ * @hide
+ */
+ public void updateCallRadioTechAfterCreation() {
+ final Connection primaryConnection = getPrimaryConnection();
+ if (primaryConnection != null) {
+ setCallRadioTech(primaryConnection.getCallRadioTech());
+ } else {
+ Log.w(this, "No primary connection found while updateCallRadioTechAfterCreation");
+ }
+ }
+
+ /**
* @hide
* @deprecated Use {@link #setConnectionTime}.
*/
@@ -652,6 +668,37 @@
}
/**
+ * Sets RIL voice radio technology used for current conference.
+ *
+ * @param vrat the RIL voice radio technology used for current conference,
+ * see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
+ *
+ * @hide
+ */
+ public final void setCallRadioTech(@ServiceState.RilRadioTechnology int vrat) {
+ putExtra(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+ ServiceState.rilRadioTechnologyToNetworkType(vrat));
+ }
+
+ /**
+ * Returns RIL voice radio technology used for current conference.
+ *
+ * @return the RIL voice radio technology used for current conference,
+ * see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
+ *
+ * @hide
+ */
+ public final @ServiceState.RilRadioTechnology int getCallRadioTech() {
+ int voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ Bundle extras = getExtras();
+ if (extras != null) {
+ voiceNetworkType = extras.getInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+ TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ }
+ return ServiceState.networkTypeToRilRadioTechnology(voiceNetworkType);
+ }
+
+ /**
* Inform this Conference that the state of its audio output has been changed externally.
*
* @param state The new audio state.
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 3d2b397..120d172 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -38,6 +38,8 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
import android.util.ArraySet;
import android.view.Surface;
@@ -1885,6 +1887,24 @@
}
/**
+ * Returns RIL voice radio technology used for current connection.
+ *
+ * @return the RIL voice radio technology used for current connection,
+ * see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
+ *
+ * @hide
+ */
+ public final @ServiceState.RilRadioTechnology int getCallRadioTech() {
+ int voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ Bundle extras = getExtras();
+ if (extras != null) {
+ voiceNetworkType = extras.getInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+ TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ }
+ return ServiceState.networkTypeToRilRadioTechnology(voiceNetworkType);
+ }
+
+ /**
* @return The status hints for this connection.
*/
public final StatusHints getStatusHints() {
@@ -2318,6 +2338,26 @@
}
/**
+ * Sets RIL voice radio technology used for current connection.
+ *
+ * @param vrat the RIL Voice Radio Technology used for current connection,
+ * see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
+ *
+ * @hide
+ */
+ public final void setCallRadioTech(@ServiceState.RilRadioTechnology int vrat) {
+ putExtra(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+ ServiceState.rilRadioTechnologyToNetworkType(vrat));
+ // Propagates the call radio technology to its parent {@link android.telecom.Conference}
+ // This action only covers non-IMS CS conference calls.
+ // For IMS PS call conference call, it can be updated via its host connection
+ // {@link #Listener.onExtrasChanged} event.
+ if (getConference() != null) {
+ getConference().setCallRadioTech(vrat);
+ }
+ }
+
+ /**
* Sets the label and icon status to display in the in-call UI.
*
* @param statusHints The status label and icon to set.
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 4e22823..b747dce3 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -317,6 +317,15 @@
"android.telecom.extra.CALL_TECHNOLOGY_TYPE";
/**
+ * Optional extra for communicating the call network technology used by a
+ * {@link android.telecom.Connection} to Telecom and InCallUI.
+ *
+ * @see {@code NETWORK_TYPE_*} in {@link android.telephony.TelephonyManager}.
+ */
+ public static final String EXTRA_CALL_NETWORK_TYPE =
+ "android.telecom.extra.CALL_NETWORK_TYPE";
+
+ /**
* An optional {@link android.content.Intent#ACTION_CALL} intent extra denoting the
* package name of the app specifying an alternative gateway for the call.
* The value is a string.
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 722df67..4846092 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -1233,6 +1233,17 @@
"android.provider.action.EXTERNAL_PROVIDER_CHANGE";
/**
+ * Same as {@link #ACTION_DEFAULT_SMS_PACKAGE_CHANGED} but it's implicit (e.g. sent to
+ * all apps) and requires
+ * {@link android.Manifest.permission#MONITOR_DEFAULT_SMS_PACKAGE} to receive.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL =
+ "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL";
+
+ /**
* Read the PDUs out of an {@link #SMS_RECEIVED_ACTION} or a
* {@link #DATA_SMS_RECEIVED_ACTION} intent.
*
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 7506d00..8590176 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1966,6 +1966,17 @@
"skip_cf_fail_to_disable_dialog_bool";
/**
+ * Flag specifying whether operator supports including no reply condition timer option on
+ * CFNRy (3GPP TS 24.082 3: Call Forwarding on No Reply) in the call forwarding settings UI.
+ * {@code true} - include no reply condition timer option on CFNRy
+ * {@code false} - don't include no reply condition timer option on CFNRy
+ *
+ * @hide
+ */
+ public static final String KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL =
+ "support_no_reply_timer_for_cfnry_bool";
+
+ /**
* List of the FAC (feature access codes) to dial as a normal call.
* @hide
*/
@@ -2418,6 +2429,7 @@
sDefaults.putBoolean(KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false);
sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false);
sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
+ sDefaults.putBoolean(KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL, true);
sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_IDENTIFY_HIGH_DEFINITION_CALLS_IN_CALL_LOG_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_PRECISE_FAILED_CAUSE_BOOL, false);
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index 91e24a9..e40bae1 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -603,7 +603,7 @@
/**
* Returns the message body as a String, if it exists and is text based.
- * @return message body is there is one, otherwise null
+ * @return message body if there is one, otherwise null
*/
public String getMessageBody() {
return mWrappedSmsMessage.getMessageBody();
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index ec26622..22c1e58 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -33,11 +33,13 @@
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
/**
* A Parcelable class for Subscription Information.
@@ -552,11 +554,49 @@
String cardIdToPrint = givePrintableIccid(mCardId);
return "{id=" + mId + ", iccId=" + iccIdToPrint + " simSlotIndex=" + mSimSlotIndex
+ " displayName=" + mDisplayName + " carrierName=" + mCarrierName
- + " nameSource=" + mNameSource + " iconTint=" + mIconTint
+ + " nameSource=" + mNameSource + " iconTint=" + mIconTint + " mNumber=" + mNumber
+ " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
- + " mnc " + mMnc + " isEmbedded " + mIsEmbedded
+ + " mnc " + mMnc + "mCountryIso=" + mCountryIso + " isEmbedded " + mIsEmbedded
+ " accessRules " + Arrays.toString(mAccessRules)
+ " cardId=" + cardIdToPrint + " isOpportunistic " + mIsOpportunistic
+ " parentSubId=" + mParentSubId + "}";
}
-}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
+ mIsOpportunistic, mParentSubId, mIccId, mNumber, mMcc, mMnc, mCountryIso,
+ mCardId, mDisplayName, mCarrierName, mAccessRules);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) return false;
+ if (obj == this) return true;
+
+ SubscriptionInfo toCompare;
+ try {
+ toCompare = (SubscriptionInfo) obj;
+ } catch (ClassCastException ex) {
+ return false;
+ }
+
+ return mId == toCompare.mId
+ && mSimSlotIndex == toCompare.mSimSlotIndex
+ && mNameSource == toCompare.mNameSource
+ && mIconTint == toCompare.mIconTint
+ && mDataRoaming == toCompare.mDataRoaming
+ && mIsEmbedded == toCompare.mIsEmbedded
+ && mIsOpportunistic == toCompare.mIsOpportunistic
+ && mParentSubId == toCompare.mParentSubId
+ && Objects.equals(mIccId, toCompare.mIccId)
+ && Objects.equals(mNumber, toCompare.mNumber)
+ && Objects.equals(mMcc, toCompare.mMcc)
+ && Objects.equals(mMnc, toCompare.mMnc)
+ && Objects.equals(mCountryIso, toCompare.mCountryIso)
+ && Objects.equals(mCardId, toCompare.mCardId)
+ && TextUtils.equals(mDisplayName, toCompare.mDisplayName)
+ && TextUtils.equals(mCarrierName, toCompare.mCarrierName)
+ && Arrays.equals(mAccessRules, toCompare.mAccessRules);
+ }
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b5d1f06..a8bcbe3 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -69,6 +69,7 @@
import com.android.internal.telephony.IPhoneSubInfo;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.ITelephonyRegistry;
+import com.android.internal.telephony.OperatorInfo;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.TelephonyProperties;
@@ -5789,21 +5790,46 @@
* @param persistSelection whether the selection will persist until reboot. If true, only allows
* attaching to the selected PLMN until reboot; otherwise, attach to the chosen PLMN and resume
* normal network selection next time.
- * @return true on success; false on any failure.
+ * @return {@code true} on success; {@code false} on any failure.
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public boolean setNetworkSelectionModeManual(String operatorNumeric, boolean persistSelection) {
+ return setNetworkSelectionModeManual(
+ new OperatorInfo(
+ "" /* operatorAlphaLong */, "" /* operatorAlphaShort */, operatorNumeric),
+ persistSelection);
+ }
+
+ /**
+ * Ask the radio to connect to the input network and change selection mode to manual.
+ *
+ * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
+ * @param operatorInfo included the PLMN id, long name, short name of the operator to attach to.
+ * @param persistSelection whether the selection will persist until reboot. If true, only allows
+ * attaching to the selected PLMN until reboot; otherwise, attach to the chosen PLMN and resume
+ * normal network selection next time.
+ * @return {@code true} on success; {@code true} on any failure.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public boolean setNetworkSelectionModeManual(
+ OperatorInfo operatorInfo, boolean persistSelection) {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
return telephony.setNetworkSelectionModeManual(
- getSubId(), operatorNumeric, persistSelection);
+ getSubId(), operatorInfo, persistSelection);
}
} catch (RemoteException ex) {
Rlog.e(TAG, "setNetworkSelectionModeManual RemoteException", ex);
- } catch (NullPointerException ex) {
- Rlog.e(TAG, "setNetworkSelectionModeManual NPE", ex);
}
return false;
}
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index f0d3c89..df7bd3e 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -245,7 +245,8 @@
* constants, the values passed for the {@link #EXTRA_CALL_RAT_TYPE} should be strings (e.g.
* "14" vs (int) 14).
* Note: This is used by {@link com.android.internal.telephony.imsphone.ImsPhoneConnection#
- * updateWifiStateFromExtras(Bundle)} to determine whether to set the
+ * updateImsCallRatFromExtras(Bundle)} to determine whether to set the
+ * {@link android.telecom.TelecomManager#EXTRA_CALL_NETWORK_TYPE} extra value and
* {@link android.telecom.Connection#PROPERTY_WIFI} property on a connection.
*/
public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index c0bccde..e1c770c 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -865,14 +865,15 @@
* Ask the radio to connect to the input network and change selection mode to manual.
*
* @param subId the id of the subscription.
- * @param operatorNumeric the PLMN of the operator to attach to.
- * @param persistSelection Whether the selection will persist until reboot. If true, only allows
+ * @param operatorInfo the operator inforamtion, included the PLMN, long name and short name of
+ * the operator to attach to.
+ * @param persistSelection whether the selection will persist until reboot. If true, only allows
* attaching to the selected PLMN until reboot; otherwise, attach to the chosen PLMN and resume
* normal network selection next time.
- * @return true if the request suceeded.
+ * @return {@code true} on success; {@code true} on any failure.
*/
- boolean setNetworkSelectionModeManual(int subId, in String operatorNumeric,
- boolean persistSelection);
+ boolean setNetworkSelectionModeManual(
+ int subId, in OperatorInfo operatorInfo, boolean persisSelection);
/**
* Set the preferred network type.
@@ -1586,4 +1587,19 @@
* Return the network selection mode on the subscription with id {@code subId}.
*/
int getNetworkSelectionMode(int subId);
+
+ /**
+ * Get a list of SMS apps on a user.
+ */
+ String[] getSmsApps(int userId);
+
+ /**
+ * Get the default SMS app on a given user.
+ */
+ String getDefaultSmsApp(int userId);
+
+ /**
+ * Set the default SMS app to a given package on a given user.
+ */
+ void setDefaultSmsApp(int userId, String packageName);
}
diff --git a/telephony/java/com/android/internal/telephony/OperatorInfo.java b/telephony/java/com/android/internal/telephony/OperatorInfo.java
index d0245a0..a47e2b0 100644
--- a/telephony/java/com/android/internal/telephony/OperatorInfo.java
+++ b/telephony/java/com/android/internal/telephony/OperatorInfo.java
@@ -21,7 +21,7 @@
import android.os.Parcelable;
/**
- * {@hide}
+ * @hide
*/
public class OperatorInfo implements Parcelable {
public enum State {
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index d8ef429..39722c6 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -209,7 +209,14 @@
* Support smsto Uri scheme.
*/
public static Collection<SmsApplicationData> getApplicationCollection(Context context) {
- int userId = getIncomingUserId(context);
+ return getApplicationCollectionAsUser(context, getIncomingUserId(context));
+ }
+
+ /**
+ * Same as {@link #getApplicationCollection} but it takes a target user ID.
+ */
+ public static Collection<SmsApplicationData> getApplicationCollectionAsUser(Context context,
+ int userId) {
final long token = Binder.clearCallingIdentity();
try {
return getApplicationCollectionInternal(context, userId);
@@ -535,13 +542,20 @@
* needs to have permission to set AppOps and write to secure settings.
*/
public static void setDefaultApplication(String packageName, Context context) {
+ setDefaultApplicationAsUser(packageName, context, getIncomingUserId(context));
+ }
+
+ /**
+ * Same as {@link #setDefaultApplication} but takes a target user id.
+ */
+ public static void setDefaultApplicationAsUser(String packageName, Context context,
+ int userId) {
TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
if (!tm.isSmsCapable()) {
// No phone, no SMS
return;
}
- final int userId = getIncomingUserId(context);
final long token = Binder.clearCallingIdentity();
try {
setDefaultApplicationInternal(packageName, context, userId);
@@ -552,6 +566,8 @@
private static void setDefaultApplicationInternal(String packageName, Context context,
int userId) {
+ final UserHandle userHandle = UserHandle.of(userId);
+
// Get old package name
String oldPackageName = Settings.Secure.getStringForUser(context.getContentResolver(),
Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
@@ -628,7 +644,7 @@
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "setDefaultApplicationInternal old=" + oldAppData.mPackageName);
}
- context.sendBroadcast(oldAppIntent);
+ context.sendBroadcastAsUser(oldAppIntent, userHandle);
}
// Notify the new sms app that it's now the default (if the new sms app has a receiver
// to handle the changed default sms intent).
@@ -646,8 +662,16 @@
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "setDefaultApplicationInternal new=" + packageName);
}
- context.sendBroadcast(intent);
+ context.sendBroadcastAsUser(intent, userHandle);
}
+
+ // Send an implicit broadcast for the system server.
+ // (or anyone with MONITOR_DEFAULT_SMS_PACKAGE, really.)
+ final Intent intent =
+ new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL);
+ context.sendBroadcastAsUser(intent, userHandle,
+ permission.MONITOR_DEFAULT_SMS_PACKAGE);
+
MetricsLogger.action(context, MetricsEvent.ACTION_DEFAULT_SMS_APP_CHANGED,
applicationData.mPackageName);
}
@@ -799,7 +823,18 @@
* @return component name of the app and class to deliver SMS messages to
*/
public static ComponentName getDefaultSmsApplication(Context context, boolean updateIfNeeded) {
- int userId = getIncomingUserId(context);
+ return getDefaultSmsApplicationAsUser(context, updateIfNeeded, getIncomingUserId(context));
+ }
+
+ /**
+ * Gets the default SMS application on a given user
+ * @param context context from the calling app
+ * @param updateIfNeeded update the default app if there is no valid default app configured.
+ * @param userId target user ID.
+ * @return component name of the app and class to deliver SMS messages to
+ */
+ public static ComponentName getDefaultSmsApplicationAsUser(Context context,
+ boolean updateIfNeeded, int userId) {
final long token = Binder.clearCallingIdentity();
try {
ComponentName component = null;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 06378ba..23ea237 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -21,6 +21,7 @@
import android.app.AppOpsManager;
import android.content.Context;
import android.os.Binder;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.Rlog;
@@ -307,4 +308,17 @@
Rlog.e(LOG_TAG, "Phone process is down, cannot check carrier privileges");
return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
}
+
+ /**
+ * Throws if the caller is not of a shell (or root) UID.
+ *
+ * @param callingUid pass Binder.callingUid().
+ */
+ public static void enforceShellOnly(int callingUid, String message) {
+ if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
+ return; // okay
+ }
+
+ throw new SecurityException(message + ": Only shell user can call it");
+ }
}
diff --git a/tests/ImfTest/Android.mk b/tests/ImfTest/Android.mk
deleted file mode 100644
index a8f5b08..0000000
--- a/tests/ImfTest/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := ImfTest
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/ImfTest/AndroidManifest.xml b/tests/ImfTest/AndroidManifest.xml
deleted file mode 100644
index 82dbe75..0000000
--- a/tests/ImfTest/AndroidManifest.xml
+++ /dev/null
@@ -1,146 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.imftest">
-
- <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-
- <application>
-
- <activity android:name=".samples.InputTypeActivity" android:label="Input Type Activity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.ButtonActivity" android:label="Button Activity">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.BigEditTextActivityNonScrollablePanScan" android:label="Big ET !Scroll Pan/Scan">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.ManyEditTextActivityNoScrollPanScan" android:label="ManyEditTextActivityNoScrollPanScan">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.BigEditTextActivityNonScrollableResize" android:label="Big ET !Scroll Resize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.BigEditTextActivityScrollablePanScan" android:label="Big ET Scroll Pan/Scan">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.BigEditTextActivityScrollableResize" android:label="Big ET Scroll Resize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.EditTextActivityDialog" android:label="ET Dialog">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.ManyEditTextActivityScrollPanScan" android:label="ManyEditTextActivityScrollPanScan">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.ManyEditTextActivityScrollResize" android:label="ManyEditTextActivityScrollResize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.BottomEditTextActivityPanScan" android:label="BottomEditTextActivityPanScan">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.BottomEditTextActivityResize" android:label="BottomEditTextActivityResize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.OneEditTextActivitySelected" android:label="OneEditTextActivitySelected">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.OneEditTextActivityNotSelected" android:label="OneEditTextActivityNotSelected">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.AutoCompleteTextViewActivityPortrait" android:label="AutoCompleteTextViewActivityPortrait" android:screenOrientation="portrait">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.AutoCompleteTextViewActivityLandscape" android:label="AutoCompleteTextViewActivityLandscape" android:screenOrientation="landscape">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- <activity android:name=".samples.DialogActivity" android:label="DialogActivity" android:screenOrientation="portrait">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER" />
- <category android:name="android.intent.category.IMF_TEST" />
- </intent-filter>
- </activity>
-
- </application>
-
-</manifest>
diff --git a/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml b/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml
deleted file mode 100644
index 1a2b7eb..0000000
--- a/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:padding="20dip"
- android:orientation="vertical">
-
- <View
- android:id="@+id/blank"
- android:layout_height="0dip"
- android:layout_width="match_parent"
- android:layout_weight="1"/>
-
- <EditText
- android:id="@+id/dialog_edit_text"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:scrollHorizontally="true"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
-</LinearLayout>
diff --git a/tests/ImfTest/res/layout/full_screen_edit_text.xml b/tests/ImfTest/res/layout/full_screen_edit_text.xml
deleted file mode 100644
index e760ac1..0000000
--- a/tests/ImfTest/res/layout/full_screen_edit_text.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/samples/SampleCode/res/layout/baseline_1.xml
-**
-** Copyright 2009, 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.
-*/
--->
-
-<EditText xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/data"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:minLines="15"
- android:gravity="top"/>
-
diff --git a/tests/ImfTest/res/layout/one_edit_text_activity.xml b/tests/ImfTest/res/layout/one_edit_text_activity.xml
deleted file mode 100644
index 0558228..0000000
--- a/tests/ImfTest/res/layout/one_edit_text_activity.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/samples/SampleCode/res/layout/baseline_1.xml
-**
-** Copyright 2007, 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.
-*/
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:baselineAligned="false">
-
- <View android:id="@+id/blank"
- android:layout_height="0dip"
- android:layout_width="match_parent"
- android:layout_weight="1"
- />
-
- <EditText android:id="@+id/dialog_edit_text"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:scrollHorizontally="true"
- android:textAppearance="?android:attr/textAppearanceMedium"
- />
- </LinearLayout>
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:background="@android:drawable/divider_horizontal_dark"
- />
-</LinearLayout>
diff --git a/tests/ImfTest/res/layout/sample_edit_text.xml b/tests/ImfTest/res/layout/sample_edit_text.xml
deleted file mode 100644
index 3ff6767..0000000
--- a/tests/ImfTest/res/layout/sample_edit_text.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/samples/SampleCode/res/layout/baseline_1.xml
-**
-** Copyright 2007, 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.
-*/
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:orientation="horizontal"
- android:baselineAligned="false"
- android:gravity="center_vertical"
- >
-
- <TextView android:id="@+id/label"
- android:layout_width="100dip"
- android:layout_height="wrap_content"
- android:gravity="right|center_vertical"
- />
-
- <EditText android:id="@+id/data"
- android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:layout_marginLeft="8dip"
- />
- </LinearLayout>
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:background="@android:drawable/divider_horizontal_dark"
- />
-</LinearLayout>
diff --git a/tests/ImfTest/res/values/config.xml b/tests/ImfTest/res/values/config.xml
deleted file mode 100644
index 5ae40a3..0000000
--- a/tests/ImfTest/res/values/config.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/**
- * Copyright (c) 2009, 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.
- */
--->
-<resources>
- <bool name="def_expect_ime_autopop">false</bool>
-</resources>
diff --git a/tests/ImfTest/res/values/strings.xml b/tests/ImfTest/res/values/strings.xml
deleted file mode 100644
index fc87480..0000000
--- a/tests/ImfTest/res/values/strings.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2008, 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.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Strings for sample activities -->
- <string name="normal_edit_text_label">Normal</string>
- <string name="uri_edit_text_label">Uri</string>
- <string name="email_address_edit_text_label">Email Address</string>
- <string name="email_subject_edit_text_label">Email Subject</string>
- <string name="email_content_edit_text_label">Email Content</string>
- <string name="person_name_edit_text_label">Person Name</string>
- <string name="postal_address_edit_text_label">Postal Address</string>
- <string name="password_edit_text_label">Password</string>
- <string name="search_string_edit_text_label">Search String</string>
- <string name="web_edit_text_label">Web Edit Text</string>
- <string name="signed_number_edit_text_label">Signed Number</string>
- <string name="decimal_number_edit_text_label">Decimal Number</string>
- <string name="phone_number_edit_text_label">Phone Number</string>
- <string name="normal_datetime_edit_text_label">Datetime</string>
- <string name="date_edit_text_label">Date</string>
- <string name="time_edit_text_label">Time</string>
- <string name="cap_chars_edit_text_label">Cap Chars</string>
- <string name="cap_words_edit_text_label">Cap Words</string>
- <string name="multiline_edit_text_label">Multiline</string>
- <string name="search_edit_text_label">Search (flag)</string>
- <string name="cap_sentences_edit_text_label">Cap Sentences</string>
- <string name="auto_complete_edit_text_label">Auto Complete</string>
- <string name="auto_correct_edit_text_label">Auto Correct</string>
- <string name="test_dialog">Test Dialog</string>
- <string name="open_dialog_scrollable">open scrollable dialog</string>
- <string name="open_dialog_nonscrollable">open nonscrollable dialog</string>
-
-
-</resources>
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java
deleted file mode 100644
index 6115fd5..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2009 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.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.provider.MediaStore;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.AutoCompleteTextView;
-import android.widget.ArrayAdapter;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-
-import com.android.internal.R;
-
-/*
- * Activity with AutoCompleteTextView forced to landscape mode
- */
-public class AutoCompleteTextViewActivityLandscape extends Activity
-{
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.auto_complete_list);
-
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
- android.R.layout.simple_dropdown_item_1line, COUNTRIES);
- AutoCompleteTextView textView = findViewById(R.id.edit);
- textView.setAdapter(adapter);
- }
-
- static final String[] COUNTRIES = new String[] {
- "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
- "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
- "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
- "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
- "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
- "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
- "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
- "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
- "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
- "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
- "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czechia",
- "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
- "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
- "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
- "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
- "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
- "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
- "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
- "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
- "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
- "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
- "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
- "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
- "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
- "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
- "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
- "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
- "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
- "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
- "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
- "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
- "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
- "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
- "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
- "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
- "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
- "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
- "Ukraine", "United Arab Emirates", "United Kingdom",
- "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
- "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
- "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
- };
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java
deleted file mode 100644
index 253c50f..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2009 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.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.AutoCompleteTextView;
-import android.widget.ArrayAdapter;
-
-import com.android.internal.R;
-
-/*
- * Activity with AutoCompleteTextView (Candidate bar should not appear)
- */
-public class AutoCompleteTextViewActivityPortrait extends Activity
-{
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.auto_complete_list);
-
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
- android.R.layout.simple_dropdown_item_1line, COUNTRIES);
- AutoCompleteTextView textView = findViewById(R.id.edit);
- textView.setAdapter(adapter);
- }
-
- static final String[] COUNTRIES = new String[] {
- "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
- "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
- "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
- "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
- "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
- "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
- "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
- "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
- "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
- "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
- "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czechia",
- "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
- "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
- "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
- "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
- "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
- "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
- "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
- "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
- "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
- "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
- "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
- "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
- "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
- "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
- "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
- "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
- "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
- "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
- "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
- "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
- "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
- "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
- "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
- "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
- "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
- "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
- "Ukraine", "United Arab Emirates", "United Kingdom",
- "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
- "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
- "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
- };
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java
deleted file mode 100644
index 033082f..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2009 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.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-
-public class BigEditTextActivityNonScrollablePanScan extends Activity {
-
- private View mRootView;
- private View mDefaultFocusedView;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
-
- mRootView = new LinearLayout(this);
- ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
- mRootView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- View view = getLayoutInflater().inflate(
- R.layout.full_screen_edit_text, ((LinearLayout) mRootView), false);
-
- ((LinearLayout) mRootView).addView(view);
-
- mDefaultFocusedView = view.findViewById(R.id.data);
-
- setContentView(mRootView);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
- public View getDefaultFocusedView() {
- return mDefaultFocusedView;
- }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java
deleted file mode 100644
index 8a16dea..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2009 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.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-
-public class BigEditTextActivityNonScrollableResize extends Activity {
-
- private View mRootView;
- private View mDefaultFocusedView;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
-
- mRootView = new LinearLayout(this);
- ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
- mRootView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- View view = getLayoutInflater().inflate(
- R.layout.full_screen_edit_text, ((LinearLayout) mRootView), false);
-
- ((LinearLayout) mRootView).addView(view);
-
- mDefaultFocusedView = view.findViewById(R.id.data);
-
- setContentView(mRootView);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
- public View getDefaultFocusedView() {
- return mDefaultFocusedView;
- }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java
deleted file mode 100644
index b4fdc4c..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2009 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.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-
-public class BigEditTextActivityScrollablePanScan extends Activity {
-
- private View mRootView;
- private View mDefaultFocusedView;
- private LinearLayout mLayout;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
-
- mRootView = new ScrollView(this);
- ((ScrollView) mRootView).setFillViewport(true);
- mRootView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- mLayout = new LinearLayout(this);
- mLayout.setOrientation(LinearLayout.VERTICAL);
- mLayout.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- View view = getLayoutInflater().inflate(
- R.layout.full_screen_edit_text, ((ScrollView) mRootView), false);
-
- mLayout.addView(view);
-
- ((ScrollView) mRootView).addView(mLayout);
- mDefaultFocusedView = view.findViewById(R.id.data);
-
- setContentView(mRootView);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
- public View getDefaultFocusedView() {
- return mDefaultFocusedView;
- }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java
deleted file mode 100644
index 757b6b5..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2009 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.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-
-public class BigEditTextActivityScrollableResize extends Activity {
-
- private View mRootView;
- private View mDefaultFocusedView;
- private LinearLayout mLayout;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
-
- mRootView = new ScrollView(this);
- ((ScrollView) mRootView).setFillViewport(true);
- mRootView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- mLayout = new LinearLayout(this);
- mLayout.setOrientation(LinearLayout.VERTICAL);
- mLayout.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- View view = getLayoutInflater().inflate(
- R.layout.full_screen_edit_text, ((ScrollView) mRootView), false);
-
- mLayout.addView(view);
-
- ((ScrollView) mRootView).addView(mLayout);
- mDefaultFocusedView = view.findViewById(R.id.data);
-
- setContentView(mRootView);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
- public View getDefaultFocusedView() {
- return mDefaultFocusedView;
- }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java
deleted file mode 100644
index 91a329d..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2009 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.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.EditText;
-import android.widget.ScrollView;
-import android.widget.TextView;
-
-import com.android.imftest.R;
-
-/*
- * Activity with EditText at the bottom (Pan&Scan)
- */
-public class BottomEditTextActivityPanScan extends Activity
-{
- private View mRootView;
- private View mDefaultFocusedView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- mRootView = new LinearLayout(this);
- ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
-
- View view = getLayoutInflater().inflate(R.layout.one_edit_text_activity, ((LinearLayout) mRootView), false);
- mDefaultFocusedView = view.findViewById(R.id.dialog_edit_text);
- ((LinearLayout) mRootView).addView(view);
-
- setContentView(mRootView);
- this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
- public View getDefaultFocusedView() {
- return mDefaultFocusedView;
- }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java
deleted file mode 100644
index c4c41bc..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2009 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.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.EditText;
-import android.widget.ScrollView;
-import android.widget.TextView;
-
-import com.android.imftest.R;
-
-/*
- * Activity with EditText at the bottom (Resize)
- */
-public class BottomEditTextActivityResize extends Activity
-{
- private View mRootView;
- private View mDefaultFocusedView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- mRootView = new LinearLayout(this);
- ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
-
- View view = getLayoutInflater().inflate(R.layout.one_edit_text_activity, ((LinearLayout) mRootView), false);
- mDefaultFocusedView = view.findViewById(R.id.dialog_edit_text);
- ((LinearLayout) mRootView).addView(view);
-
- setContentView(mRootView);
- this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
- public View getDefaultFocusedView() {
- return mDefaultFocusedView;
- }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java b/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
deleted file mode 100644
index dbaedf9..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2009 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.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.Button;
-import android.widget.TextView;
-
-public class ButtonActivity extends Activity
-{
- static boolean mKeyboardIsActive = false;
- public static final int BUTTON_ID = 0;
- private View mRootView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- final ButtonActivity instance = this;
-
- final Button myButton = new Button(this);
- myButton.setClickable(true);
- myButton.setText("Keyboard UP!");
- myButton.setId(BUTTON_ID);
- myButton.setFocusableInTouchMode(true);
- myButton.setOnClickListener(new View.OnClickListener()
- {
- public void onClick (View v)
- {
- InputMethodManager imm = InputMethodManager.getInstance();
- if (mKeyboardIsActive)
- {
- imm.hideSoftInputFromInputMethod(v.getWindowToken(), 0);
- myButton.setText("Keyboard UP!");
-
- }
- else
- {
- myButton.requestFocusFromTouch();
- imm.showSoftInput(v, 0);
- myButton.setText("Keyboard DOWN!");
- }
-
- mKeyboardIsActive = !mKeyboardIsActive;
- }
- });
-
- LinearLayout layout = new LinearLayout(this);
- layout.setOrientation(LinearLayout.VERTICAL);
- layout.addView(myButton);
- setContentView(layout);
- mRootView = layout;
- }
-
- public View getRootView() {
- return mRootView;
- }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java b/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java
deleted file mode 100644
index 3ed0386..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2009 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.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-import android.widget.EditText;
-import android.widget.Button;
-import android.view.LayoutInflater;
-import android.app.Dialog;
-
-public class DialogActivity extends Activity {
-
- private static final int DIALOG_WITHOUT_EDITTEXT = 0;
- private static final int DIALOG_WITH_EDITTEXT = 1;
-
- private LinearLayout mLayout;
- private LayoutInflater mInflater;
- private Button mButton1;
- private Button mButton2;
- private EditText mEditText;
-
-
- @Override
- protected void onCreate(Bundle icicle)
- {
- super.onCreate(icicle);
-
- mLayout = new LinearLayout(this);
- mLayout.setOrientation(LinearLayout.VERTICAL);
- mLayout.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- mButton1 = new Button(this);
- mButton1.setText("Dialog WITHOUT EditText");//(R.string.open_dialog_scrollable);
- mButton1.setOnClickListener(new View.OnClickListener()
- {
- public void onClick(View v)
- {
- showDialog(DIALOG_WITHOUT_EDITTEXT);
- }
- });
-
- mButton2 = new Button(this);
- mButton2.setText("Dialog WITH EditText");//(R.string.open_dialog_nonscrollable);
- mButton2.setOnClickListener(new View.OnClickListener()
- {
- public void onClick(View v)
- {
- showDialog(DIALOG_WITH_EDITTEXT);
- }
- });
-
- mEditText = new EditText(this);
- mLayout.addView(mEditText);
- mLayout.addView(mButton1);
- mLayout.addView(mButton2);
-
- setContentView(mLayout);
- }
-
- @Override
- protected Dialog onCreateDialog(int id)
- {
- switch (id)
- {
- case DIALOG_WITHOUT_EDITTEXT:
- return createDialog(false);
- case DIALOG_WITH_EDITTEXT:
- return createDialog(true);
- }
-
- return super.onCreateDialog(id);
- }
-
- protected Dialog createDialog(boolean bEditText)
- {
- LinearLayout layout;
- layout = new LinearLayout(this);
- layout.setOrientation(LinearLayout.VERTICAL);
-
- if(bEditText)
- {
- EditText editText;
- editText = new EditText(this);
- layout.addView(editText);
- }
-
- Dialog d = new Dialog(this);
- d.setTitle("The DIALOG!!!");
- d.setCancelable(true);
- d.setContentView(layout);
- return d;
- }
-
- }
diff --git a/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java b/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java
deleted file mode 100644
index 2591b7c..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2009 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.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-
-public class EditTextActivityDialog extends Activity {
-
- private static final int SCROLLABLE_DIALOG_ID = 0;
- private static final int NONSCROLLABLE_DIALOG_ID = 1;
-
- private LinearLayout mLayout;
- private ScrollView mScrollView;
- private LayoutInflater mInflater;
- private Button mButton1;
- private Button mButton2;
-
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- mLayout = new LinearLayout(this);
- mLayout.setOrientation(LinearLayout.VERTICAL);
- mLayout.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- mButton1 = new Button(this);
- mButton1.setText(R.string.open_dialog_scrollable);
- mButton1.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- showDialog(SCROLLABLE_DIALOG_ID);
- }
- });
-
- mButton2 = new Button(this);
- mButton2.setText(R.string.open_dialog_nonscrollable);
- mButton2.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- showDialog(NONSCROLLABLE_DIALOG_ID);
- }
- });
-
- mLayout.addView(mButton1);
- mLayout.addView(mButton2);
-
- setContentView(mLayout);
- }
-
- @Override
- protected Dialog onCreateDialog(int id) {
- switch (id) {
- case SCROLLABLE_DIALOG_ID:
- return createDialog(true);
- case NONSCROLLABLE_DIALOG_ID:
- return createDialog(false);
- }
-
- return super.onCreateDialog(id);
- }
-
- protected Dialog createDialog(boolean scrollable) {
- View layout;
- EditText editText;
-
- if (scrollable) {
- layout = new ScrollView(EditTextActivityDialog.this);
- ((ScrollView) layout).setMinimumHeight(mLayout.getHeight());
-
- ((ScrollView) layout).addView((
- LinearLayout) View.inflate(EditTextActivityDialog.this,
- R.layout.dialog_edit_text_no_scroll, null));
- } else {
- layout = View.inflate(EditTextActivityDialog.this,
- R.layout.dialog_edit_text_no_scroll, null);
- }
-
- Dialog d = new Dialog(EditTextActivityDialog.this);
- d.setTitle(getString(R.string.test_dialog));
- d.setCancelable(true);
- d.setContentView(layout);
- return d;
- }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java b/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java
deleted file mode 100644
index 299e6bb..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.app.Activity;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-import android.widget.TextView;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.inputmethod.EditorInfo;
-
-public class InputTypeActivity extends Activity {
-
- private LinearLayout mLayout;
- private ScrollView mScrollView;
- private LayoutInflater mInflater;
- private ViewGroup mParent;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- mScrollView = new ScrollView(this);
-
- mLayout = new LinearLayout(this);
- mLayout.setOrientation(LinearLayout.VERTICAL);
- mLayout.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- mInflater = getLayoutInflater();
- mParent = mLayout;
-
- /* Normal Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL,
- R.string.normal_edit_text_label));
-
- /* Normal Edit Text w/Cap Chars Flag*/
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS,
- R.string.cap_chars_edit_text_label));
-
- /* Normal Edit Text w/Cap Words Flag*/
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS,
- R.string.cap_words_edit_text_label));
-
- /* Normal Edit Text w/Cap Multiline Flag */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE,
- R.string.multiline_edit_text_label));
-
- /* Normal Edit Text w/Cap Sentences Flag */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES,
- R.string.cap_sentences_edit_text_label));
-
- /* Normal Edit Text w/Auto-complete Flag */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE,
- R.string.auto_complete_edit_text_label));
-
- /* Normal Edit Text w/Auto-correct Flag */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT,
- R.string.auto_correct_edit_text_label));
-
- /* Uri Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_URI,
- R.string.uri_edit_text_label));
-
- /* Email Address Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS,
- R.string.email_address_edit_text_label));
-
- /* Email Subject Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_EMAIL_SUBJECT,
- R.string.email_subject_edit_text_label));
-
- /* Email Content Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_LONG_MESSAGE,
- R.string.email_content_edit_text_label));
-
- /* Person Name Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME,
- R.string.person_name_edit_text_label));
-
- /* Postal Address Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_POSTAL_ADDRESS,
- R.string.postal_address_edit_text_label));
-
- /* Password Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_PASSWORD,
- R.string.password_edit_text_label));
-
- /* Web Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT,
- R.string.web_edit_text_label));
-
- /* Signed Number Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_NUMBER|EditorInfo.TYPE_NUMBER_FLAG_SIGNED,
- R.string.signed_number_edit_text_label));
-
- /* Decimal Number Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_NUMBER|EditorInfo.TYPE_NUMBER_FLAG_DECIMAL,
- R.string.decimal_number_edit_text_label));
-
- /* Phone Number Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_PHONE,
- R.string.phone_number_edit_text_label));
-
- /* Normal Datetime Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_DATETIME|EditorInfo.TYPE_DATETIME_VARIATION_NORMAL,
- R.string.normal_datetime_edit_text_label));
-
- /* Date Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_DATETIME|EditorInfo.TYPE_DATETIME_VARIATION_DATE,
- R.string.date_edit_text_label));
-
- /* Time Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_DATETIME|EditorInfo.TYPE_DATETIME_VARIATION_TIME,
- R.string.time_edit_text_label));
-
- mScrollView.addView(mLayout);
- setContentView(mScrollView);
- }
-
- private View buildEntryView(int inputType, int label) {
-
-
- View view = mInflater.inflate(R.layout.sample_edit_text, mParent, false);
-
- EditText editText = (EditText) view.findViewById(R.id.data);
- editText.setInputType(inputType);
-
- TextView textView = (TextView) view.findViewById(R.id.label);
- textView.setText(label);
-
- return view;
- }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java
deleted file mode 100644
index 646e480..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2009 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.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.ScrollView;
-
-import com.android.internal.R;
-
-/*
- * Full screen of EditTexts (Non-Scrollable, Pan&Scan)
- */
-public class ManyEditTextActivityNoScrollPanScan extends Activity
-{
- public static final int NUM_EDIT_TEXTS = 9;
-
- private View mRootView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- mRootView = new LinearLayout(this);
- ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
-
- for (int i=0; i<NUM_EDIT_TEXTS; i++)
- {
- final EditText editText = new EditText(this);
- editText.setText(String.valueOf(i));
- editText.setId(i);
- ((LinearLayout) mRootView).addView(editText);
- }
- setContentView(mRootView);
- this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java
deleted file mode 100644
index 0387e1e..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2009 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.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.ScrollView;
-
-import com.android.internal.R;
-
-/*
- * Full screen of EditTexts (Scrollable, Pan&Scan)
- */
-public class ManyEditTextActivityScrollPanScan extends Activity
-{
- public static final int NUM_EDIT_TEXTS = 12;
-
- private View mRootView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- mRootView = new ScrollView(this);
-
- LinearLayout layout = new LinearLayout(this);
- layout.setOrientation(LinearLayout.VERTICAL);
-
- for (int i=0; i<NUM_EDIT_TEXTS; i++)
- {
- final EditText editText = new EditText(this);
- editText.setText(String.valueOf(i));
- editText.setId(i);
- layout.addView(editText);
- }
-
- ((ScrollView) mRootView).addView(layout);
- setContentView(mRootView);
- this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
- }
-
- public View getRootView() {
- return mRootView;
- }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java
deleted file mode 100644
index 7793b55..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2009 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.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.widget.EditText;
-import android.widget.ScrollView;
-
-/*
- * Full screen of EditTexts (Scrollable, Resize)
- */
-public class ManyEditTextActivityScrollResize extends Activity
-{
- public static final int NUM_EDIT_TEXTS = 12;
-
- private View mRootView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- mRootView = new ScrollView(this);
-
- LinearLayout layout = new LinearLayout(this);
- layout.setOrientation(LinearLayout.VERTICAL);
-
- for (int i=0; i<NUM_EDIT_TEXTS; i++)
- {
- final EditText editText = new EditText(this);
- editText.setText(String.valueOf(i));
- editText.setId(i);
- layout.addView(editText);
- }
-
- ((ScrollView) mRootView).addView(layout);
- setContentView(mRootView);
- this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
- }
-
- public View getRootView() {
- return mRootView;
- }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java
deleted file mode 100644
index c4be21c..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2009 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.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.os.Debug;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.ScrollView;
-
-import com.android.internal.R;
-
-/*
- * Activity with non-EditText view selected initially
- */
-public class OneEditTextActivityNotSelected extends Activity
-{
- private View mRootView;
- private View mDefaultFocusedView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- LinearLayout layout = new LinearLayout(this);
- layout.setOrientation(LinearLayout.VERTICAL);
- mRootView = new ScrollView(this);
-
- EditText editText = new EditText(this);
- Button button = new Button(this);
- button.setText("The focus is here.");
- button.setFocusableInTouchMode(true);
- button.requestFocus();
- mDefaultFocusedView = button;
- layout.addView(button);
- layout.addView(editText);
-
- ((ScrollView) mRootView).addView(layout);
- setContentView(mRootView);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
- public View getDefaultFocusedView() {
- return mDefaultFocusedView;
- }
-}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
deleted file mode 100644
index 64882aa..0000000
--- a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2009 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.imftest.samples;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.LinearLayout;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.ScrollView;
-
-import com.android.internal.R;
-
-/*
- * Activity with EditText selected initially
- */
-public class OneEditTextActivitySelected extends Activity
-{
- private View mRootView;
- private View mDefaultFocusedView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- LinearLayout layout = new LinearLayout(this);
- layout.setOrientation(LinearLayout.VERTICAL);
- mRootView = new ScrollView(this);
-
- EditText editText = new EditText(this);
- editText.requestFocus();
- mDefaultFocusedView = editText;
- layout.addView(editText);
-
- ((ScrollView) mRootView).addView(layout);
- setContentView(mRootView);
-
- // set to resize so IME is always shown (and also so
- // ImfBaseTestCase#destructiveCheckImeInitialState thinks it should always be shown
- this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
- }
-
- public View getRootView() {
- return mRootView;
- }
-
- public View getDefaultFocusedView() {
- return mDefaultFocusedView;
- }
-}
diff --git a/tests/ImfTest/tests/Android.mk b/tests/ImfTest/tests/Android.mk
deleted file mode 100644
index 14186d7..0000000
--- a/tests/ImfTest/tests/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-
-LOCAL_PACKAGE_NAME := ImfTestTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_INSTRUMENTATION_FOR := ImfTest
-
-include $(BUILD_PACKAGE)
diff --git a/tests/ImfTest/tests/AndroidManifest.xml b/tests/ImfTest/tests/AndroidManifest.xml
deleted file mode 100644
index c02fa0b..0000000
--- a/tests/ImfTest/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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 name must be unique so suffix with "tests" so package loader doesn't ignore us -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.imftest.tests">
-
- <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <!--
- This declares that this app uses the instrumentation test runner targeting
- the package of com.android.imftest. To run the tests use the command:
- "adb shell am instrument -w com.android.imftest.tests/android.test.InstrumentationTestRunner"
- -->
- <instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.android.imftest"
- android:label="imf tests"/>
-
-</manifest>
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java
deleted file mode 100644
index 2db11c5..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BigEditTextActivityNonScrollablePanScanTests extends ImfBaseTestCase<BigEditTextActivityNonScrollablePanScan> {
-
- public final String TAG = "BigEditTextActivityNonScrollablePanScanTests";
-
- public BigEditTextActivityNonScrollablePanScanTests() {
- super(BigEditTextActivityNonScrollablePanScan.class);
- }
-
- @LargeTest
- public void testAppAdjustmentPanScan() {
- // Give the IME 2 seconds to appear.
- pause(2000);
-
- View rootView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getRootView();
- View servedView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getDefaultFocusedView();
-
- assertNotNull(rootView);
- assertNotNull(servedView);
-
- destructiveCheckImeInitialState(rootView, servedView);
-
- verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java
deleted file mode 100644
index 1050794..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BigEditTextActivityNonScrollableResizeTests extends ImfBaseTestCase<BigEditTextActivityNonScrollableResize> {
-
- public final String TAG = "BigEditTextActivityNonScrollableResizeTests";
-
- public BigEditTextActivityNonScrollableResizeTests() {
- super(BigEditTextActivityNonScrollableResize.class);
- }
-
- @LargeTest
- public void testAppAdjustmentPanScan() { // Give the IME 2 seconds to appear.
- pause(2000);
-
- View rootView = ((BigEditTextActivityNonScrollableResize) mTargetActivity).getRootView();
- View servedView = ((BigEditTextActivityNonScrollableResize) mTargetActivity).getDefaultFocusedView();
-
- assertNotNull(rootView);
- assertNotNull(servedView);
-
- destructiveCheckImeInitialState(rootView, servedView);
-
- verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java
deleted file mode 100644
index 1e848b0..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BigEditTextActivityScrollablePanScanTests extends ImfBaseTestCase<BigEditTextActivityScrollablePanScan> {
-
- public final String TAG = "BigEditTextActivityScrollablePanScanTests";
-
- public BigEditTextActivityScrollablePanScanTests() {
- super(BigEditTextActivityScrollablePanScan.class);
- }
-
- @LargeTest
- public void testAppAdjustmentPanScan() { // Give the IME 2 seconds to appear.
- pause(2000);
-
- View rootView = ((BigEditTextActivityScrollablePanScan) mTargetActivity).getRootView();
- View servedView = ((BigEditTextActivityScrollablePanScan) mTargetActivity).getDefaultFocusedView();
-
- assertNotNull(rootView);
- assertNotNull(servedView);
-
- destructiveCheckImeInitialState(rootView, servedView);
-
- verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java
deleted file mode 100644
index de607d6..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BigEditTextActivityScrollableResizeTests extends ImfBaseTestCase<BigEditTextActivityScrollableResize> {
-
- public final String TAG = "BigEditTextActivityScrollableResizeTests";
-
- public BigEditTextActivityScrollableResizeTests() {
- super(BigEditTextActivityScrollableResize.class);
- }
-
- @LargeTest
- public void testAppAdjustmentPanScan() {
- // Give the IME 2 seconds to appear.
- pause(2000);
-
- View rootView = ((BigEditTextActivityScrollableResize) mTargetActivity).getRootView();
- View servedView = ((BigEditTextActivityScrollableResize) mTargetActivity).getDefaultFocusedView();
-
- assertNotNull(rootView);
- assertNotNull(servedView);
-
- destructiveCheckImeInitialState(rootView, servedView);
-
- verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java
deleted file mode 100644
index c521905..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BottomEditTextActivityPanScanTests extends ImfBaseTestCase<BottomEditTextActivityPanScan> {
-
- public final String TAG = "BottomEditTextActivityPanScanTests";
-
- public BottomEditTextActivityPanScanTests() {
- super(BottomEditTextActivityPanScan.class);
- }
-
- @LargeTest
- public void testAppAdjustmentPanScan() {
- // Give the IME 2 seconds to appear.
- pause(2000);
-
- View rootView = ((BottomEditTextActivityPanScan) mTargetActivity).getRootView();
- View servedView = ((BottomEditTextActivityPanScan) mTargetActivity).getDefaultFocusedView();
-
- assertNotNull(rootView);
- assertNotNull(servedView);
-
- destructiveCheckImeInitialState(rootView, servedView);
-
- verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java
deleted file mode 100644
index 9a69fd5..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-import com.android.imftest.R;
-
-
-public class BottomEditTextActivityResizeTests extends ImfBaseTestCase<BottomEditTextActivityResize> {
-
- public final String TAG = "BottomEditTextActivityResizeTests";
-
- public BottomEditTextActivityResizeTests() {
- super(BottomEditTextActivityResize.class);
- }
-
- @LargeTest
- public void testAppAdjustmentResize() {
- // Give the IME 2 seconds to appear.
- pause(2000);
-
- View rootView = ((BottomEditTextActivityResize) mTargetActivity).getRootView();
- View servedView = ((BottomEditTextActivityResize) mTargetActivity).getDefaultFocusedView();
-
- assertNotNull(rootView);
- assertNotNull(servedView);
-
- destructiveCheckImeInitialState(rootView, servedView);
-
- verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java
deleted file mode 100644
index f6f97b5..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.KeyEvent;
-import android.widget.Button;
-
-
-public class ButtonActivityTest extends ImfBaseTestCase<ButtonActivity> {
-
- final public String TAG = "ButtonActivityTest";
-
- public ButtonActivityTest() {
- super(ButtonActivity.class);
- }
-
- @LargeTest
- public void testButtonActivatesIme() {
-
- final Button button = (Button) mTargetActivity.findViewById(ButtonActivity.BUTTON_ID);
-
- // Push button
- // Bring the target EditText into focus.
- mTargetActivity.runOnUiThread(new Runnable() {
- public void run() {
- button.requestFocus();
- }
- });
-
- sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-
- // Give it a couple seconds
- pause(2000);
-
- // We should have initialized imm.mServedView and imm.mCurrentTextBoxAttribute
- assertTrue(mImm.isActive());
- // imm.mServedInputConnection should be null since Button doesn't override onCreateInputConnection().
- assertFalse(mImm.isAcceptingText());
-
- destructiveCheckImeInitialState(mTargetActivity.getRootView(), button);
-
- }
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
deleted file mode 100644
index 32f80a3..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.app.Activity;
-import android.app.KeyguardManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.os.SystemClock;
-import android.test.InstrumentationTestCase;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.inputmethod.InputMethodManager;
-
-import com.android.imftest.R;
-
-public abstract class ImfBaseTestCase<T extends Activity> extends InstrumentationTestCase {
-
- /*
- * The amount of time we are willing to wait for the IME to appear after a user action
- * before we give up and fail the test.
- */
- public final long WAIT_FOR_IME = 5000;
-
- /*
- * Unfortunately there is now way for us to know how tall the IME is,
- * so we have to hard code a minimum and maximum value.
- */
- public final int IME_MIN_HEIGHT = 150;
- public final int IME_MAX_HEIGHT = 300;
-
- protected InputMethodManager mImm;
- protected T mTargetActivity;
- protected boolean mExpectAutoPop;
- private Class<T> mTargetActivityClass;
-
- public ImfBaseTestCase(Class<T> activityClass) {
- mTargetActivityClass = activityClass;
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- final String packageName = getInstrumentation().getTargetContext().getPackageName();
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- mTargetActivity = launchActivityWithIntent(packageName, mTargetActivityClass, intent);
- // expect ime to auto pop up if device has no hard keyboard
- int keyboardType = mTargetActivity.getResources().getConfiguration().keyboard;
- mExpectAutoPop = (keyboardType == Configuration.KEYBOARD_NOKEYS ||
- keyboardType == Configuration.KEYBOARD_UNDEFINED);
-
- mImm = InputMethodManager.getInstance();
-
- KeyguardManager keyguardManager =
- (KeyguardManager) getInstrumentation().getContext().getSystemService(
- Context.KEYGUARD_SERVICE);
- keyguardManager.newKeyguardLock("imftest").disableKeyguard();
- }
-
- // Utility test methods
- public void verifyEditTextAdjustment(final View editText, int rootViewHeight) {
-
- int[] origLocation = new int[2];
- int[] newLocation = new int[2];
-
- // Tell the keyboard to go away.
- mImm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
-
- // Bring the target EditText into focus.
- mTargetActivity.runOnUiThread(new Runnable() {
- public void run() {
- editText.requestFocus();
- }
- });
-
- // Get the original location of the EditText.
- editText.getLocationOnScreen(origLocation);
-
- // Tap the EditText to bring up the IME.
- sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-
- // Wait until the EditText pops above the IME or until we hit the timeout.
- editText.getLocationOnScreen(newLocation);
- long timeoutTime = SystemClock.uptimeMillis() + WAIT_FOR_IME;
- while (newLocation[1] > rootViewHeight - IME_MIN_HEIGHT && SystemClock.uptimeMillis() < timeoutTime) {
- editText.getLocationOnScreen(newLocation);
- pause(100);
- }
-
- assertTrue(newLocation[1] <= rootViewHeight - IME_MIN_HEIGHT);
-
- // Tell the keyboard to go away.
- mImm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
- }
-
- public void destructiveCheckImeInitialState(View rootView, View servedView) {
- int windowSoftInputMode = mTargetActivity.getWindow().getAttributes().softInputMode;
- int adjustMode = windowSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
- if (mExpectAutoPop && adjustMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
- assertTrue(destructiveCheckImeUp(rootView, servedView));
- } else {
- assertFalse(destructiveCheckImeUp(rootView, servedView));
- }
- }
-
- public boolean destructiveCheckImeUp(View rootView, View servedView) {
- int origHeight;
- int newHeight;
-
- origHeight = rootView.getHeight();
-
- // Tell the keyboard to go away.
- mImm.hideSoftInputFromWindow(servedView.getWindowToken(), 0);
-
- // Give it five seconds to adjust
- newHeight = rootView.getHeight();
- long timeoutTime = SystemClock.uptimeMillis() + WAIT_FOR_IME;
- while (Math.abs(newHeight - origHeight) < IME_MIN_HEIGHT && SystemClock.uptimeMillis() < timeoutTime) {
- newHeight = rootView.getHeight();
- }
-
- return (Math.abs(origHeight - newHeight) >= IME_MIN_HEIGHT);
- }
-
- void pause(int millis) {
- try {
- Thread.sleep(millis);
- } catch (InterruptedException e) {
- }
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java
deleted file mode 100644
index 278efb1..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.app.Activity;
-import android.widget.EditText;
-
-
-public abstract class ManyEditTextActivityBaseTestCase<T extends Activity> extends ImfBaseTestCase<T> {
-
- public ManyEditTextActivityBaseTestCase(Class<T> activityClass){
- super(activityClass);
- }
-
- public abstract void testAllEditTextsAdjust();
-
- public void verifyAllEditTextAdjustment(int numEditTexts, int rootViewHeight) {
-
- for (int i = 0; i < numEditTexts; i++) {
- final EditText lastEditText = (EditText) mTargetActivity.findViewById(i);
- verifyEditTextAdjustment(lastEditText, rootViewHeight);
- }
-
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java
deleted file mode 100644
index 4f8d14e..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-
-
-public class ManyEditTextActivityNoScrollPanScanTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityNoScrollPanScan> {
-
- public final String TAG = "ManyEditTextActivityNoScrollPanScanTests";
-
- public ManyEditTextActivityNoScrollPanScanTests() {
- super(ManyEditTextActivityNoScrollPanScan.class);
- }
-
-
- @LargeTest
- public void testAllEditTextsAdjust() {
- verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS,
- mTargetActivity.getRootView().getMeasuredHeight());
- }
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java
deleted file mode 100644
index 7f98f7f..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-
-
-public class ManyEditTextActivityScrollPanScanTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityScrollPanScan> {
-
- public final String TAG = "ManyEditTextActivityScrollPanScanTests";
-
-
- public ManyEditTextActivityScrollPanScanTests() {
- super(ManyEditTextActivityScrollPanScan.class);
- }
-
- @LargeTest
- public void testAllEditTextsAdjust() {
- verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS,
- mTargetActivity.getRootView().getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java
deleted file mode 100644
index 68dae87..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-
-
-public class ManyEditTextActivityScrollResizeTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityScrollResize> {
-
- public final String TAG = "ManyEditTextActivityScrollResizeTests";
-
-
- public ManyEditTextActivityScrollResizeTests() {
- super(ManyEditTextActivityScrollResize.class);
- }
-
- @LargeTest
- public void testAllEditTextsAdjust() {
- verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS,
- mTargetActivity.getRootView().getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java
deleted file mode 100644
index 6147d3c..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.View;
-
-
-public class OneEditTextActivityNotSelectedTests extends ImfBaseTestCase<OneEditTextActivityNotSelected> {
-
- public final String TAG = "OneEditTextActivityNotSelectedTests";
-
- public OneEditTextActivityNotSelectedTests() {
- super(OneEditTextActivityNotSelected.class);
- }
-
- @LargeTest
- public void testSoftKeyboardNoAutoPop() {
-
- // Give the IME 2 seconds to appear.
- pause(2000);
-
- assertFalse(mImm.isAcceptingText());
-
- View rootView = ((OneEditTextActivityNotSelected) mTargetActivity).getRootView();
- View servedView = ((OneEditTextActivityNotSelected) mTargetActivity).getDefaultFocusedView();
-
- assertNotNull(rootView);
- assertNotNull(servedView);
-
- destructiveCheckImeInitialState(rootView, servedView);
-
- verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
- }
-
-}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java
deleted file mode 100644
index 42fcd66..0000000
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2007 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.imftest.samples;
-
-import com.android.imftest.R;
-
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.KeyEvent;
-import android.view.View;
-
-
-public class OneEditTextActivitySelectedTests extends ImfBaseTestCase<OneEditTextActivitySelected> {
-
- public final String TAG = "OneEditTextActivitySelectedTests";
-
- public OneEditTextActivitySelectedTests() {
- super(OneEditTextActivitySelected.class);
- }
-
- @LargeTest
- public void testSoftKeyboardAutoPop() {
-
- // Give the IME 2 seconds to appear.
- pause(2000);
-
- assertTrue(mImm.isAcceptingText());
-
- View rootView = ((OneEditTextActivitySelected) mTargetActivity).getRootView();
- View servedView = ((OneEditTextActivitySelected) mTargetActivity).getDefaultFocusedView();
-
- assertNotNull(rootView);
- assertNotNull(servedView);
-
- destructiveCheckImeInitialState(rootView, servedView);
-
- verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
- }
-
-}
diff --git a/tests/NativeProcessesMemoryTest/Android.bp b/tests/NativeProcessesMemoryTest/Android.bp
new file mode 100644
index 0000000..f2625bf
--- /dev/null
+++ b/tests/NativeProcessesMemoryTest/Android.bp
@@ -0,0 +1,21 @@
+// 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.
+
+java_test_host {
+ name: "native-processes-memory-test",
+ srcs: ["src/**/*.java"],
+
+ libs: ["tradefed"],
+ test_suites: ["general-tests"],
+}
diff --git a/tests/NativeProcessesMemoryTest/AndroidTest.xml b/tests/NativeProcessesMemoryTest/AndroidTest.xml
new file mode 100644
index 0000000..0f326fd
--- /dev/null
+++ b/tests/NativeProcessesMemoryTest/AndroidTest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs the native processes memory tests">
+ <option name="test-suite-tag" value="native-processes-memory-test" />
+ <test class="com.android.tradefed.testtype.HostTest" >
+ <option name="class" value="com.android.tests.nativeprocesses.NativeProcessesMemoryTest" />
+ </test>
+</configuration>
diff --git a/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java b/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java
new file mode 100644
index 0000000..ae011a0
--- /dev/null
+++ b/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java
@@ -0,0 +1,234 @@
+/*
+ * 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.tests.nativeprocesses;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.ByteArrayInputStreamSource;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.LogDataType;
+import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.IRemoteTest;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.InputMismatchException;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Scanner;
+
+/**
+ * Test to gather native processes count and memory usage.
+ *
+ * Native processes are parsed from dumpsys meminfo --oom -c
+ *
+ * <pre>
+ * time,35857009,35857009
+ * oom,native,331721,N/A
+ * proc,native,init,1,2715,N/A,e
+ * proc,native,init,445,1492,N/A,e
+ * ...
+ * </pre>
+ *
+ * For each native process we also look at its showmap output, and gather the PSS, VSS, and RSS.
+ * The showmap output is also saved to test logs.
+ *
+ * The metrics reported are:
+ *
+ * <pre>
+ * - number of native processes
+ * - total memory use of native processes
+ * - memory usage of each native process (one measurement for each process)
+ * </pre>
+ */
+public class NativeProcessesMemoryTest implements IDeviceTest, IRemoteTest {
+ // the dumpsys process comes and go as we run this test, changing pids, so ignore it
+ private static final List<String> PROCESSES_TO_IGNORE = Arrays.asList("dumpsys");
+
+ // -c gives us a compact output which is comma separated
+ private static final String DUMPSYS_MEMINFO_OOM_CMD = "dumpsys meminfo --oom -c";
+
+ private static final String SEPARATOR = ",";
+ private static final String LINE_SEPARATOR = "\\n";
+
+ // name of this test run, used for reporting
+ private static final String RUN_NAME = "NativeProcessesTest";
+ // key used to report the number of native processes
+ private static final String NUM_NATIVE_PROCESSES_KEY = "Num_native_processes";
+
+ private final Map<String, String> mNativeProcessToMemory = new HashMap<String, String>();
+ // identity for summing over MemoryMetric
+ private final MemoryMetric mZero = new MemoryMetric(0, 0, 0);
+
+ private ITestDevice mTestDevice;
+ private ITestInvocationListener mListener;
+
+ public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
+ mListener = listener;
+ // showmap requires root, we enable it here for the rest of the test
+ mTestDevice.enableAdbRoot();
+
+ listener.testRunStarted(RUN_NAME, 0 /* testCount */);
+
+ // process name -> list of pids with that name
+ Map<String, List<String>> nativeProcesses = collectNativeProcesses();
+ sampleAndLogAllProcesses(nativeProcesses);
+
+ // want to also record the number of native processes
+ mNativeProcessToMemory.put(
+ NUM_NATIVE_PROCESSES_KEY, Integer.toString(nativeProcesses.size()));
+
+ listener.testRunEnded(0, mNativeProcessToMemory);
+ }
+
+ /** Samples memory of all processes and logs the memory use. */
+ private void sampleAndLogAllProcesses(Map<String, List<String>> nativeProcesses)
+ throws DeviceNotAvailableException {
+ for (Map.Entry<String, List<String>> entry : nativeProcesses.entrySet()) {
+ String processName = entry.getKey();
+ if (PROCESSES_TO_IGNORE.contains(processName)) {
+ continue;
+ }
+
+ // for all pids associated with this process name, record their memory usage
+ List<MemoryMetric> allMemsForProcess = new ArrayList<>();
+ for (String pid : entry.getValue()) {
+ Optional<MemoryMetric> mem = snapMemoryUsage(processName, pid);
+ if (mem.isPresent()) {
+ allMemsForProcess.add(mem.get());
+ }
+ }
+
+ // if for some reason a process does not have any MemoryMetric, don't log it
+ if (allMemsForProcess.isEmpty()) {
+ continue;
+ }
+
+ // combine all the memory metrics of process with the same name
+ MemoryMetric combined = allMemsForProcess.stream().reduce(mZero, MemoryMetric::sum);
+ logMemoryMetric(processName, combined);
+ }
+ }
+
+ @Override
+ public void setDevice(ITestDevice device) {
+ mTestDevice = device;
+ }
+
+ @Override
+ public ITestDevice getDevice() {
+ return mTestDevice;
+ }
+
+ /**
+ * Query system for a list of native process.
+ *
+ * @return a map from process name to a list of pids that share the same name
+ */
+ private Map<String, List<String>> collectNativeProcesses() throws DeviceNotAvailableException {
+ HashMap<String, List<String>> nativeProcesses = new HashMap<>();
+ String memInfo = mTestDevice.executeShellCommand(DUMPSYS_MEMINFO_OOM_CMD);
+
+ for (String line : memInfo.split(LINE_SEPARATOR)) {
+ String[] splits = line.split(SEPARATOR);
+ // ignore lines that don't list a native process
+ if (splits.length < 4 || !splits[0].equals("proc") || !splits[1].equals("native")) {
+ continue;
+ }
+
+ String processName = splits[2];
+ String pid = splits[3];
+ if (nativeProcesses.containsKey(processName)) {
+ nativeProcesses.get(processName).add(pid);
+ } else {
+ nativeProcesses.put(processName, new ArrayList<>(Arrays.asList(pid)));
+ }
+ }
+ return nativeProcesses;
+ }
+
+ /** Logs an entire showmap output to the test logs. */
+ private void logShowmap(String label, String showmap) {
+ try (ByteArrayInputStreamSource source =
+ new ByteArrayInputStreamSource(showmap.getBytes())) {
+ mListener.testLog(label + "_showmap", LogDataType.TEXT, source);
+ }
+ }
+
+ /**
+ * Extract VSS, PSS, and RSS from showmap of a process.
+ * The showmap output is also added to test logs.
+ */
+ private Optional<MemoryMetric> snapMemoryUsage(String processName, String pid)
+ throws DeviceNotAvailableException {
+ // TODO(zhin): copied from com.android.tests.sysmem.host.Metrics#sample(), extract?
+ String showmap = mTestDevice.executeShellCommand("showmap " + pid);
+ logShowmap(processName + "_" + pid, showmap);
+
+ // CHECKSTYLE:OFF Generated code
+ // The last lines of the showmap output looks like:
+ // ------- -------- -------- -------- -------- -------- -------- -------- -------- ---- ------------------------------
+ // virtual shared shared private private
+ // size RSS PSS clean dirty clean dirty swap swapPSS # object
+ // -------- -------- -------- -------- -------- -------- -------- -------- -------- ---- ------------------------------
+ // 12848 4240 1543 2852 64 36 1288 0 0 171 TOTAL
+ // CHECKSTYLE:ON Generated code
+ try {
+ int pos = showmap.lastIndexOf("----");
+ Scanner sc = new Scanner(showmap.substring(pos));
+ sc.next();
+ long vss = sc.nextLong();
+ long rss = sc.nextLong();
+ long pss = sc.nextLong();
+ return Optional.of(new MemoryMetric(pss, rss, vss));
+ } catch (InputMismatchException e) {
+ // this might occur if we have transient processes, it was collected earlier,
+ // but by the time we look at showmap the process is gone
+ CLog.e("Unable to parse MemoryMetric from showmap of pid: " + pid + " processName: "
+ + processName);
+ CLog.e(showmap);
+ return Optional.empty();
+ }
+ }
+
+ /** Logs a MemoryMetric of a process. */
+ private void logMemoryMetric(String processName, MemoryMetric memoryMetric) {
+ mNativeProcessToMemory.put(processName + "_pss", Long.toString(memoryMetric.pss));
+ mNativeProcessToMemory.put(processName + "_rss", Long.toString(memoryMetric.rss));
+ mNativeProcessToMemory.put(processName + "_vss", Long.toString(memoryMetric.vss));
+ }
+
+ /** Container of memory numbers we want to log. */
+ private final class MemoryMetric {
+ final long pss;
+ final long rss;
+ final long vss;
+
+ MemoryMetric(long pss, long rss, long vss) {
+ this.pss = pss;
+ this.rss = rss;
+ this.vss = vss;
+ }
+
+ MemoryMetric sum(MemoryMetric other) {
+ return new MemoryMetric(
+ pss + other.pss, rss + other.rss, vss + other.vss);
+ }
+ }
+}
diff --git a/tests/net/AndroidManifest.xml b/tests/net/AndroidManifest.xml
index ba1a2ea..6dae3f1 100644
--- a/tests/net/AndroidManifest.xml
+++ b/tests/net/AndroidManifest.xml
@@ -44,6 +44,7 @@
<uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+ <uses-permission android:name="android.permission.NETWORK_STACK" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
new file mode 100644
index 0000000..39ecb7e5a
--- /dev/null
+++ b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
@@ -0,0 +1,337 @@
+/*
+ * 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 android.net.netlink;
+
+import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
+import static android.os.Process.INVALID_UID;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.IPPROTO_TCP;
+import static android.system.OsConstants.IPPROTO_UDP;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_STREAM;
+import static android.system.OsConstants.SOL_SOCKET;
+import static android.system.OsConstants.SO_RCVTIMEO;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.netlink.StructNlMsgHdr;
+import android.os.Process;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
+import android.support.test.InstrumentationRegistry;
+import android.system.Os;
+import android.system.StructTimeval;
+import android.util.Log;
+import java.io.FileDescriptor;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import libcore.util.HexEncoding;
+
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class InetDiagSocketTest {
+ private final String TAG = "InetDiagSocketTest";
+ private ConnectivityManager mCm;
+ private Context mContext;
+ private final static int SOCKET_TIMEOUT_MS = 100;
+ private boolean mInetDiagUdpEnabled;
+
+ @Before
+ public void setUp() throws Exception {
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ mContext = instrumentation.getTargetContext();
+ mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ int expectedUid = Process.myUid();
+ UdpConnection udp = new UdpConnection("127.0.0.1", "127.0.0.2");
+ int uid = mCm.getConnectionOwnerUid(udp.protocol, udp.local, udp.remote);
+ mInetDiagUdpEnabled = (uid == expectedUid);
+ }
+
+ private class Connection {
+ public int socketDomain;
+ public int socketType;
+ public InetAddress localAddress;
+ public InetAddress remoteAddress;
+ public InetAddress localhostAddress;
+ public InetSocketAddress local;
+ public InetSocketAddress remote;
+ public int protocol;
+ public FileDescriptor localFd;
+ public FileDescriptor remoteFd;
+
+ public FileDescriptor createSocket() throws Exception {
+ return Os.socket(socketDomain, socketType, protocol);
+ }
+
+ public Connection(String to, String from) throws Exception {
+ remoteAddress = InetAddress.getByName(to);
+ if (from != null) {
+ localAddress = InetAddress.getByName(from);
+ } else {
+ localAddress = (remoteAddress instanceof Inet4Address) ?
+ Inet4Address.getByName("localhost") : Inet6Address.getByName("::");
+ }
+ if ((localAddress instanceof Inet4Address) && (remoteAddress instanceof Inet4Address)) {
+ socketDomain = AF_INET;
+ localhostAddress = Inet4Address.getByName("localhost");
+ } else {
+ socketDomain = AF_INET6;
+ localhostAddress = Inet6Address.getByName("::");
+ }
+ }
+
+ public void close() throws Exception {
+ Os.close(localFd);
+ }
+ }
+
+ private class TcpConnection extends Connection {
+ public TcpConnection(String to, String from) throws Exception {
+ super(to, from);
+ protocol = IPPROTO_TCP;
+ socketType = SOCK_STREAM;
+
+ remoteFd = createSocket();
+ Os.bind(remoteFd, remoteAddress, 0);
+ Os.listen(remoteFd, 10);
+ int remotePort = ((InetSocketAddress) Os.getsockname(remoteFd)).getPort();
+
+ localFd = createSocket();
+ Os.bind(localFd, localAddress, 0);
+ Os.connect(localFd, remoteAddress, remotePort);
+
+ local = (InetSocketAddress) Os.getsockname(localFd);
+ remote = (InetSocketAddress) Os.getpeername(localFd);
+ }
+
+ public void close() throws Exception {
+ super.close();
+ Os.close(remoteFd);
+ }
+ }
+ private class UdpConnection extends Connection {
+ public UdpConnection(String to, String from) throws Exception {
+ super(to, from);
+ protocol = IPPROTO_UDP;
+ socketType = SOCK_DGRAM;
+
+ remoteFd = null;
+ localFd = createSocket();
+ Os.bind(localFd, localAddress, 0);
+
+ Os.connect(localFd, remoteAddress, 7);
+ local = (InetSocketAddress) Os.getsockname(localFd);
+ remote = new InetSocketAddress(remoteAddress, 7);
+ }
+ }
+
+ private void checkConnectionOwnerUid(int protocol, InetSocketAddress local,
+ InetSocketAddress remote, boolean expectSuccess) {
+ final int expectedUid = expectSuccess ? Process.myUid() : INVALID_UID;
+ final int uid = mCm.getConnectionOwnerUid(protocol, local, remote);
+ assertEquals(expectedUid, uid);
+ }
+
+ private int findLikelyFreeUdpPort(UdpConnection conn) throws Exception {
+ UdpConnection udp = new UdpConnection(conn.remoteAddress.getHostAddress(),
+ conn.localAddress.getHostAddress());
+ final int localPort = udp.local.getPort();
+ udp.close();
+ return localPort;
+ }
+
+ public void checkGetConnectionOwnerUid(String to, String from) throws Exception {
+ /**
+ * For TCP connections, create a test connection and verify that this
+ * {protocol, local, remote} socket result in receiving a valid UID.
+ */
+ TcpConnection tcp = new TcpConnection(to, from);
+ checkConnectionOwnerUid(tcp.protocol, tcp.local, tcp.remote, true);
+ checkConnectionOwnerUid(IPPROTO_UDP, tcp.local, tcp.remote, false);
+ checkConnectionOwnerUid(tcp.protocol, new InetSocketAddress(0), tcp.remote, false);
+ checkConnectionOwnerUid(tcp.protocol, tcp.local, new InetSocketAddress(0), false);
+ tcp.close();
+
+ /**
+ * TODO: STOPSHIP: Always test for UDP, do not allow opt-out.
+ */
+ if (!mInetDiagUdpEnabled) return;
+
+ /**
+ * For UDP connections, either a complete match {protocol, local, remote} or a
+ * partial match {protocol, local} should return a valid UID.
+ */
+ UdpConnection udp = new UdpConnection(to,from);
+ checkConnectionOwnerUid(udp.protocol, udp.local, udp.remote, true);
+ checkConnectionOwnerUid(udp.protocol, udp.local, new InetSocketAddress(0), true);
+ checkConnectionOwnerUid(IPPROTO_TCP, udp.local, udp.remote, false);
+ checkConnectionOwnerUid(udp.protocol, new InetSocketAddress(findLikelyFreeUdpPort(udp)),
+ udp.remote, false);
+ udp.close();
+ }
+
+ @Test
+ public void testGetConnectionOwnerUid() throws Exception {
+ checkGetConnectionOwnerUid("::", null);
+ checkGetConnectionOwnerUid("::", "::");
+ checkGetConnectionOwnerUid("0.0.0.0", null);
+ checkGetConnectionOwnerUid("0.0.0.0", "0.0.0.0");
+ checkGetConnectionOwnerUid("127.0.0.1", null);
+ checkGetConnectionOwnerUid("127.0.0.1", "127.0.0.2");
+ checkGetConnectionOwnerUid("::1", null);
+ checkGetConnectionOwnerUid("::1", "::1");
+ }
+
+ // Hexadecimal representation of InetDiagReqV2 request.
+ private static final String INET_DIAG_REQ_V2_UDP_INET4_HEX =
+ // struct nlmsghdr
+ "48000000" + // length = 72
+ "1400" + // type = SOCK_DIAG_BY_FAMILY
+ "0103" + // flags = NLM_F_REQUEST | NLM_F_DUMP
+ "00000000" + // seqno
+ "00000000" + // pid (0 == kernel)
+ // struct inet_diag_req_v2
+ "02" + // family = AF_INET
+ "11" + // protcol = IPPROTO_UDP
+ "00" + // idiag_ext
+ "00" + // pad
+ "ffffffff" + // idiag_states
+ // inet_diag_sockid
+ "a5de" + // idiag_sport = 42462
+ "b971" + // idiag_dport = 47473
+ "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2
+ "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8
+ "00000000" + // idiag_if
+ "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
+ private static final byte[] INET_DIAG_REQ_V2_UDP_INET4_BYTES =
+ HexEncoding.decode(INET_DIAG_REQ_V2_UDP_INET4_HEX.toCharArray(), false);
+
+ @Test
+ public void testInetDiagReqV2UdpInet4() throws Exception {
+ InetSocketAddress local = new InetSocketAddress(InetAddress.getByName("10.0.100.2"),
+ 42462);
+ InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
+ 47473);
+ final byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_UDP, local, remote, AF_INET,
+ (short) (NLM_F_REQUEST | NLM_F_DUMP));
+ assertArrayEquals(INET_DIAG_REQ_V2_UDP_INET4_BYTES, msg);
+ }
+
+ // Hexadecimal representation of InetDiagReqV2 request.
+ private static final String INET_DIAG_REQ_V2_TCP_INET6_HEX =
+ // struct nlmsghdr
+ "48000000" + // length = 72
+ "1400" + // type = SOCK_DIAG_BY_FAMILY
+ "0100" + // flags = NLM_F_REQUEST
+ "00000000" + // seqno
+ "00000000" + // pid (0 == kernel)
+ // struct inet_diag_req_v2
+ "0a" + // family = AF_INET6
+ "06" + // protcol = IPPROTO_TCP
+ "00" + // idiag_ext
+ "00" + // pad
+ "ffffffff" + // idiag_states
+ // inet_diag_sockid
+ "a5de" + // idiag_sport = 42462
+ "b971" + // idiag_dport = 47473
+ "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b
+ "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8
+ "00000000" + // idiag_if
+ "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
+ private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_BYTES =
+ HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_HEX.toCharArray(), false);
+
+ @Test
+ public void testInetDiagReqV2TcpInet6() throws Exception {
+ InetSocketAddress local = new InetSocketAddress(
+ InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462);
+ InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
+ 47473);
+ byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6,
+ NLM_F_REQUEST);
+
+ assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg);
+ }
+
+ // Hexadecimal representation of InetDiagReqV2 request.
+ private static final String INET_DIAG_MSG_HEX =
+ // struct nlmsghdr
+ "58000000" + // length = 88
+ "1400" + // type = SOCK_DIAG_BY_FAMILY
+ "0200" + // flags = NLM_F_MULTI
+ "00000000" + // seqno
+ "f5220000" + // pid (0 == kernel)
+ // struct inet_diag_msg
+ "0a" + // family = AF_INET6
+ "01" + // idiag_state
+ "00" + // idiag_timer
+ "00" + // idiag_retrans
+ // inet_diag_sockid
+ "a817" + // idiag_sport = 43031
+ "960f" + // idiag_dport = 38415
+ "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b
+ "00000000000000000000ffff08080808" + // idiag_dst = 8.8.8.8
+ "00000000" + // idiag_if
+ "ffffffffffffffff" + // idiag_cookie = INET_DIAG_NOCOOKIE
+ "00000000" + // idiag_expires
+ "00000000" + // idiag_rqueue
+ "00000000" + // idiag_wqueue
+ "a3270000" + // idiag_uid
+ "A57E1900"; // idiag_inode
+ private static final byte[] INET_DIAG_MSG_BYTES =
+ HexEncoding.decode(INET_DIAG_MSG_HEX.toCharArray(), false);
+
+ @Test
+ public void testParseInetDiagResponse() throws Exception {
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES);
+ byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
+ final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
+ assertNotNull(msg);
+
+ assertTrue(msg instanceof InetDiagMessage);
+ final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg;
+ assertEquals(10147, inetDiagMsg.mStructInetDiagMsg.idiag_uid);
+
+ final StructNlMsgHdr hdr = inetDiagMsg.getHeader();
+ assertNotNull(hdr);
+ assertEquals(NetlinkConstants.SOCK_DIAG_BY_FAMILY, hdr.nlmsg_type);
+ assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags);
+ assertEquals(0, hdr.nlmsg_seq);
+ assertEquals(8949, hdr.nlmsg_pid);
+ }
+}
diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py
index 6c46e67..fdc800b 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists.py
@@ -212,8 +212,8 @@
move_from_files(args.input_greylists, uncategorized, light_greylist)
move_from_files(args.input_blacklists, uncategorized, blacklist)
- # Iterate over all uncategorized members and move serialization API to light greylist.
- move_serialization(uncategorized, light_greylist)
+ # Iterate over all uncategorized members and move serialization API to whitelist.
+ move_serialization(uncategorized, whitelist)
# Extract package names of members from whitelist and light greylist, which
# are assumed to have been finalized at this point. Assign all uncategorized
diff --git a/tools/hiddenapi/generate_hiddenapi_lists_test.py b/tools/hiddenapi/generate_hiddenapi_lists_test.py
index 8f79318..4716241 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists_test.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists_test.py
@@ -85,5 +85,23 @@
self.assertEqual(
dst, set([ "Lfoo/bar/ClassA;->abc()J", "Lfoo/bar/ClassA;->def()J" ]))
+ def test_move_serialization(self):
+ # All the entries should be moved apart from the last one
+ src = set([ "Lfoo/bar/ClassA;->readObject(Ljava/io/ObjectInputStream;)V",
+ "Lfoo/bar/ClassA;->readObjectNoData()V",
+ "Lfoo/bar/ClassA;->readResolve()Ljava/lang/Object;",
+ "Lfoo/bar/ClassA;->serialVersionUID:J",
+ "Lfoo/bar/ClassA;->serialPersistentFields:[Ljava/io/ObjectStreamField;",
+ "Lfoo/bar/ClassA;->writeObject(Ljava/io/ObjectOutputStream;)V",
+ "Lfoo/bar/ClassA;->writeReplace()Ljava/lang/Object;",
+ # Should not be moved as signature does not match
+ "Lfoo/bar/ClassA;->readObject(Ljava/io/ObjectInputStream;)I"])
+ expectedToMove = len(src) - 1
+ dst = set()
+ packages = set([ "Lfoo/bar/" ])
+ move_serialization(src, dst)
+ self.assertEqual(len(src), 1)
+ self.assertEqual(len(dst), expectedToMove)
+
if __name__ == '__main__':
unittest.main()
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index 639f980..0cf1046 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -138,7 +138,7 @@
size_t base = 0;
size_t found;
while (true) {
- found = args.find_first_of(" ", base);
+ found = args.find_first_of(' ', base);
if (found != base) {
string arg = args.substr(base, found - base);
printf(" \"%s\",", arg.c_str());