Merge "Add logic in DreamBackend to parse dream description."
diff --git a/Android.bp b/Android.bp
index acd3b34..cf3c017 100644
--- a/Android.bp
+++ b/Android.bp
@@ -160,6 +160,7 @@
"android.net.ipsec.ike.stubs.module_lib",
"framework-appsearch.stubs.module_lib",
"framework-connectivity.stubs.module_lib",
+ "framework-connectivity-tiramisu.stubs.module_lib",
"framework-graphics.stubs.module_lib",
"framework-media.stubs.module_lib",
"framework-mediaprovider.stubs.module_lib",
@@ -192,6 +193,7 @@
"framework-minus-apex",
"framework-appsearch.impl",
"framework-connectivity.impl",
+ "framework-connectivity-tiramisu.impl",
"framework-graphics.impl",
"framework-mediaprovider.impl",
"framework-permission.impl",
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 7a4ef2a..feb43d1 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -118,6 +118,7 @@
srcs: [
":framework-appsearch-sources",
":framework-connectivity-sources",
+ ":framework-connectivity-tiramisu-updatable-sources",
":framework-graphics-srcs",
":framework-mediaprovider-sources",
":framework-nearby-sources",
@@ -164,6 +165,7 @@
":android.net.ipsec.ike{.public.stubs.source}",
":framework-appsearch{.public.stubs.source}",
":framework-connectivity{.public.stubs.source}",
+ ":framework-connectivity-tiramisu{.public.stubs.source}",
":framework-graphics{.public.stubs.source}",
":framework-media{.public.stubs.source}",
":framework-mediaprovider{.public.stubs.source}",
@@ -204,6 +206,7 @@
":art.module.public.api{.public.annotations.zip}",
":framework-appsearch{.public.annotations.zip}",
":framework-connectivity{.public.annotations.zip}",
+ ":framework-connectivity-tiramisu{.public.annotations.zip}",
":framework-graphics{.public.annotations.zip}",
":framework-media{.public.annotations.zip}",
":framework-mediaprovider{.public.annotations.zip}",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 9543fbd..3b38860 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -249,6 +249,7 @@
"conscrypt.module.public.api.stubs",
"framework-appsearch.stubs",
"framework-connectivity.stubs",
+ "framework-connectivity-tiramisu.stubs",
"framework-graphics.stubs",
"framework-media.stubs",
"framework-mediaprovider.stubs",
@@ -271,6 +272,7 @@
"conscrypt.module.public.api.stubs", // Only has public stubs
"framework-appsearch.stubs.system",
"framework-connectivity.stubs.system",
+ "framework-connectivity-tiramisu.stubs.system",
"framework-graphics.stubs.system",
"framework-media.stubs.system",
"framework-mediaprovider.stubs.system",
diff --git a/TEST_MAPPING b/TEST_MAPPING
index c5c6012..81e4fcb 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -17,6 +17,19 @@
],
"presubmit": [
{
+ "file_patterns": [
+ "ApexManager\\.java",
+ "SystemServer\\.java",
+ "services/tests/apexsystemservices/.*"
+ ],
+ "name": "ApexSystemServicesTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
"name": "FrameworksUiServicesTests",
"options": [
{
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java b/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java
index 530dc9d..15a65ce 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java
@@ -130,7 +130,8 @@
IntentSender getIntentSender(int sessionId) {
String action = BROADCAST_ACTION + "." + sessionId;
IntentFilter filter = new IntentFilter(action);
- mContext.registerReceiver(this, filter);
+ mContext.registerReceiver(this, filter,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
Intent intent = new Intent(action);
PendingIntent pending = PendingIntent.getBroadcast(mContext, sessionId, intent,
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobService.java b/apex/jobscheduler/framework/java/android/app/job/JobService.java
index c251529a..e5b0742 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobService.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobService.java
@@ -125,7 +125,7 @@
* will not be invoked.
*
* @param params Parameters specifying info about this job, including the optional
- * extras configured with {@link JobInfo.Builder#setExtras(android.os.PersistableBundle).
+ * extras configured with {@link JobInfo.Builder#setExtras(android.os.PersistableBundle)}.
* This object serves to identify this specific running job instance when calling
* {@link #jobFinished(JobParameters, boolean)}.
* @return {@code true} if your service will continue running, using a separate thread
diff --git a/apex/media/framework/jarjar_rules.txt b/apex/media/framework/jarjar_rules.txt
index 91489dc..1bd5b36 100644
--- a/apex/media/framework/jarjar_rules.txt
+++ b/apex/media/framework/jarjar_rules.txt
@@ -1,2 +1,4 @@
rule com.android.modules.** android.media.internal.@1
rule com.google.android.exoplayer2.** android.media.internal.exo.@1
+rule com.google.common.** android.media.internal.guava_common.@1
+rule com.google.thirdparty.** android.media.internal.guava_thirdparty.@1
diff --git a/apex/media/framework/java/android/media/MediaCommunicationManager.java b/apex/media/framework/java/android/media/MediaCommunicationManager.java
index 8ee9616..ef5552e 100644
--- a/apex/media/framework/java/android/media/MediaCommunicationManager.java
+++ b/apex/media/framework/java/android/media/MediaCommunicationManager.java
@@ -36,6 +36,8 @@
import androidx.annotation.RequiresApi;
+import androidx.annotation.RequiresApi;
+
import com.android.internal.annotations.GuardedBy;
import com.android.modules.annotation.MinSdk;
import com.android.modules.utils.build.SdkLevel;
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index b6f85c7..7daebd0 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -62,8 +62,8 @@
import com.google.android.exoplayer2.upstream.DataReader;
import com.google.android.exoplayer2.util.ParsableByteArray;
import com.google.android.exoplayer2.util.TimestampAdjuster;
-import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.ColorInfo;
+import com.google.common.base.Ascii;
import java.io.EOFException;
import java.io.IOException;
@@ -978,7 +978,7 @@
@ParserName
public static List<String> getParserNames(@NonNull MediaFormat mediaFormat) {
String mimeType = mediaFormat.getString(MediaFormat.KEY_MIME);
- mimeType = mimeType == null ? null : Util.toLowerInvariant(mimeType.trim());
+ mimeType = mimeType == null ? null : Ascii.toLowerCase(mimeType);
if (TextUtils.isEmpty(mimeType)) {
// No MIME type provided. Return all.
return Collections.unmodifiableList(
@@ -1420,7 +1420,7 @@
int flags = 0;
TimestampAdjuster timestampAdjuster = null;
if (mIgnoreTimestampOffset) {
- timestampAdjuster = new TimestampAdjuster(TimestampAdjuster.DO_NOT_OFFSET);
+ timestampAdjuster = new TimestampAdjuster(TimestampAdjuster.MODE_NO_OFFSET);
}
switch (parserName) {
case PARSER_NAME_MATROSKA:
diff --git a/api/Android.bp b/api/Android.bp
index 1ec1b3c..51422b3 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -97,6 +97,7 @@
":conscrypt.module.public.api{.public.api.txt}",
":framework-appsearch{.public.api.txt}",
":framework-connectivity{.public.api.txt}",
+ ":framework-connectivity-tiramisu{.public.api.txt}",
":framework-graphics{.public.api.txt}",
":framework-media{.public.api.txt}",
":framework-mediaprovider{.public.api.txt}",
@@ -159,6 +160,7 @@
":conscrypt.module.public.api{.public.stubs.source}",
":framework-appsearch{.public.stubs.source}",
":framework-connectivity{.public.stubs.source}",
+ ":framework-connectivity-tiramisu{.public.stubs.source}",
":framework-graphics{.public.stubs.source}",
":framework-media{.public.stubs.source}",
":framework-mediaprovider{.public.stubs.source}",
@@ -188,6 +190,7 @@
":conscrypt.module.public.api{.public.removed-api.txt}",
":framework-appsearch{.public.removed-api.txt}",
":framework-connectivity{.public.removed-api.txt}",
+ ":framework-connectivity-tiramisu{.public.removed-api.txt}",
":framework-graphics{.public.removed-api.txt}",
":framework-media{.public.removed-api.txt}",
":framework-mediaprovider{.public.removed-api.txt}",
@@ -231,6 +234,7 @@
":android.net.ipsec.ike{.system.api.txt}",
":framework-appsearch{.system.api.txt}",
":framework-connectivity{.system.api.txt}",
+ ":framework-connectivity-tiramisu{.system.api.txt}",
":framework-graphics{.system.api.txt}",
":framework-media{.system.api.txt}",
":framework-mediaprovider{.system.api.txt}",
@@ -292,6 +296,7 @@
":android.net.ipsec.ike{.system.removed-api.txt}",
":framework-appsearch{.system.removed-api.txt}",
":framework-connectivity{.system.removed-api.txt}",
+ ":framework-connectivity-tiramisu{.system.removed-api.txt}",
":framework-graphics{.system.removed-api.txt}",
":framework-media{.system.removed-api.txt}",
":framework-mediaprovider{.system.removed-api.txt}",
@@ -335,6 +340,7 @@
":android.net.ipsec.ike{.module-lib.api.txt}",
":framework-appsearch{.module-lib.api.txt}",
":framework-connectivity{.module-lib.api.txt}",
+ ":framework-connectivity-tiramisu{.module-lib.api.txt}",
":framework-graphics{.module-lib.api.txt}",
":framework-media{.module-lib.api.txt}",
":framework-mediaprovider{.module-lib.api.txt}",
@@ -398,6 +404,7 @@
":android.net.ipsec.ike{.module-lib.removed-api.txt}",
":framework-appsearch{.module-lib.removed-api.txt}",
":framework-connectivity{.module-lib.removed-api.txt}",
+ ":framework-connectivity-tiramisu{.module-lib.removed-api.txt}",
":framework-graphics{.module-lib.removed-api.txt}",
":framework-media{.module-lib.removed-api.txt}",
":framework-mediaprovider{.module-lib.removed-api.txt}",
@@ -519,6 +526,7 @@
":conscrypt.module.public.api.stubs{.jar}",
":framework-appsearch.stubs{.jar}",
":framework-connectivity.stubs{.jar}",
+ ":framework-connectivity-tiramisu.stubs{.jar}",
":framework-graphics.stubs{.jar}",
":framework-media.stubs{.jar}",
":framework-mediaprovider.stubs{.jar}",
diff --git a/boot/hiddenapi/hiddenapi-max-target-o.txt b/boot/hiddenapi/hiddenapi-max-target-o.txt
index 0ec918b..9153426 100644
--- a/boot/hiddenapi/hiddenapi-max-target-o.txt
+++ b/boot/hiddenapi/hiddenapi-max-target-o.txt
@@ -36441,93 +36441,6 @@
Landroid/net/MobileLinkQualityInfo;->mLteSignalStrength:I
Landroid/net/MobileLinkQualityInfo;->mMobileNetworkType:I
Landroid/net/MobileLinkQualityInfo;->mRssi:I
-Landroid/net/nsd/DnsSdTxtRecord;-><init>()V
-Landroid/net/nsd/DnsSdTxtRecord;-><init>(Landroid/net/nsd/DnsSdTxtRecord;)V
-Landroid/net/nsd/DnsSdTxtRecord;-><init>([B)V
-Landroid/net/nsd/DnsSdTxtRecord;->contains(Ljava/lang/String;)Z
-Landroid/net/nsd/DnsSdTxtRecord;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/net/nsd/DnsSdTxtRecord;->get(Ljava/lang/String;)Ljava/lang/String;
-Landroid/net/nsd/DnsSdTxtRecord;->getKey(I)Ljava/lang/String;
-Landroid/net/nsd/DnsSdTxtRecord;->getRawData()[B
-Landroid/net/nsd/DnsSdTxtRecord;->getValue(I)[B
-Landroid/net/nsd/DnsSdTxtRecord;->getValue(Ljava/lang/String;)[B
-Landroid/net/nsd/DnsSdTxtRecord;->getValueAsString(I)Ljava/lang/String;
-Landroid/net/nsd/DnsSdTxtRecord;->insert([B[BI)V
-Landroid/net/nsd/DnsSdTxtRecord;->keyCount()I
-Landroid/net/nsd/DnsSdTxtRecord;->mData:[B
-Landroid/net/nsd/DnsSdTxtRecord;->mSeperator:B
-Landroid/net/nsd/DnsSdTxtRecord;->remove(Ljava/lang/String;)I
-Landroid/net/nsd/DnsSdTxtRecord;->set(Ljava/lang/String;Ljava/lang/String;)V
-Landroid/net/nsd/DnsSdTxtRecord;->size()I
-Landroid/net/nsd/INsdManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/net/nsd/INsdManager$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/net/nsd/INsdManager$Stub$Proxy;->getMessenger()Landroid/os/Messenger;
-Landroid/net/nsd/INsdManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/net/nsd/INsdManager$Stub$Proxy;->setEnabled(Z)V
-Landroid/net/nsd/INsdManager$Stub;-><init>()V
-Landroid/net/nsd/INsdManager$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/net/nsd/INsdManager$Stub;->TRANSACTION_getMessenger:I
-Landroid/net/nsd/INsdManager$Stub;->TRANSACTION_setEnabled:I
-Landroid/net/nsd/INsdManager;->setEnabled(Z)V
-Landroid/net/nsd/NsdManager;-><init>(Landroid/content/Context;Landroid/net/nsd/INsdManager;)V
-Landroid/net/nsd/NsdManager;->BASE:I
-Landroid/net/nsd/NsdManager;->checkListener(Ljava/lang/Object;)V
-Landroid/net/nsd/NsdManager;->checkProtocol(I)V
-Landroid/net/nsd/NsdManager;->checkServiceInfo(Landroid/net/nsd/NsdServiceInfo;)V
-Landroid/net/nsd/NsdManager;->DBG:Z
-Landroid/net/nsd/NsdManager;->DISABLE:I
-Landroid/net/nsd/NsdManager;->disconnect()V
-Landroid/net/nsd/NsdManager;->DISCOVER_SERVICES:I
-Landroid/net/nsd/NsdManager;->DISCOVER_SERVICES_FAILED:I
-Landroid/net/nsd/NsdManager;->DISCOVER_SERVICES_STARTED:I
-Landroid/net/nsd/NsdManager;->ENABLE:I
-Landroid/net/nsd/NsdManager;->EVENT_NAMES:Landroid/util/SparseArray;
-Landroid/net/nsd/NsdManager;->fatal(Ljava/lang/String;)V
-Landroid/net/nsd/NsdManager;->FIRST_LISTENER_KEY:I
-Landroid/net/nsd/NsdManager;->getListenerKey(Ljava/lang/Object;)I
-Landroid/net/nsd/NsdManager;->getMessenger()Landroid/os/Messenger;
-Landroid/net/nsd/NsdManager;->getNsdServiceInfoType(Landroid/net/nsd/NsdServiceInfo;)Ljava/lang/String;
-Landroid/net/nsd/NsdManager;->init()V
-Landroid/net/nsd/NsdManager;->mAsyncChannel:Lcom/android/internal/util/AsyncChannel;
-Landroid/net/nsd/NsdManager;->mConnected:Ljava/util/concurrent/CountDownLatch;
-Landroid/net/nsd/NsdManager;->mContext:Landroid/content/Context;
-Landroid/net/nsd/NsdManager;->mHandler:Landroid/net/nsd/NsdManager$ServiceHandler;
-Landroid/net/nsd/NsdManager;->mListenerKey:I
-Landroid/net/nsd/NsdManager;->mListenerMap:Landroid/util/SparseArray;
-Landroid/net/nsd/NsdManager;->mMapLock:Ljava/lang/Object;
-Landroid/net/nsd/NsdManager;->mService:Landroid/net/nsd/INsdManager;
-Landroid/net/nsd/NsdManager;->mServiceMap:Landroid/util/SparseArray;
-Landroid/net/nsd/NsdManager;->nameOf(I)Ljava/lang/String;
-Landroid/net/nsd/NsdManager;->NATIVE_DAEMON_EVENT:I
-Landroid/net/nsd/NsdManager;->nextListenerKey()I
-Landroid/net/nsd/NsdManager;->putListener(Ljava/lang/Object;Landroid/net/nsd/NsdServiceInfo;)I
-Landroid/net/nsd/NsdManager;->REGISTER_SERVICE:I
-Landroid/net/nsd/NsdManager;->REGISTER_SERVICE_FAILED:I
-Landroid/net/nsd/NsdManager;->REGISTER_SERVICE_SUCCEEDED:I
-Landroid/net/nsd/NsdManager;->removeListener(I)V
-Landroid/net/nsd/NsdManager;->RESOLVE_SERVICE:I
-Landroid/net/nsd/NsdManager;->RESOLVE_SERVICE_FAILED:I
-Landroid/net/nsd/NsdManager;->RESOLVE_SERVICE_SUCCEEDED:I
-Landroid/net/nsd/NsdManager;->SERVICE_FOUND:I
-Landroid/net/nsd/NsdManager;->SERVICE_LOST:I
-Landroid/net/nsd/NsdManager;->setEnabled(Z)V
-Landroid/net/nsd/NsdManager;->STOP_DISCOVERY:I
-Landroid/net/nsd/NsdManager;->STOP_DISCOVERY_FAILED:I
-Landroid/net/nsd/NsdManager;->STOP_DISCOVERY_SUCCEEDED:I
-Landroid/net/nsd/NsdManager;->TAG:Ljava/lang/String;
-Landroid/net/nsd/NsdManager;->UNREGISTER_SERVICE:I
-Landroid/net/nsd/NsdManager;->UNREGISTER_SERVICE_FAILED:I
-Landroid/net/nsd/NsdManager;->UNREGISTER_SERVICE_SUCCEEDED:I
-Landroid/net/nsd/NsdServiceInfo;-><init>(Ljava/lang/String;Ljava/lang/String;)V
-Landroid/net/nsd/NsdServiceInfo;->getTxtRecord()[B
-Landroid/net/nsd/NsdServiceInfo;->getTxtRecordSize()I
-Landroid/net/nsd/NsdServiceInfo;->mHost:Ljava/net/InetAddress;
-Landroid/net/nsd/NsdServiceInfo;->mPort:I
-Landroid/net/nsd/NsdServiceInfo;->mServiceName:Ljava/lang/String;
-Landroid/net/nsd/NsdServiceInfo;->mServiceType:Ljava/lang/String;
-Landroid/net/nsd/NsdServiceInfo;->mTxtRecord:Landroid/util/ArrayMap;
-Landroid/net/nsd/NsdServiceInfo;->setTxtRecords(Ljava/lang/String;)V
-Landroid/net/nsd/NsdServiceInfo;->TAG:Ljava/lang/String;
Landroid/net/PacProxySelector;-><init>()V
Landroid/net/PacProxySelector;->mDefaultList:Ljava/util/List;
Landroid/net/PacProxySelector;->mProxyService:Lcom/android/net/IProxyService;
diff --git a/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt b/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt
index 79d2521..20d7cc0 100644
--- a/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt
+++ b/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt
@@ -21,7 +21,6 @@
Landroid/Manifest$permission;->READ_FRAME_BUFFER:Ljava/lang/String;
Landroid/media/IVolumeController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IVolumeController;
Landroid/net/INetworkPolicyListener$Stub;-><init>()V
-Landroid/net/nsd/INsdManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/nsd/INsdManager;
Landroid/net/sip/ISipSession$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/sip/ISipSession;
Landroid/nfc/INfcAdapter$Stub;->TRANSACTION_enable:I
Landroid/os/IPowerManager$Stub;->TRANSACTION_acquireWakeLock:I
diff --git a/core/api/current.txt b/core/api/current.txt
index b52a3e4..0162e14 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -61,6 +61,7 @@
field public static final String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
field public static final String BLUETOOTH_SCAN = "android.permission.BLUETOOTH_SCAN";
field public static final String BODY_SENSORS = "android.permission.BODY_SENSORS";
+ field public static final String BODY_SENSORS_BACKGROUND = "android.permission.BODY_SENSORS_BACKGROUND";
field public static final String BROADCAST_PACKAGE_REMOVED = "android.permission.BROADCAST_PACKAGE_REMOVED";
field public static final String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
field public static final String BROADCAST_STICKY = "android.permission.BROADCAST_STICKY";
@@ -16524,6 +16525,7 @@
method @NonNull public static android.graphics.RenderEffect createColorFilterEffect(@NonNull android.graphics.ColorFilter);
method @NonNull public static android.graphics.RenderEffect createOffsetEffect(float, float);
method @NonNull public static android.graphics.RenderEffect createOffsetEffect(float, float, @NonNull android.graphics.RenderEffect);
+ method @NonNull public static android.graphics.RenderEffect createRuntimeShaderEffect(@NonNull android.graphics.RuntimeShader, @NonNull String);
method @NonNull public static android.graphics.RenderEffect createShaderEffect(@NonNull android.graphics.Shader);
}
@@ -20939,11 +20941,12 @@
method @NonNull public java.util.List<android.media.AudioDeviceInfo> getAvailableCommunicationDevices();
method @Nullable public android.media.AudioDeviceInfo getCommunicationDevice();
method public android.media.AudioDeviceInfo[] getDevices(int);
+ method public static int getDirectPlaybackSupport(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes);
method public int getEncodedSurroundMode();
method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException;
method public int getMode();
method public String getParameters(String);
- method public static int getPlaybackOffloadSupport(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes);
+ method @Deprecated public static int getPlaybackOffloadSupport(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes);
method public String getProperty(String);
method public int getRingerMode();
method @Deprecated public int getRouting(int);
@@ -21034,6 +21037,10 @@
field public static final int AUDIOFOCUS_REQUEST_FAILED = 0; // 0x0
field public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; // 0x1
field public static final int AUDIO_SESSION_ID_GENERATE = 0; // 0x0
+ field public static final int DIRECT_PLAYBACK_BITSTREAM_SUPPORTED = 4; // 0x4
+ field public static final int DIRECT_PLAYBACK_NOT_SUPPORTED = 0; // 0x0
+ field public static final int DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED = 3; // 0x3
+ field public static final int DIRECT_PLAYBACK_OFFLOAD_SUPPORTED = 1; // 0x1
field public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2; // 0x2
field public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0; // 0x0
field public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3; // 0x3
@@ -21424,7 +21431,7 @@
method public int getStreamType();
method public boolean getTimestamp(android.media.AudioTimestamp);
method public int getUnderrunCount();
- method public static boolean isDirectPlaybackSupported(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes);
+ method @Deprecated public static boolean isDirectPlaybackSupported(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes);
method public boolean isOffloadedPlayback();
method public void pause() throws java.lang.IllegalStateException;
method public void play() throws java.lang.IllegalStateException;
@@ -21932,6 +21939,7 @@
public class MediaActionSound {
ctor public MediaActionSound();
method public void load(int);
+ method public static boolean mustPlayShutterSound();
method public void play(int);
method public void release();
field public static final int FOCUS_COMPLETE = 1; // 0x1
@@ -27424,65 +27432,6 @@
}
-package android.net.nsd {
-
- public final class NsdManager {
- method public void discoverServices(String, int, android.net.nsd.NsdManager.DiscoveryListener);
- method public void registerService(android.net.nsd.NsdServiceInfo, int, android.net.nsd.NsdManager.RegistrationListener);
- method public void resolveService(android.net.nsd.NsdServiceInfo, android.net.nsd.NsdManager.ResolveListener);
- method public void stopServiceDiscovery(android.net.nsd.NsdManager.DiscoveryListener);
- method public void unregisterService(android.net.nsd.NsdManager.RegistrationListener);
- field public static final String ACTION_NSD_STATE_CHANGED = "android.net.nsd.STATE_CHANGED";
- field public static final String EXTRA_NSD_STATE = "nsd_state";
- field public static final int FAILURE_ALREADY_ACTIVE = 3; // 0x3
- field public static final int FAILURE_INTERNAL_ERROR = 0; // 0x0
- field public static final int FAILURE_MAX_LIMIT = 4; // 0x4
- field public static final int NSD_STATE_DISABLED = 1; // 0x1
- field public static final int NSD_STATE_ENABLED = 2; // 0x2
- field public static final int PROTOCOL_DNS_SD = 1; // 0x1
- }
-
- public static interface NsdManager.DiscoveryListener {
- method public void onDiscoveryStarted(String);
- method public void onDiscoveryStopped(String);
- method public void onServiceFound(android.net.nsd.NsdServiceInfo);
- method public void onServiceLost(android.net.nsd.NsdServiceInfo);
- method public void onStartDiscoveryFailed(String, int);
- method public void onStopDiscoveryFailed(String, int);
- }
-
- public static interface NsdManager.RegistrationListener {
- method public void onRegistrationFailed(android.net.nsd.NsdServiceInfo, int);
- method public void onServiceRegistered(android.net.nsd.NsdServiceInfo);
- method public void onServiceUnregistered(android.net.nsd.NsdServiceInfo);
- method public void onUnregistrationFailed(android.net.nsd.NsdServiceInfo, int);
- }
-
- public static interface NsdManager.ResolveListener {
- method public void onResolveFailed(android.net.nsd.NsdServiceInfo, int);
- method public void onServiceResolved(android.net.nsd.NsdServiceInfo);
- }
-
- public final class NsdServiceInfo implements android.os.Parcelable {
- ctor public NsdServiceInfo();
- method public int describeContents();
- method public java.util.Map<java.lang.String,byte[]> getAttributes();
- method public java.net.InetAddress getHost();
- method public int getPort();
- method public String getServiceName();
- method public String getServiceType();
- method public void removeAttribute(String);
- method public void setAttribute(String, String);
- method public void setHost(java.net.InetAddress);
- method public void setPort(int);
- method public void setServiceName(String);
- method public void setServiceType(String);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.nsd.NsdServiceInfo> CREATOR;
- }
-
-}
-
package android.net.rtp {
@Deprecated public class AudioCodec {
@@ -43504,9 +43453,12 @@
field public static final int DATA_DISCONNECTED = 0; // 0x0
field public static final int DATA_DISCONNECTING = 4; // 0x4
field public static final int DATA_ENABLED_REASON_CARRIER = 2; // 0x2
+ field public static final int DATA_ENABLED_REASON_OVERRIDE = 4; // 0x4
field public static final int DATA_ENABLED_REASON_POLICY = 1; // 0x1
field public static final int DATA_ENABLED_REASON_THERMAL = 3; // 0x3
+ field public static final int DATA_ENABLED_REASON_UNKNOWN = -1; // 0xffffffff
field public static final int DATA_ENABLED_REASON_USER = 0; // 0x0
+ field public static final int DATA_HANDOVER_IN_PROGRESS = 5; // 0x5
field public static final int DATA_SUSPENDED = 3; // 0x3
field public static final int DATA_UNKNOWN = -1; // 0xffffffff
field public static final int DEFAULT_PORT_INDEX = 0; // 0x0
@@ -43756,6 +43708,8 @@
method public String getMmsProxyAddressAsString();
method public int getMmsProxyPort();
method public android.net.Uri getMmsc();
+ method public int getMtuV4();
+ method public int getMtuV6();
method public int getMvnoType();
method public int getNetworkTypeBitmask();
method public String getOperatorNumeric();
@@ -43812,10 +43766,14 @@
method @NonNull public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(@Nullable String);
method @NonNull public android.telephony.data.ApnSetting.Builder setMmsProxyPort(int);
method @NonNull public android.telephony.data.ApnSetting.Builder setMmsc(@Nullable android.net.Uri);
+ method @NonNull public android.telephony.data.ApnSetting.Builder setMtuV4(int);
+ method @NonNull public android.telephony.data.ApnSetting.Builder setMtuV6(int);
method @NonNull public android.telephony.data.ApnSetting.Builder setMvnoType(int);
method @NonNull public android.telephony.data.ApnSetting.Builder setNetworkTypeBitmask(int);
method @NonNull public android.telephony.data.ApnSetting.Builder setOperatorNumeric(@Nullable String);
method @NonNull public android.telephony.data.ApnSetting.Builder setPassword(@Nullable String);
+ method @NonNull public android.telephony.data.ApnSetting.Builder setPersistent(boolean);
+ method @NonNull public android.telephony.data.ApnSetting.Builder setProfileId(int);
method @NonNull public android.telephony.data.ApnSetting.Builder setProtocol(int);
method @Deprecated public android.telephony.data.ApnSetting.Builder setProxyAddress(java.net.InetAddress);
method @NonNull public android.telephony.data.ApnSetting.Builder setProxyAddress(@Nullable String);
@@ -51427,9 +51385,9 @@
method public int getRecordCount();
method public int getWindowChanges();
method public void initFromParcel(android.os.Parcel);
- method public static android.view.accessibility.AccessibilityEvent obtain(int);
- method public static android.view.accessibility.AccessibilityEvent obtain(android.view.accessibility.AccessibilityEvent);
- method public static android.view.accessibility.AccessibilityEvent obtain();
+ method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(int);
+ method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(android.view.accessibility.AccessibilityEvent);
+ method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain();
method public void setAction(int);
method public void setContentChangeTypes(int);
method public void setEventTime(long);
@@ -51617,13 +51575,13 @@
method public boolean isShowingHintText();
method public boolean isTextEntryKey();
method public boolean isVisibleToUser();
- method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
- method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int);
- method public static android.view.accessibility.AccessibilityNodeInfo obtain();
- method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.accessibility.AccessibilityNodeInfo);
+ method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
+ method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int);
+ method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain();
+ method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.accessibility.AccessibilityNodeInfo);
method public boolean performAction(int);
method public boolean performAction(int, android.os.Bundle);
- method public void recycle();
+ method @Deprecated public void recycle();
method public boolean refresh();
method public boolean refreshWithExtraData(String, android.os.Bundle);
method @Deprecated public void removeAction(int);
@@ -51802,8 +51760,8 @@
method public int getRowCount();
method public int getSelectionMode();
method public boolean isHierarchical();
- method public static android.view.accessibility.AccessibilityNodeInfo.CollectionInfo obtain(int, int, boolean);
- method public static android.view.accessibility.AccessibilityNodeInfo.CollectionInfo obtain(int, int, boolean, int);
+ method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.CollectionInfo obtain(int, int, boolean);
+ method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.CollectionInfo obtain(int, int, boolean, int);
field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2
field public static final int SELECTION_MODE_NONE = 0; // 0x0
field public static final int SELECTION_MODE_SINGLE = 1; // 0x1
@@ -51820,9 +51778,9 @@
method @Nullable public String getRowTitle();
method @Deprecated public boolean isHeading();
method public boolean isSelected();
- method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean);
- method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean, boolean);
- method @NonNull public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(@Nullable String, int, int, @Nullable String, int, int, boolean, boolean);
+ method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean);
+ method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean, boolean);
+ method @Deprecated @NonNull public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(@Nullable String, int, int, @Nullable String, int, int, boolean, boolean);
}
public static final class AccessibilityNodeInfo.CollectionItemInfo.Builder {
@@ -51850,7 +51808,7 @@
method public float getMax();
method public float getMin();
method public int getType();
- method public static android.view.accessibility.AccessibilityNodeInfo.RangeInfo obtain(int, float, float, float);
+ method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.RangeInfo obtain(int, float, float, float);
field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
field public static final int RANGE_TYPE_INT = 0; // 0x0
field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
@@ -51904,9 +51862,9 @@
method public boolean isFullScreen();
method public boolean isPassword();
method public boolean isScrollable();
- method public static android.view.accessibility.AccessibilityRecord obtain(android.view.accessibility.AccessibilityRecord);
- method public static android.view.accessibility.AccessibilityRecord obtain();
- method public void recycle();
+ method @Deprecated public static android.view.accessibility.AccessibilityRecord obtain(android.view.accessibility.AccessibilityRecord);
+ method @Deprecated public static android.view.accessibility.AccessibilityRecord obtain();
+ method @Deprecated public void recycle();
method public void setAddedCount(int);
method public void setBeforeText(CharSequence);
method public void setChecked(boolean);
@@ -53004,11 +52962,11 @@
field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.TextAttribute> CREATOR;
}
- public static final class TextAttribute.TextAttributeBuilder {
- ctor public TextAttribute.TextAttributeBuilder();
+ public static final class TextAttribute.Builder {
+ ctor public TextAttribute.Builder();
method @NonNull public android.view.inputmethod.TextAttribute build();
- method @NonNull public android.view.inputmethod.TextAttribute.TextAttributeBuilder setExtras(@NonNull android.os.PersistableBundle);
- method @NonNull public android.view.inputmethod.TextAttribute.TextAttributeBuilder setTextConversionSuggestions(@NonNull java.util.List<java.lang.String>);
+ method @NonNull public android.view.inputmethod.TextAttribute.Builder setExtras(@NonNull android.os.PersistableBundle);
+ method @NonNull public android.view.inputmethod.TextAttribute.Builder setTextConversionSuggestions(@NonNull java.util.List<java.lang.String>);
}
public final class TextSnapshot {
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 850b2e6..04c1e9e 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -24,8 +24,8 @@
}
public class BroadcastOptions {
- method public int getMaxManifestReceiverApiLevel();
- method public void setMaxManifestReceiverApiLevel(int);
+ method @Deprecated public int getMaxManifestReceiverApiLevel();
+ method @Deprecated public void setMaxManifestReceiverApiLevel(int);
}
public abstract class HomeVisibilityListener {
@@ -217,10 +217,6 @@
package android.net {
- public final class ConnectivityFrameworkInitializerTiramisu {
- method public static void registerServiceWrappers();
- }
-
public final class EthernetNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
ctor public EthernetNetworkSpecifier(@NonNull String);
method public int describeContents();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 6e1ab91..75c9be9 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -240,6 +240,7 @@
field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
field public static final String READ_PROJECTION_STATE = "android.permission.READ_PROJECTION_STATE";
field public static final String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES";
+ field public static final String READ_SAFETY_CENTER_STATUS = "android.permission.READ_SAFETY_CENTER_STATUS";
field public static final String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES";
field public static final String READ_SYSTEM_UPDATE_INFO = "android.permission.READ_SYSTEM_UPDATE_INFO";
field public static final String READ_WALLPAPER_INTERNAL = "android.permission.READ_WALLPAPER_INTERNAL";
@@ -344,6 +345,7 @@
public static final class R.attr {
field public static final int allowClearUserDataOnFailedRestore = 16844288; // 0x1010600
+ field public static final int gameSessionService;
field public static final int hotwordDetectionService = 16844326; // 0x1010626
field public static final int isVrOnly = 16844152; // 0x1010578
field public static final int minExtensionVersion = 16844305; // 0x1010611
@@ -722,12 +724,14 @@
}
public class BroadcastOptions {
+ method public void clearRequireCompatChange();
method public boolean isPendingIntentBackgroundActivityLaunchAllowed();
method public static android.app.BroadcastOptions makeBasic();
method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean);
method public void setDontSendToRestrictedApps(boolean);
method public void setPendingIntentBackgroundActivityLaunchAllowed(boolean);
method public void setRequireAllOfPermissions(@Nullable String[]);
+ method public void setRequireCompatChange(long, boolean);
method public void setRequireNoneOfPermissions(@Nullable String[]);
method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppAllowlist(long, int, int, @Nullable String);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(long);
@@ -1398,7 +1402,9 @@
method public static boolean isChangeEnabled(long);
method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, @NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, int);
+ method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void putAllPackageOverrides(@NonNull java.util.Map<java.lang.String,java.util.Map<java.lang.Long,android.app.compat.PackageOverride>>);
method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void putPackageOverrides(@NonNull String, @NonNull java.util.Map<java.lang.Long,android.app.compat.PackageOverride>);
+ method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void removeAllPackageOverrides(@NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.Long>>);
method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void removePackageOverrides(@NonNull String, @NonNull java.util.Set<java.lang.Long>);
}
@@ -6298,9 +6304,11 @@
method @Nullable @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, @NonNull android.media.tv.TvInputInfo, @Nullable String, int, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.TvInputManager.HardwareCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void addBlockedRating(@NonNull android.media.tv.TvContentRating);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean captureFrame(String, android.view.Surface, android.media.tv.TvStreamConfig);
+ method @NonNull public java.util.List<java.lang.String> getAvailableExtensionInterfaceNames(@NonNull String);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(String);
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TUNED_INFO) public java.util.List<android.media.tv.TunedInfo> getCurrentTunedInfos();
method @NonNull @RequiresPermission("android.permission.DVB_DEVICE") public java.util.List<android.media.tv.DvbDeviceInfo> getDvbDeviceList();
+ method @Nullable public android.os.IBinder getExtensionInterface(@NonNull String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public java.util.List<android.media.tv.TvInputHardwareInfo> getHardwareList();
method @RequiresPermission(android.Manifest.permission.READ_CONTENT_RATING_SYSTEMS) public java.util.List<android.media.tv.TvContentRatingSystemInfo> getTvContentRatingSystemList();
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean isSingleSessionActive();
@@ -6331,6 +6339,9 @@
public abstract class TvInputService extends android.app.Service {
method @Nullable public android.os.IBinder createExtension();
+ method @NonNull public java.util.List<java.lang.String> getAvailableExtensionInterfaceNames();
+ method @Nullable public android.os.IBinder getExtensionInterface(@NonNull String);
+ method @Nullable public String getExtensionInterfacePermission(@NonNull String);
method @Nullable public android.media.tv.TvInputInfo onHardwareAdded(android.media.tv.TvInputHardwareInfo);
method @Nullable public String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
method @Nullable public android.media.tv.TvInputInfo onHdmiDeviceAdded(android.hardware.hdmi.HdmiDeviceInfo);
@@ -6458,6 +6469,7 @@
method public int getAvSyncHwId(@NonNull android.media.tv.tuner.filter.Filter);
method public long getAvSyncTime(int);
method @Nullable public java.util.List<android.media.tv.tuner.frontend.FrontendInfo> getAvailableFrontendInfos();
+ method @Nullable public String getCurrentFrontendHardwardInfo();
method @Nullable public android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities();
method @Nullable public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
method @Nullable public android.media.tv.tuner.frontend.FrontendStatus getFrontendStatus(@NonNull int[]);
@@ -6622,6 +6634,10 @@
method public boolean isPassthrough();
method public boolean useSecureMemory();
field public static final int AUDIO_STREAM_TYPE_AAC = 6; // 0x6
+ field public static final int AUDIO_STREAM_TYPE_AAC_ADTS = 16; // 0x10
+ field public static final int AUDIO_STREAM_TYPE_AAC_HE_ADTS = 18; // 0x12
+ field public static final int AUDIO_STREAM_TYPE_AAC_HE_LATM = 19; // 0x13
+ field public static final int AUDIO_STREAM_TYPE_AAC_LATM = 17; // 0x11
field public static final int AUDIO_STREAM_TYPE_AC3 = 7; // 0x7
field public static final int AUDIO_STREAM_TYPE_AC4 = 9; // 0x9
field public static final int AUDIO_STREAM_TYPE_DRA = 15; // 0xf
@@ -6685,6 +6701,8 @@
method @Nullable public String acquireSharedFilterToken();
method public void close();
method public int configure(@NonNull android.media.tv.tuner.filter.FilterConfiguration);
+ method public int delayCallbackUntilBufferFilled(int);
+ method public int delayCallbackUntilTimeMillis(long);
method public int flush();
method public void freeSharedFilterToken(@NonNull String);
method @Deprecated public int getId();
@@ -6783,6 +6801,7 @@
method @IntRange(from=0) public int getMpuSequenceNumber();
method public long getOffset();
method public long getPts();
+ method public int getScIndexMask();
method public int getStreamId();
method public boolean isDtsPresent();
method public boolean isPrivateData();
@@ -7605,6 +7624,7 @@
method public int getBer();
method @NonNull public int[] getBers();
method @NonNull public int[] getCodeRates();
+ method @NonNull public int[] getDvbtCellIds();
method @NonNull public int[] getExtendedModulations();
method @Deprecated public int getFreqOffset();
method public long getFreqOffsetLong();
@@ -7647,6 +7667,7 @@
field public static final int FRONTEND_STATUS_TYPE_BERS = 23; // 0x17
field public static final int FRONTEND_STATUS_TYPE_CODERATES = 24; // 0x18
field public static final int FRONTEND_STATUS_TYPE_DEMOD_LOCK = 0; // 0x0
+ field public static final int FRONTEND_STATUS_TYPE_DVBT_CELL_IDS = 40; // 0x28
field public static final int FRONTEND_STATUS_TYPE_EWBS = 13; // 0xd
field public static final int FRONTEND_STATUS_TYPE_FEC = 8; // 0x8
field public static final int FRONTEND_STATUS_TYPE_FREQ_OFFSET = 18; // 0x12
@@ -7881,6 +7902,7 @@
method public void onAtsc3PlpInfosReported(@NonNull android.media.tv.tuner.frontend.Atsc3PlpInfo[]);
method public default void onDvbcAnnexReported(int);
method public void onDvbsStandardReported(int);
+ method public default void onDvbtCellIdsReported(@NonNull int[]);
method public void onDvbtStandardReported(int);
method public default void onFrequenciesLongReported(@NonNull long[]);
method @Deprecated public void onFrequenciesReported(@NonNull int[]);
@@ -7895,6 +7917,7 @@
method public void onScanStopped();
method public void onSignalTypeReported(int);
method public void onSymbolRatesReported(@NonNull int[]);
+ method public default void onUnLocked();
}
}
@@ -10736,12 +10759,35 @@
package android.service.games {
+ public final class CreateGameSessionRequest implements android.os.Parcelable {
+ ctor public CreateGameSessionRequest(int, @NonNull String);
+ method public int describeContents();
+ method @NonNull public String getGamePackageName();
+ method public int getTaskId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.games.CreateGameSessionRequest> CREATOR;
+ }
+
public class GameService extends android.app.Service {
ctor public GameService();
method @Nullable public android.os.IBinder onBind(@Nullable android.content.Intent);
method public void onConnected();
method public void onDisconnected();
- field public static final String SERVICE_INTERFACE = "android.service.games.GameService";
+ field public static final String ACTION_GAME_SERVICE = "android.service.games.action.GAME_SERVICE";
+ field public static final String SERVICE_META_DATA = "android.game_service";
+ }
+
+ public abstract class GameSession {
+ ctor public GameSession();
+ method public void onCreate();
+ method public void onDestroy();
+ }
+
+ public abstract class GameSessionService extends android.app.Service {
+ ctor public GameSessionService();
+ method @Nullable public android.os.IBinder onBind(@Nullable android.content.Intent);
+ method @NonNull public abstract android.service.games.GameSession onNewSession(@NonNull android.service.games.CreateGameSessionRequest);
+ field public static final String ACTION_GAME_SESSION_SERVICE = "android.service.games.action.GAME_SESSION_SERVICE";
}
}
@@ -13086,21 +13132,23 @@
public final class DataProfile implements android.os.Parcelable {
method public int describeContents();
- method @NonNull public String getApn();
- method public int getAuthType();
- method public int getBearerBitmask();
+ method @Deprecated @NonNull public String getApn();
+ method @Nullable public android.telephony.data.ApnSetting getApnSetting();
+ method @Deprecated public int getAuthType();
+ method @Deprecated public int getBearerBitmask();
method @Deprecated public int getMtu();
- method public int getMtuV4();
- method public int getMtuV6();
- method @Nullable public String getPassword();
- method public int getProfileId();
- method public int getProtocolType();
- method public int getRoamingProtocolType();
- method public int getSupportedApnTypesBitmask();
+ method @Deprecated public int getMtuV4();
+ method @Deprecated public int getMtuV6();
+ method @Deprecated @Nullable public String getPassword();
+ method @Deprecated public int getProfileId();
+ method @Deprecated public int getProtocolType();
+ method @Deprecated public int getRoamingProtocolType();
+ method @Deprecated public int getSupportedApnTypesBitmask();
+ method @Nullable public android.telephony.data.TrafficDescriptor getTrafficDescriptor();
method public int getType();
- method @Nullable public String getUserName();
+ method @Deprecated @Nullable public String getUserName();
method public boolean isEnabled();
- method public boolean isPersistent();
+ method @Deprecated public boolean isPersistent();
method public boolean isPreferred();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataProfile> CREATOR;
@@ -13113,21 +13161,23 @@
ctor public DataProfile.Builder();
method @NonNull public android.telephony.data.DataProfile build();
method @NonNull public android.telephony.data.DataProfile.Builder enable(boolean);
- method @NonNull public android.telephony.data.DataProfile.Builder setApn(@NonNull String);
- method @NonNull public android.telephony.data.DataProfile.Builder setAuthType(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setBearerBitmask(int);
+ method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setApn(@NonNull String);
+ method @NonNull public android.telephony.data.DataProfile.Builder setApnSetting(@NonNull android.telephony.data.ApnSetting);
+ method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setAuthType(int);
+ method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setBearerBitmask(int);
method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setMtu(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setMtuV4(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setMtuV6(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setPassword(@NonNull String);
- method @NonNull public android.telephony.data.DataProfile.Builder setPersistent(boolean);
+ method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setMtuV4(int);
+ method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setMtuV6(int);
+ method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setPassword(@NonNull String);
+ method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setPersistent(boolean);
method @NonNull public android.telephony.data.DataProfile.Builder setPreferred(boolean);
- method @NonNull public android.telephony.data.DataProfile.Builder setProfileId(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setProtocolType(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setRoamingProtocolType(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setSupportedApnTypesBitmask(int);
+ method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setProfileId(int);
+ method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setProtocolType(int);
+ method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setRoamingProtocolType(int);
+ method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setSupportedApnTypesBitmask(int);
+ method @NonNull public android.telephony.data.DataProfile.Builder setTrafficDescriptor(@NonNull android.telephony.data.TrafficDescriptor);
method @NonNull public android.telephony.data.DataProfile.Builder setType(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setUserName(@NonNull String);
+ method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setUserName(@NonNull String);
}
public abstract class DataService extends android.app.Service {
@@ -13259,8 +13309,7 @@
method public void authenticateServer(String, String, byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
method public void cancelSession(String, byte[], @android.telephony.euicc.EuiccCardManager.CancelReason int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
method public void deleteProfile(String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
- method @Deprecated public void disableProfile(String, String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
- method public void disableProfile(@Nullable String, @Nullable String, int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
+ method public void disableProfile(String, String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
method public void listNotifications(String, @android.telephony.euicc.EuiccNotification.Event int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification[]>);
method public void loadBoundProfilePackage(String, byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
method public void prepareDownload(String, @Nullable byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 89dc678..8ae6e4c 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -59,6 +59,7 @@
public static final class R.bool {
field public static final int config_assistantOnTopOfDream = 17891333; // 0x1110005
field public static final int config_perDisplayFocusEnabled = 17891332; // 0x1110004
+ field public static final int config_preventImeStartupUnlessTextEditor;
field public static final int config_remoteInsetsControllerControlsSystemBars = 17891334; // 0x1110006
}
@@ -248,12 +249,15 @@
public class BroadcastOptions {
ctor public BroadcastOptions(@NonNull android.os.Bundle);
- method public int getMaxManifestReceiverApiLevel();
+ method @Deprecated public int getMaxManifestReceiverApiLevel();
method public long getTemporaryAppAllowlistDuration();
method @Nullable public String getTemporaryAppAllowlistReason();
method public int getTemporaryAppAllowlistReasonCode();
method public int getTemporaryAppAllowlistType();
- method public void setMaxManifestReceiverApiLevel(int);
+ method @Deprecated public void setMaxManifestReceiverApiLevel(int);
+ method public boolean testRequireCompatChange(int);
+ field public static final long CHANGE_ALWAYS_DISABLED = 210856463L; // 0xc916a0fL
+ field public static final long CHANGE_ALWAYS_ENABLED = 209888056L; // 0xc82a338L
}
public class DownloadManager {
@@ -699,6 +703,7 @@
field public static final String FONT_SERVICE = "font";
field public static final String POWER_EXEMPTION_SERVICE = "power_exemption";
field @Deprecated public static final String POWER_WHITELIST_MANAGER = "power_whitelist";
+ field @Deprecated public static final int RECEIVER_EXPORTED_UNAUDITED = 2; // 0x2
field public static final String TEST_NETWORK_SERVICE = "test_network";
}
@@ -1428,6 +1433,9 @@
field public static final int DEVICE_ROLE_DISABLED = 2; // 0x2
field public static final int DEVICE_ROLE_NONE = 0; // 0x0
field public static final int DEVICE_ROLE_PREFERRED = 1; // 0x1
+ field public static final int DIRECT_BITSTREAM_SUPPORTED = 4; // 0x4
+ field public static final int DIRECT_OFFLOAD_GAPLESS_SUPPORTED = 3; // 0x3
+ field public static final int DIRECT_OFFLOAD_SUPPORTED = 1; // 0x1
field public static final int OFFLOAD_GAPLESS_SUPPORTED = 2; // 0x2
field public static final int OFFLOAD_SUPPORTED = 1; // 0x1
field public static final int STREAM_DEFAULT = -1; // 0xffffffff
@@ -2079,6 +2087,7 @@
field public static final String NAMESPACE_CONSTRAIN_DISPLAY_APIS = "constrain_display_apis";
field public static final String NAMESPACE_DEVICE_IDLE = "device_idle";
field public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler";
+ field public static final String NAMESPACE_SELECTION_TOOLBAR = "selection_toolbar";
}
public final class Settings {
@@ -2829,7 +2838,6 @@
method public void addChild(@NonNull android.os.IBinder);
method public long getSourceNodeId();
method public void setLeashedParent(@Nullable android.os.IBinder, int);
- method public static void setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger);
method public void writeToParcelNoRecycle(android.os.Parcel, int);
}
diff --git a/core/java/android/accounts/ChooseAccountActivity.java b/core/java/android/accounts/ChooseAccountActivity.java
index bc7f4d6..6c8744f 100644
--- a/core/java/android/accounts/ChooseAccountActivity.java
+++ b/core/java/android/accounts/ChooseAccountActivity.java
@@ -148,7 +148,7 @@
am.setAccountVisibility(account, mCallingPackage,
AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
}
- Log.d(TAG, "selected account " + account);
+ Log.d(TAG, "selected account " + account.toSafeString());
Bundle bundle = new Bundle();
bundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 2be88ab..2e9f73c 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -190,10 +190,6 @@
mAccounts = getAcceptableAccountChoices(AccountManager.get(this));
}
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "selected account name is " + mSelectedAccountName);
- }
-
mPossiblyVisibleAccounts = new ArrayList<>(mAccounts.size());
for (Map.Entry<Account, Integer> entry : mAccounts.entrySet()) {
if (AccountManager.VISIBILITY_NOT_VISIBLE != entry.getValue()) {
@@ -302,7 +298,7 @@
if (data != null && data.getExtras() != null) data.getExtras().keySet();
Bundle extras = data != null ? data.getExtras() : null;
Log.v(TAG, "ChooseTypeAndAccountActivity.onActivityResult(reqCode=" + requestCode
- + ", resCode=" + resultCode + ", extras=" + extras + ")");
+ + ", resCode=" + resultCode + ")");
}
// we got our result, so clear the fact that we had a pending request
@@ -424,8 +420,8 @@
}
private void onAccountSelected(Account account) {
- Log.d(TAG, "selected account " + account);
- setResultAndFinish(account.name, account.type);
+ Log.d(TAG, "selected account " + account.toSafeString());
+ setResultAndFinish(account.name, account.type);
}
private void setResultAndFinish(final String accountName, final String accountType) {
@@ -451,9 +447,8 @@
setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "ChooseTypeAndAccountActivity.setResultAndFinish: selected account "
- + accountName + ", " + accountType);
+ + account.toSafeString());
}
-
finish();
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 11a2ede..cf2b7ac 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6191,18 +6191,20 @@
@Nullable
public Uri getReferrer() {
Intent intent = getIntent();
- try {
- Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
- if (referrer != null) {
- return referrer;
+ if (intent != null) {
+ try {
+ Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
+ if (referrer != null) {
+ return referrer;
+ }
+ String referrerName = intent.getStringExtra(Intent.EXTRA_REFERRER_NAME);
+ if (referrerName != null) {
+ return Uri.parse(referrerName);
+ }
+ } catch (BadParcelableException e) {
+ Log.w(TAG, "Cannot read referrer from intent;"
+ + " intent extras contain unknown custom Parcelable objects");
}
- String referrerName = intent.getStringExtra(Intent.EXTRA_REFERRER_NAME);
- if (referrerName != null) {
- return Uri.parse(referrerName);
- }
- } catch (BadParcelableException e) {
- Log.w(TAG, "Cannot read referrer from intent;"
- + " intent extras contain unknown custom Parcelable objects");
}
if (mReferrer != null) {
return new Uri.Builder().scheme("android-app").authority(mReferrer).build();
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index d0096fd..f7d5e52 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -380,6 +380,8 @@
public static final int ANIM_OPEN_CROSS_PROFILE_APPS = 12;
/** @hide */
public static final int ANIM_REMOTE_ANIMATION = 13;
+ /** @hide */
+ public static final int ANIM_FROM_STYLE = 14;
private String mPackageName;
private Rect mLaunchBounds;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a8894dc..1778ea4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -243,6 +243,7 @@
import java.util.Objects;
import java.util.TimeZone;
import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
/**
@@ -344,11 +345,9 @@
*/
@UnsupportedAppUsage
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
- /**
- * Maps from activity token to local record of the activities that are preparing to be launched.
- */
- final Map<IBinder, ActivityClientRecord> mLaunchingActivities =
- Collections.synchronizedMap(new ArrayMap<IBinder, ActivityClientRecord>());
+ /** Maps from activity token to the pending override configuration. */
+ @GuardedBy("mPendingOverrideConfigs")
+ private final ArrayMap<IBinder, Configuration> mPendingOverrideConfigs = new ArrayMap<>();
/** The activities to be truly destroyed (not include relaunch). */
final Map<IBinder, ClientTransactionItem> mActivitiesToBeDestroyed =
Collections.synchronizedMap(new ArrayMap<IBinder, ClientTransactionItem>());
@@ -358,6 +357,7 @@
// Number of activities that are currently visible on-screen.
@UnsupportedAppUsage
int mNumVisibleActivities = 0;
+ private final AtomicInteger mNumLaunchingActivities = new AtomicInteger();
@GuardedBy("mAppThread")
private int mLastProcessState = PROCESS_STATE_UNKNOWN;
@GuardedBy("mAppThread")
@@ -555,10 +555,6 @@
boolean hideForNow;
Configuration createdConfig;
Configuration overrideConfig;
- // Used to save the last reported configuration from server side so that activity
- // configuration transactions can always use the latest configuration.
- @GuardedBy("this")
- private Configuration mPendingOverrideConfig;
// Used for consolidating configs before sending on to Activity.
private Configuration tmpConfig = new Configuration();
// Callback used for updating activity override config and camera compat control state.
@@ -3361,21 +3357,6 @@
}
@Override
- public void addLaunchingActivity(IBinder token, ActivityClientRecord activity) {
- mLaunchingActivities.put(token, activity);
- }
-
- @Override
- public ActivityClientRecord getLaunchingActivity(IBinder token) {
- return mLaunchingActivities.get(token);
- }
-
- @Override
- public void removeLaunchingActivity(IBinder token) {
- mLaunchingActivities.remove(token);
- }
-
- @Override
public ActivityClientRecord getActivityClient(IBinder token) {
return mActivities.get(token);
}
@@ -3419,7 +3400,7 @@
// Defer the top state for VM to avoid aggressive JIT compilation affecting activity
// launch time.
if (processState == ActivityManager.PROCESS_STATE_TOP
- && !mLaunchingActivities.isEmpty()) {
+ && mNumLaunchingActivities.get() > 0) {
mPendingProcessState = processState;
mH.postDelayed(this::applyPendingProcessState, PENDING_TOP_PROCESS_STATE_TIMEOUT);
} else {
@@ -3435,7 +3416,7 @@
// Handle the pending configuration if the process state is changed from cached to
// non-cached. Except the case where there is a launching activity because the
// LaunchActivityItem will handle it.
- if (wasCached && !isCachedProcessState() && mLaunchingActivities.isEmpty()) {
+ if (wasCached && !isCachedProcessState() && mNumLaunchingActivities.get() == 0) {
final Configuration pendingConfig =
mConfigurationController.getPendingConfiguration(false /* clearPending */);
if (pendingConfig == null) {
@@ -3473,6 +3454,11 @@
}
}
+ @Override
+ public void countLaunchingActivities(int num) {
+ mNumLaunchingActivities.getAndAdd(num);
+ }
+
@UnsupportedAppUsage
public final void sendActivityResult(
IBinder token, String id, int requestCode,
@@ -6096,31 +6082,31 @@
}
/**
- * Sets the supplied {@code overrideConfig} as pending for the {@code activityToken}. Calling
+ * Sets the supplied {@code overrideConfig} as pending for the {@code token}. Calling
* this method prevents any calls to
* {@link #handleActivityConfigurationChanged(ActivityClientRecord, Configuration, int)} from
* processing any configurations older than {@code overrideConfig}.
*/
@Override
- public void updatePendingActivityConfiguration(ActivityClientRecord r,
- Configuration overrideConfig) {
- synchronized (r) {
- if (r.mPendingOverrideConfig != null
- && !r.mPendingOverrideConfig.isOtherSeqNewer(overrideConfig)) {
+ public void updatePendingActivityConfiguration(IBinder token, Configuration overrideConfig) {
+ synchronized (mPendingOverrideConfigs) {
+ final Configuration pendingOverrideConfig = mPendingOverrideConfigs.get(token);
+ if (pendingOverrideConfig != null
+ && !pendingOverrideConfig.isOtherSeqNewer(overrideConfig)) {
if (DEBUG_CONFIGURATION) {
- Slog.v(TAG, "Activity has newer configuration pending so drop this"
- + " transaction. overrideConfig=" + overrideConfig
- + " r.mPendingOverrideConfig=" + r.mPendingOverrideConfig);
+ Slog.v(TAG, "Activity has newer configuration pending so this transaction will"
+ + " be dropped. overrideConfig=" + overrideConfig
+ + " pendingOverrideConfig=" + pendingOverrideConfig);
}
return;
}
- r.mPendingOverrideConfig = overrideConfig;
+ mPendingOverrideConfigs.put(token, overrideConfig);
}
}
/**
* Handle new activity configuration and/or move to a different display. This method is a noop
- * if {@link #updatePendingActivityConfiguration(ActivityClientRecord, Configuration)} has been
+ * if {@link #updatePendingActivityConfiguration(IBinder, Configuration)} has been
* called with a newer config than {@code overrideConfig}.
*
* @param r Target activity record.
@@ -6131,16 +6117,17 @@
@Override
public void handleActivityConfigurationChanged(ActivityClientRecord r,
@NonNull Configuration overrideConfig, int displayId) {
- synchronized (r) {
- if (overrideConfig.isOtherSeqNewer(r.mPendingOverrideConfig)) {
+ synchronized (mPendingOverrideConfigs) {
+ final Configuration pendingOverrideConfig = mPendingOverrideConfigs.get(r.token);
+ if (overrideConfig.isOtherSeqNewer(pendingOverrideConfig)) {
if (DEBUG_CONFIGURATION) {
Slog.v(TAG, "Activity has newer configuration pending so drop this"
+ " transaction. overrideConfig=" + overrideConfig
- + " r.mPendingOverrideConfig=" + r.mPendingOverrideConfig);
+ + " pendingOverrideConfig=" + pendingOverrideConfig);
}
return;
}
- r.mPendingOverrideConfig = null;
+ mPendingOverrideConfigs.remove(r.token);
}
if (displayId == INVALID_DISPLAY) {
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 3108d91..0bb6ffa 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -21,6 +21,11 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
+import android.compat.annotation.EnabledSince;
+import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerExemptionManager;
@@ -45,6 +50,35 @@
private boolean mAllowBackgroundActivityStarts;
private String[] mRequireAllOfPermissions;
private String[] mRequireNoneOfPermissions;
+ private long mRequireCompatChangeId = CHANGE_INVALID;
+ private boolean mRequireCompatChangeEnabled = true;
+
+ /**
+ * Change ID which is invalid.
+ *
+ * @hide
+ */
+ public static final long CHANGE_INVALID = Long.MIN_VALUE;
+
+ /**
+ * Change ID which is always enabled, for testing purposes.
+ *
+ * @hide
+ */
+ @TestApi
+ @ChangeId
+ @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.BASE)
+ public static final long CHANGE_ALWAYS_ENABLED = 209888056L;
+
+ /**
+ * Change ID which is always disabled, for testing purposes.
+ *
+ * @hide
+ */
+ @TestApi
+ @ChangeId
+ @Disabled
+ public static final long CHANGE_ALWAYS_DISABLED = 210856463L;
/**
* How long to temporarily put an app on the power allowlist when executing this broadcast
@@ -101,6 +135,18 @@
"android:broadcast.requireNoneOfPermissions";
/**
+ * Corresponds to {@link #setRequireCompatChange(long, boolean)}
+ */
+ private static final String KEY_REQUIRE_COMPAT_CHANGE_ID =
+ "android:broadcast.requireCompatChangeId";
+
+ /**
+ * Corresponds to {@link #setRequireCompatChange(long, boolean)}
+ */
+ private static final String KEY_REQUIRE_COMPAT_CHANGE_ENABLED =
+ "android:broadcast.requireCompatChangeEnabled";
+
+ /**
* @hide
* @deprecated Use {@link android.os.PowerExemptionManager#
* TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED} instead.
@@ -150,6 +196,8 @@
false);
mRequireAllOfPermissions = opts.getStringArray(KEY_REQUIRE_ALL_OF_PERMISSIONS);
mRequireNoneOfPermissions = opts.getStringArray(KEY_REQUIRE_NONE_OF_PERMISSIONS);
+ mRequireCompatChangeId = opts.getLong(KEY_REQUIRE_COMPAT_CHANGE_ID, CHANGE_INVALID);
+ mRequireCompatChangeEnabled = opts.getBoolean(KEY_REQUIRE_COMPAT_CHANGE_ENABLED, true);
}
/**
@@ -270,16 +318,32 @@
* Set the minimum target API level of receivers of the broadcast. If an application
* is targeting an API level less than this, the broadcast will not be delivered to
* them. This only applies to receivers declared in the app's AndroidManifest.xml.
+ *
+ * @deprecated to give developers the most flexibility during beta releases,
+ * we strongly encourage using {@link ChangeId} instead of
+ * target SDK checks; callers should use
+ * {@link #setRequireCompatChange(long, boolean)} instead,
+ * possibly combined with
+ * {@link Intent#FLAG_RECEIVER_REGISTERED_ONLY}.
* @hide
*/
+ @Deprecated
public void setMinManifestReceiverApiLevel(int apiLevel) {
mMinManifestReceiverApiLevel = apiLevel;
}
/**
* Return {@link #setMinManifestReceiverApiLevel}.
+ *
+ * @deprecated to give developers the most flexibility during beta releases,
+ * we strongly encourage using {@link ChangeId} instead of
+ * target SDK checks; callers should use
+ * {@link #setRequireCompatChange(long, boolean)} instead,
+ * possibly combined with
+ * {@link Intent#FLAG_RECEIVER_REGISTERED_ONLY}.
* @hide
*/
+ @Deprecated
public int getMinManifestReceiverApiLevel() {
return mMinManifestReceiverApiLevel;
}
@@ -288,20 +352,36 @@
* Set the maximum target API level of receivers of the broadcast. If an application
* is targeting an API level greater than this, the broadcast will not be delivered to
* them. This only applies to receivers declared in the app's AndroidManifest.xml.
+ *
+ * @deprecated to give developers the most flexibility during beta releases,
+ * we strongly encourage using {@link ChangeId} instead of
+ * target SDK checks; callers should use
+ * {@link #setRequireCompatChange(long, boolean)} instead,
+ * possibly combined with
+ * {@link Intent#FLAG_RECEIVER_REGISTERED_ONLY}.
* @hide
*/
@TestApi
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @Deprecated
public void setMaxManifestReceiverApiLevel(int apiLevel) {
mMaxManifestReceiverApiLevel = apiLevel;
}
/**
* Return {@link #setMaxManifestReceiverApiLevel}.
+ *
+ * @deprecated to give developers the most flexibility during beta releases,
+ * we strongly encourage using {@link ChangeId} instead of
+ * target SDK checks; callers should use
+ * {@link #setRequireCompatChange(long, boolean)} instead,
+ * possibly combined with
+ * {@link Intent#FLAG_RECEIVER_REGISTERED_ONLY}.
* @hide
*/
@TestApi
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @Deprecated
public int getMaxManifestReceiverApiLevel() {
return mMaxManifestReceiverApiLevel;
}
@@ -379,6 +459,58 @@
}
/**
+ * When set, this broadcast will only be delivered to apps which have the
+ * given {@link ChangeId} in the given state.
+ * <p>
+ * Each {@link BroadcastOptions} instance supports only a single
+ * {@link ChangeId} requirement, so any subsequent calls will override any
+ * previously defined requirement.
+ * <p>
+ * This requirement applies to both manifest registered and runtime
+ * registered receivers.
+ *
+ * @param changeId the {@link ChangeId} to inspect
+ * @param enabled the required enabled state of the inspected
+ * {@link ChangeId} for this broadcast to be delivered
+ * @see CompatChanges#isChangeEnabled
+ * @see #clearRequireCompatChange()
+ */
+ public void setRequireCompatChange(long changeId, boolean enabled) {
+ mRequireCompatChangeId = changeId;
+ mRequireCompatChangeEnabled = enabled;
+ }
+
+ /**
+ * Clear any previously defined requirement for this broadcast requested via
+ * {@link #setRequireCompatChange(long, boolean)}.
+ */
+ public void clearRequireCompatChange() {
+ mRequireCompatChangeId = CHANGE_INVALID;
+ mRequireCompatChangeEnabled = true;
+ }
+
+ /** {@hide} */
+ public long getRequireCompatChangeId() {
+ return mRequireCompatChangeId;
+ }
+
+ /**
+ * Test if the given app meets the {@link ChangeId} state required by this
+ * broadcast, if any.
+ *
+ * @hide
+ */
+ @TestApi
+ public boolean testRequireCompatChange(int uid) {
+ if (mRequireCompatChangeId != CHANGE_INVALID) {
+ return CompatChanges.isChangeEnabled(mRequireCompatChangeId,
+ uid) == mRequireCompatChangeEnabled;
+ } else {
+ return true;
+ }
+ }
+
+ /**
* Returns the created options as a Bundle, which can be passed to
* {@link android.content.Context#sendBroadcast(android.content.Intent)
* Context.sendBroadcast(Intent)} and related methods.
@@ -413,6 +545,10 @@
if (mRequireNoneOfPermissions != null) {
b.putStringArray(KEY_REQUIRE_NONE_OF_PERMISSIONS, mRequireNoneOfPermissions);
}
+ if (mRequireCompatChangeId != CHANGE_INVALID) {
+ b.putLong(KEY_REQUIRE_COMPAT_CHANGE_ID, mRequireCompatChangeId);
+ b.putBoolean(KEY_REQUIRE_COMPAT_CHANGE_ENABLED, mRequireCompatChangeEnabled);
+ }
return b.isEmpty() ? null : b;
}
}
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index c743f65..d365269 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -83,6 +83,9 @@
/** Set current process state. */
public abstract void updateProcessState(int processState, boolean fromIpc);
+ /** Count how many activities are launching. */
+ public abstract void countLaunchingActivities(int num);
+
// Execute phase related logic and handlers. Methods here execute actual lifecycle transactions
// and deliver callbacks.
@@ -139,7 +142,7 @@
public abstract void performRestartActivity(@NonNull ActivityClientRecord r, boolean start);
/** Set pending activity configuration in case it will be updated by other transaction item. */
- public abstract void updatePendingActivityConfiguration(@NonNull ActivityClientRecord r,
+ public abstract void updatePendingActivityConfiguration(@NonNull IBinder token,
Configuration overrideConfig);
/** Deliver activity (override) configuration change. */
@@ -189,26 +192,6 @@
FixedRotationAdjustments fixedRotationAdjustments);
/**
- * Add {@link ActivityClientRecord} that is preparing to be launched.
- * @param token Activity token.
- * @param activity An initialized instance of {@link ActivityClientRecord} to use during launch.
- */
- public abstract void addLaunchingActivity(IBinder token, ActivityClientRecord activity);
-
- /**
- * Get {@link ActivityClientRecord} that is preparing to be launched.
- * @param token Activity token.
- * @return An initialized instance of {@link ActivityClientRecord} to use during launch.
- */
- public abstract ActivityClientRecord getLaunchingActivity(IBinder token);
-
- /**
- * Remove {@link ActivityClientRecord} from the launching activity list.
- * @param token Activity token.
- */
- public abstract void removeLaunchingActivity(IBinder token);
-
- /**
* Get {@link android.app.ActivityThread.ActivityClientRecord} instance that corresponds to the
* provided token.
*/
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 717e289..4aa2d2e 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -2199,8 +2199,11 @@
+ conversationSendersToString(priorityConversationSenders)
+ ",suppressedVisualEffects="
+ suppressedEffectsToString(suppressedVisualEffects)
- + ",areChannelsBypassingDnd=" + (((state & STATE_CHANNELS_BYPASSING_DND) != 0)
- ? "true" : "false")
+ + ",areChannelsBypassingDnd=" + (state == STATE_UNSET
+ ? "unset"
+ : ((state & STATE_CHANNELS_BYPASSING_DND) != 0)
+ ? "true"
+ : "false")
+ "]";
}
diff --git a/core/java/android/app/compat/CompatChanges.java b/core/java/android/app/compat/CompatChanges.java
index 0d85fb9..d7b2ab4 100644
--- a/core/java/android/app/compat/CompatChanges.java
+++ b/core/java/android/app/compat/CompatChanges.java
@@ -22,8 +22,11 @@
import android.compat.Compatibility;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.util.ArrayMap;
import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesByPackageConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveByPackageConfig;
import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
import java.util.Map;
@@ -98,6 +101,31 @@
}
/**
+ * Equivalent to calling {@link #putPackageOverrides(String, Map)} on each entry in {@code
+ * packageNameToOverrides}, but the state of the compat config will be updated only once
+ * instead of for each package.
+ *
+ * @param packageNameToOverrides A map from package name to a map from change ID to the
+ * override applied for that package name and change ID.
+ */
+ @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
+ public static void putAllPackageOverrides(
+ @NonNull Map<String, Map<Long, PackageOverride>> packageNameToOverrides) {
+ ArrayMap<String, CompatibilityOverrideConfig> packageNameToConfig = new ArrayMap<>();
+ for (String packageName : packageNameToOverrides.keySet()) {
+ packageNameToConfig.put(packageName,
+ new CompatibilityOverrideConfig(packageNameToOverrides.get(packageName)));
+ }
+ CompatibilityOverridesByPackageConfig config = new CompatibilityOverridesByPackageConfig(
+ packageNameToConfig);
+ try {
+ QUERY_CACHE.getPlatformCompatService().putAllOverridesOnReleaseBuilds(config);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Associates app compat overrides with the given package and their respective change IDs.
* This will check whether the caller is allowed to perform this operation on the given apk and
* build. Only the installer package is allowed to set overrides on a non-debuggable final
@@ -123,6 +151,33 @@
}
/**
+ * Equivalent to calling {@link #removePackageOverrides(String, Set)} on each entry in {@code
+ * packageNameToOverridesToRemove}, but the state of the compat config will be updated only once
+ * instead of for each package.
+ *
+ * @param packageNameToOverridesToRemove A map from package name to a set of change IDs for
+ * which to remove overrides for that package name.
+ */
+ @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
+ public static void removeAllPackageOverrides(
+ @NonNull Map<String, Set<Long>> packageNameToOverridesToRemove) {
+ ArrayMap<String, CompatibilityOverridesToRemoveConfig> packageNameToConfig =
+ new ArrayMap<>();
+ for (String packageName : packageNameToOverridesToRemove.keySet()) {
+ packageNameToConfig.put(packageName,
+ new CompatibilityOverridesToRemoveConfig(
+ packageNameToOverridesToRemove.get(packageName)));
+ }
+ CompatibilityOverridesToRemoveByPackageConfig config =
+ new CompatibilityOverridesToRemoveByPackageConfig(packageNameToConfig);
+ try {
+ QUERY_CACHE.getPlatformCompatService().removeAllOverridesOnReleaseBuilds(config);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Removes app compat overrides for the given package. This will check whether the caller is
* allowed to perform this operation on the given apk and build. Only the installer package is
* allowed to clear overrides on a non-debuggable final build and a non-test apk.
diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
index 032b57e..5a3ad31 100644
--- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
+++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
@@ -40,11 +40,9 @@
@Override
public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
- final ActivityClientRecord r = getActivityClientRecord(client, token,
- true /* includeLaunching */);
// Notify the client of an upcoming change in the token configuration. This ensures that
// batches of config change items only process the newest configuration.
- client.updatePendingActivityConfiguration(r, mConfiguration);
+ client.updatePendingActivityConfiguration(token, mConfiguration);
}
@Override
diff --git a/core/java/android/app/servertransaction/ActivityTransactionItem.java b/core/java/android/app/servertransaction/ActivityTransactionItem.java
index 186f25d..6a6d76d 100644
--- a/core/java/android/app/servertransaction/ActivityTransactionItem.java
+++ b/core/java/android/app/servertransaction/ActivityTransactionItem.java
@@ -53,43 +53,23 @@
public abstract void execute(@NonNull ClientTransactionHandler client,
@NonNull ActivityClientRecord r, PendingTransactionActions pendingActions);
- @NonNull ActivityClientRecord getActivityClientRecord(
- @NonNull ClientTransactionHandler client, IBinder token) {
- return getActivityClientRecord(client, token, false /* includeLaunching */);
- }
-
/**
* Gets the {@link ActivityClientRecord} instance that corresponds to the provided token.
* @param client Target client handler.
* @param token Target activity token.
- * @param includeLaunching Indicate to find the {@link ActivityClientRecord} in launching
- * activity list.
- * <p>Note that there is no {@link android.app.Activity} instance in
- * {@link ActivityClientRecord} from the launching activity list.
* @return The {@link ActivityClientRecord} instance that corresponds to the provided token.
*/
@NonNull ActivityClientRecord getActivityClientRecord(
- @NonNull ClientTransactionHandler client, IBinder token, boolean includeLaunching) {
- ActivityClientRecord r = null;
- // Check launching Activity first to prevent race condition that activity instance has not
- // yet set to ActivityClientRecord.
- if (includeLaunching) {
- r = client.getLaunchingActivity(token);
- }
- // Then if we don't want to find launching Activity or the ActivityClientRecord doesn't
- // exist in launching Activity list. The ActivityClientRecord should have been initialized
- // and put in the Activity list.
- if (r == null) {
- r = client.getActivityClient(token);
- if (r != null && client.getActivity(token) == null) {
- throw new IllegalArgumentException("Activity must not be null to execute "
- + "transaction item");
- }
- }
+ @NonNull ClientTransactionHandler client, IBinder token) {
+ final ActivityClientRecord r = client.getActivityClient(token);
if (r == null) {
throw new IllegalArgumentException("Activity client record must not be null to execute "
+ "transaction item");
}
+ if (client.getActivity(token) == null) {
+ throw new IllegalArgumentException("Activity must not be null to execute "
+ + "transaction item");
+ }
return r;
}
}
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 4de608b..0a2503c 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -82,12 +82,7 @@
@Override
public void preExecute(ClientTransactionHandler client, IBinder token) {
- ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
- mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
- mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
- client, mAssistToken, mFixedRotationAdjustments, mShareableActivityToken,
- mLaunchedFromBubble);
- client.addLaunchingActivity(token, r);
+ client.countLaunchingActivities(1);
client.updateProcessState(mProcState, false);
client.updatePendingConfiguration(mCurConfig);
if (mActivityClientController != null) {
@@ -99,7 +94,11 @@
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
- ActivityClientRecord r = client.getLaunchingActivity(token);
+ ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
+ mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
+ mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
+ client, mAssistToken, mFixedRotationAdjustments, mShareableActivityToken,
+ mLaunchedFromBubble);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -107,7 +106,7 @@
@Override
public void postExecute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
- client.removeLaunchingActivity(token);
+ client.countLaunchingActivities(-1);
}
diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java
index 4b8a347..2893ff2 100644
--- a/core/java/android/app/servertransaction/MoveToDisplayItem.java
+++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java
@@ -40,11 +40,9 @@
@Override
public void preExecute(ClientTransactionHandler client, IBinder token) {
- final ActivityClientRecord r = getActivityClientRecord(client, token,
- true /* includeLaunching */);
// Notify the client of an upcoming change in the token configuration. This ensures that
// batches of config change items only process the newest configuration.
- client.updatePendingActivityConfiguration(r, mConfiguration);
+ client.updatePendingActivityConfiguration(token, mConfiguration);
}
@Override
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index bb537dd..2a8ff51 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -189,7 +189,7 @@
@NonNull
@SystemApi
public static final ParcelUuid CAP =
- ParcelUuid.fromString("00008FE0-0000-1000-8000-00805F9B34FB");
+ ParcelUuid.fromString("00001853-0000-1000-8000-00805F9B34FB");
/** @hide */
@NonNull
@SystemApi
diff --git a/core/java/android/companion/AssociationInfo.java b/core/java/android/companion/AssociationInfo.java
index 3f02aa2..78d5137 100644
--- a/core/java/android/companion/AssociationInfo.java
+++ b/core/java/android/companion/AssociationInfo.java
@@ -197,6 +197,20 @@
return macAddress.equals(mDeviceMacAddress);
}
+ /** @hide */
+ public @NonNull String toShortString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("id=").append(mId);
+ if (mDeviceMacAddress != null) {
+ sb.append(", addr=").append(getDeviceMacAddressAsString());
+ }
+ if (mSelfManaged) {
+ sb.append(", self-managed");
+ }
+ sb.append(", pkg=u").append(mUserId).append('/').append(mPackageName);
+ return sb.toString();
+ }
+
@Override
public String toString() {
return "Association{"
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6d13712..120a0a6 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -534,7 +534,8 @@
/** @hide */
@IntDef(flag = true, prefix = { "RECEIVER_VISIBLE" }, value = {
- RECEIVER_VISIBLE_TO_INSTANT_APPS, RECEIVER_EXPORTED, RECEIVER_NOT_EXPORTED
+ RECEIVER_VISIBLE_TO_INSTANT_APPS, RECEIVER_EXPORTED, RECEIVER_NOT_EXPORTED,
+ RECEIVER_EXPORTED_UNAUDITED
})
@Retention(RetentionPolicy.SOURCE)
public @interface RegisterReceiverFlags {}
@@ -551,6 +552,14 @@
public static final int RECEIVER_EXPORTED = 0x2;
/**
+ * @deprecated Use {@link #RECEIVER_NOT_EXPORTED} or {@link #RECEIVER_EXPORTED} instead.
+ * @hide
+ */
+ @Deprecated
+ @TestApi
+ public static final int RECEIVER_EXPORTED_UNAUDITED = RECEIVER_EXPORTED;
+
+ /**
* Flag for {@link #registerReceiver}: The receiver cannot receive broadcasts from other Apps.
* Has the same behavior as marking a statically registered receiver with "exported=false"
*/
@@ -3606,9 +3615,8 @@
* {@link #BIND_ADJUST_WITH_ACTIVITY}.
* @return {@code true} if the system is in the process of bringing up a
* service that your client has permission to bind to; {@code false}
- * if the system couldn't find the service. If this value is {@code true}, you
- * should later call {@link #unbindService} to release the
- * connection.
+ * if the system couldn't find the service. You should call {@link #unbindService}
+ * to release the connection even if this method returned {@code false}.
*
* @throws SecurityException if the client does not have the required permission to bind.
*/
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 1e6029f..2ff29cb 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -5598,7 +5598,9 @@
*
* <p>Targets provided in this way will be presented inline with all other targets provided
* by services from other apps. They will be prioritized before other service targets, but
- * after those targets provided by sources that the user has manually pinned to the front.</p>
+ * after those targets provided by sources that the user has manually pinned to the front.
+ * You can provide up to two targets on this extra (the limit of two targets
+ * starts in Android 10).</p>
*
* @see #ACTION_CHOOSER
*/
@@ -5709,9 +5711,11 @@
/**
* A Parcelable[] of {@link Intent} or
* {@link android.content.pm.LabeledIntent} objects as set with
- * {@link #putExtra(String, Parcelable[])} of additional activities to place
- * a the front of the list of choices, when shown to the user with a
- * {@link #ACTION_CHOOSER}.
+ * {@link #putExtra(String, Parcelable[])} to place
+ * at the front of the list of choices, when shown to the user with an
+ * {@link #ACTION_CHOOSER}. You can choose up to two additional activities
+ * to show before the app suggestions (the limit of two additional activities starts in
+ * Android 10).
*/
public static final String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS";
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 973fe01..9a7aeef 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3735,14 +3735,6 @@
public static final String FEATURE_MANAGED_PROFILES = "android.software.managed_users";
/**
- * @hide
- * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
- * The device supports Nearby mainline feature.
- */
- @SdkConstant(SdkConstantType.FEATURE)
- public static final String FEATURE_NEARBY = "android.software.nearby";
-
- /**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device supports verified boot.
*/
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 282f1d3..3a8513b 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -464,7 +464,8 @@
IntentFilter filter = new IntentFilter("dynamic_sensor_change");
filter.addAction(Intent.ACTION_DYNAMIC_SENSOR_CHANGED);
- mContext.registerReceiver(mDynamicSensorBroadcastReceiver, filter);
+ mContext.registerReceiver(mDynamicSensorBroadcastReceiver, filter,
+ Context.RECEIVER_NOT_EXPORTED);
}
}
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 01833fd..e731165 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -965,7 +965,7 @@
private static final class DisplayListenerDelegate extends Handler {
public final DisplayListener mListener;
- public long mEventsMask;
+ public volatile long mEventsMask;
private final DisplayInfo mDisplayInfo = new DisplayInfo();
@@ -985,12 +985,12 @@
removeCallbacksAndMessages(null);
}
- public synchronized void setEventsMask(@EventsMask long newEventsMask) {
+ public void setEventsMask(@EventsMask long newEventsMask) {
mEventsMask = newEventsMask;
}
@Override
- public synchronized void handleMessage(Message msg) {
+ public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_DISPLAY_ADDED:
if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) {
diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java
index 3b50f0f..9468ca2 100644
--- a/core/java/android/hardware/location/ContextHubClient.java
+++ b/core/java/android/hardware/location/ContextHubClient.java
@@ -30,7 +30,7 @@
/**
* A class describing a client of the Context Hub Service.
- *
+ * <p>
* Clients can send messages to nanoapps at a Context Hub through this object. The APIs supported
* by this object are thread-safe and can be used without external synchronization.
*
@@ -110,7 +110,7 @@
* This value can be used as an identifier for the messaging channel between a
* ContextHubClient and the Context Hub. This may be used as a routing mechanism
* between various ContextHubClient objects within an application.
- *
+ * <p>
* The value returned by this method will remain the same if it is associated with
* the same client reference at the ContextHubService (for instance, the ID of a
* PendingIntent ContextHubClient will remain the same even if the local object
@@ -119,8 +119,6 @@
* of a non-equal PendingIntent client), the ID will not be the same.
*
* @return The ID of this ContextHubClient.
- *
- * @throws IllegalStateException if the ID was not set internally.
*/
public int getId() {
if (mId == null) {
@@ -135,7 +133,7 @@
* When this function is invoked, the messaging associated with this client is invalidated.
* All futures messages targeted for this client are dropped at the service, and the
* ContextHubClient is unregistered from the service.
- *
+ * <p>
* If this object has a PendingIntent, i.e. the object was generated via
* {@link ContextHubManager.createClient(PendingIntent, ContextHubInfo, long)}, then the
* Intent events corresponding to the PendingIntent will no longer be triggered.
@@ -158,7 +156,7 @@
*
* This function returns RESULT_SUCCESS if the message has reached the HAL, but
* does not guarantee delivery of the message to the target nanoapp.
- *
+ * <p>
* Before sending the first message to your nanoapp, it's recommended that the following
* operations should be performed:
* 1) Invoke {@link ContextHubManager#queryNanoApps(ContextHubInfo)} to verify the nanoapp is
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 22b444e..afaa085 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -51,7 +51,6 @@
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
-import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -1340,28 +1339,43 @@
mInflater = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initSoftInputWindow");
- mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
- WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
- mWindow.getWindow().getAttributes().setFitInsetsTypes(statusBars() | navigationBars());
- mWindow.getWindow().getAttributes().setFitInsetsSides(Side.all() & ~Side.BOTTOM);
- mWindow.getWindow().getAttributes().receiveInsetsIgnoringZOrder = true;
+ mWindow = new SoftInputWindow(this, mTheme, mDispatcherState);
- // Automotive devices may request the navigation bar to be hidden when the IME shows up
- // (controlled via config_automotiveHideNavBarForKeyboard) in order to maximize the visible
- // screen real estate. When this happens, the IME window should animate from the bottom of
- // the screen to reduce the jank that happens from the lack of synchronization between the
- // bottom system window and the IME window.
- if (mIsAutomotive && mAutomotiveHideNavBarForKeyboard) {
- mWindow.getWindow().setDecorFitsSystemWindows(false);
+ {
+ final Window window = mWindow.getWindow();
+ {
+ final WindowManager.LayoutParams lp = window.getAttributes();
+ lp.setTitle("InputMethod");
+ lp.type = WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+ lp.width = WindowManager.LayoutParams.MATCH_PARENT;
+ lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
+ lp.gravity = Gravity.BOTTOM;
+ lp.setFitInsetsTypes(statusBars() | navigationBars());
+ lp.setFitInsetsSides(Side.all() & ~Side.BOTTOM);
+ lp.receiveInsetsIgnoringZOrder = true;
+ window.setAttributes(lp);
+ }
+
+ // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set
+ // by default (but IME developers can opt this out later if they want a new behavior).
+ final int windowFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ final int windowFlagsMask = windowFlags
+ | WindowManager.LayoutParams.FLAG_DIM_BEHIND; // to be unset
+ window.setFlags(windowFlags, windowFlagsMask);
+
+ // Automotive devices may request the navigation bar to be hidden when the IME shows up
+ // (controlled via config_automotiveHideNavBarForKeyboard) in order to maximize the
+ // visible screen real estate. When this happens, the IME window should animate from the
+ // bottom of the screen to reduce the jank that happens from the lack of synchronization
+ // between the bottom system window and the IME window.
+ if (mIsAutomotive && mAutomotiveHideNavBarForKeyboard) {
+ window.setDecorFitsSystemWindows(false);
+ }
}
- // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set
- // by default (but IME developers can opt this out later if they want a new behavior).
- mWindow.getWindow().setFlags(
- FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
-
initViews();
- mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
mInlineSuggestionSessionController = new InlineSuggestionSessionController(
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index bc0b37e..66288d6 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -1,17 +1,17 @@
/*
- * Copyright (C) 2007-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
- *
+ * 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.
+ * 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.inputmethodservice;
@@ -42,29 +42,22 @@
import java.lang.annotation.Retention;
/**
- * A SoftInputWindow is a Dialog that is intended to be used for a top-level input
- * method window. It will be displayed along the edge of the screen, moving
- * the application user interface away from it so that the focused item is
- * always visible.
- * @hide
+ * A {@link SoftInputWindow} is a {@link Dialog} that is intended to be used for a top-level input
+ * method window. It will be displayed along the edge of the screen, moving the application user
+ * interface away from it so that the focused item is always visible.
*/
-public class SoftInputWindow extends Dialog {
+final class SoftInputWindow extends Dialog {
private static final boolean DEBUG = false;
private static final String TAG = "SoftInputWindow";
- final String mName;
- final Callback mCallback;
- final KeyEvent.Callback mKeyEventCallback;
- final KeyEvent.DispatcherState mDispatcherState;
- final int mWindowType;
- final int mGravity;
- final boolean mTakesFocus;
+ private final KeyEvent.DispatcherState mDispatcherState;
private final Rect mBounds = new Rect();
@Retention(SOURCE)
- @IntDef(value = {SoftInputWindowState.TOKEN_PENDING, SoftInputWindowState.TOKEN_SET,
- SoftInputWindowState.SHOWN_AT_LEAST_ONCE, SoftInputWindowState.REJECTED_AT_LEAST_ONCE})
- private @interface SoftInputWindowState {
+ @IntDef(value = {WindowState.TOKEN_PENDING, WindowState.TOKEN_SET,
+ WindowState.SHOWN_AT_LEAST_ONCE, WindowState.REJECTED_AT_LEAST_ONCE,
+ WindowState.DESTROYED})
+ private @interface WindowState {
/**
* The window token is not set yet.
*/
@@ -88,21 +81,23 @@
int DESTROYED = 4;
}
- @SoftInputWindowState
- private int mWindowState = SoftInputWindowState.TOKEN_PENDING;
+ @WindowState
+ private int mWindowState = WindowState.TOKEN_PENDING;
- public interface Callback {
- public void onBackPressed();
- }
-
- public void setToken(IBinder token) {
+ /**
+ * Set {@link IBinder} window token to the window.
+ *
+ * <p>This method can be called only once.</p>
+ * @param token {@link IBinder} token to be associated with the window.
+ */
+ void setToken(IBinder token) {
switch (mWindowState) {
- case SoftInputWindowState.TOKEN_PENDING:
+ case WindowState.TOKEN_PENDING:
// Normal scenario. Nothing to worry about.
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.token = token;
getWindow().setAttributes(lp);
- updateWindowState(SoftInputWindowState.TOKEN_SET);
+ updateWindowState(WindowState.TOKEN_SET);
// As soon as we have a token, make sure the window is added (but not shown) by
// setting visibility to INVISIBLE and calling show() on Dialog. Note that
@@ -111,11 +106,11 @@
getWindow().getDecorView().setVisibility(View.INVISIBLE);
show();
return;
- case SoftInputWindowState.TOKEN_SET:
- case SoftInputWindowState.SHOWN_AT_LEAST_ONCE:
- case SoftInputWindowState.REJECTED_AT_LEAST_ONCE:
+ case WindowState.TOKEN_SET:
+ case WindowState.SHOWN_AT_LEAST_ONCE:
+ case WindowState.REJECTED_AT_LEAST_ONCE:
throw new IllegalStateException("setToken can be called only once");
- case SoftInputWindowState.DESTROYED:
+ case WindowState.DESTROYED:
// Just ignore. Since there are multiple event queues from the token is issued
// in the system server to the timing when it arrives here, it can be delivered
// after the is already destroyed. No one should be blamed because of such an
@@ -129,7 +124,7 @@
/**
* Create a SoftInputWindow that uses a custom style.
- *
+ *
* @param context The Context in which the DockWindow should run. In
* particular, it uses the window manager and theme from this context
* to present its UI.
@@ -139,18 +134,9 @@
* using styles. This theme is applied on top of the current theme in
* <var>context</var>. If 0, the default dialog theme will be used.
*/
- public SoftInputWindow(Context context, String name, int theme, Callback callback,
- KeyEvent.Callback keyEventCallback, KeyEvent.DispatcherState dispatcherState,
- int windowType, int gravity, boolean takesFocus) {
+ SoftInputWindow(Context context, int theme, KeyEvent.DispatcherState dispatcherState) {
super(context, theme);
- mName = name;
- mCallback = callback;
- mKeyEventCallback = keyEventCallback;
mDispatcherState = dispatcherState;
- mWindowType = windowType;
- mGravity = gravity;
- mTakesFocus = takesFocus;
- initDockWindow();
}
@Override
@@ -175,108 +161,17 @@
}
}
- /**
- * Set which boundary of the screen the DockWindow sticks to.
- *
- * @param gravity The boundary of the screen to stick. See {@link
- * android.view.Gravity.LEFT}, {@link android.view.Gravity.TOP},
- * {@link android.view.Gravity.BOTTOM}, {@link
- * android.view.Gravity.RIGHT}.
- */
- public void setGravity(int gravity) {
- WindowManager.LayoutParams lp = getWindow().getAttributes();
- lp.gravity = gravity;
- updateWidthHeight(lp);
- getWindow().setAttributes(lp);
- }
-
- public int getGravity() {
- return getWindow().getAttributes().gravity;
- }
-
- private void updateWidthHeight(WindowManager.LayoutParams lp) {
- if (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM) {
- lp.width = WindowManager.LayoutParams.MATCH_PARENT;
- lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
- } else {
- lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
- lp.height = WindowManager.LayoutParams.MATCH_PARENT;
- }
- }
-
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (mKeyEventCallback != null && mKeyEventCallback.onKeyDown(keyCode, event)) {
- return true;
- }
- return super.onKeyDown(keyCode, event);
- }
-
- public boolean onKeyLongPress(int keyCode, KeyEvent event) {
- if (mKeyEventCallback != null && mKeyEventCallback.onKeyLongPress(keyCode, event)) {
- return true;
- }
- return super.onKeyLongPress(keyCode, event);
- }
-
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (mKeyEventCallback != null && mKeyEventCallback.onKeyUp(keyCode, event)) {
- return true;
- }
- return super.onKeyUp(keyCode, event);
- }
-
- public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
- if (mKeyEventCallback != null && mKeyEventCallback.onKeyMultiple(keyCode, count, event)) {
- return true;
- }
- return super.onKeyMultiple(keyCode, count, event);
- }
-
- public void onBackPressed() {
- if (mCallback != null) {
- mCallback.onBackPressed();
- } else {
- super.onBackPressed();
- }
- }
-
- private void initDockWindow() {
- WindowManager.LayoutParams lp = getWindow().getAttributes();
-
- lp.type = mWindowType;
- lp.setTitle(mName);
-
- lp.gravity = mGravity;
- updateWidthHeight(lp);
-
- getWindow().setAttributes(lp);
-
- int windowSetFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
- int windowModFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
- WindowManager.LayoutParams.FLAG_DIM_BEHIND;
-
- if (!mTakesFocus) {
- windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- } else {
- windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
- windowModFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
- }
-
- getWindow().setFlags(windowSetFlags, windowModFlags);
- }
-
@Override
- public final void show() {
+ public void show() {
switch (mWindowState) {
- case SoftInputWindowState.TOKEN_PENDING:
+ case WindowState.TOKEN_PENDING:
throw new IllegalStateException("Window token is not set yet.");
- case SoftInputWindowState.TOKEN_SET:
- case SoftInputWindowState.SHOWN_AT_LEAST_ONCE:
+ case WindowState.TOKEN_SET:
+ case WindowState.SHOWN_AT_LEAST_ONCE:
// Normal scenario. Nothing to worry about.
try {
super.show();
- updateWindowState(SoftInputWindowState.SHOWN_AT_LEAST_ONCE);
+ updateWindowState(WindowState.SHOWN_AT_LEAST_ONCE);
} catch (WindowManager.BadTokenException e) {
// Just ignore this exception. Since show() can be requested from other
// components such as the system and there could be multiple event queues before
@@ -286,14 +181,14 @@
// the state so that we do not touch this window later.
Log.i(TAG, "Probably the IME window token is already invalidated."
+ " show() does nothing.");
- updateWindowState(SoftInputWindowState.REJECTED_AT_LEAST_ONCE);
+ updateWindowState(WindowState.REJECTED_AT_LEAST_ONCE);
}
return;
- case SoftInputWindowState.REJECTED_AT_LEAST_ONCE:
+ case WindowState.REJECTED_AT_LEAST_ONCE:
// Just ignore. In general we cannot completely avoid this kind of race condition.
Log.i(TAG, "Not trying to call show() because it was already rejected once.");
return;
- case SoftInputWindowState.DESTROYED:
+ case WindowState.DESTROYED:
// Just ignore. In general we cannot completely avoid this kind of race condition.
Log.i(TAG, "Ignoring show() because the window is already destroyed.");
return;
@@ -302,14 +197,14 @@
}
}
- final void dismissForDestroyIfNecessary() {
+ void dismissForDestroyIfNecessary() {
switch (mWindowState) {
- case SoftInputWindowState.TOKEN_PENDING:
- case SoftInputWindowState.TOKEN_SET:
+ case WindowState.TOKEN_PENDING:
+ case WindowState.TOKEN_SET:
// nothing to do because the window has never been shown.
- updateWindowState(SoftInputWindowState.DESTROYED);
+ updateWindowState(WindowState.DESTROYED);
return;
- case SoftInputWindowState.SHOWN_AT_LEAST_ONCE:
+ case WindowState.SHOWN_AT_LEAST_ONCE:
// Disable exit animation for the current IME window
// to avoid the race condition between the exit and enter animations
// when the current IME is being switched to another one.
@@ -327,16 +222,16 @@
+ "No need to dismiss it.");
}
// Either way, consider that the window is destroyed.
- updateWindowState(SoftInputWindowState.DESTROYED);
+ updateWindowState(WindowState.DESTROYED);
return;
- case SoftInputWindowState.REJECTED_AT_LEAST_ONCE:
+ case WindowState.REJECTED_AT_LEAST_ONCE:
// Just ignore. In general we cannot completely avoid this kind of race condition.
Log.i(TAG,
"Not trying to dismiss the window because it is most likely unnecessary.");
// Anyway, consider that the window is destroyed.
- updateWindowState(SoftInputWindowState.DESTROYED);
+ updateWindowState(WindowState.DESTROYED);
return;
- case SoftInputWindowState.DESTROYED:
+ case WindowState.DESTROYED:
throw new IllegalStateException(
"dismissForDestroyIfNecessary can be called only once");
default:
@@ -344,7 +239,7 @@
}
}
- private void updateWindowState(@SoftInputWindowState int newState) {
+ private void updateWindowState(@WindowState int newState) {
if (DEBUG) {
if (mWindowState != newState) {
Log.d(TAG, "WindowState: " + stateToString(mWindowState) + " -> "
@@ -354,17 +249,17 @@
mWindowState = newState;
}
- private static String stateToString(@SoftInputWindowState int state) {
+ private static String stateToString(@WindowState int state) {
switch (state) {
- case SoftInputWindowState.TOKEN_PENDING:
+ case WindowState.TOKEN_PENDING:
return "TOKEN_PENDING";
- case SoftInputWindowState.TOKEN_SET:
+ case WindowState.TOKEN_SET:
return "TOKEN_SET";
- case SoftInputWindowState.SHOWN_AT_LEAST_ONCE:
+ case WindowState.SHOWN_AT_LEAST_ONCE:
return "SHOWN_AT_LEAST_ONCE";
- case SoftInputWindowState.REJECTED_AT_LEAST_ONCE:
+ case WindowState.REJECTED_AT_LEAST_ONCE:
return "REJECTED_AT_LEAST_ONCE";
- case SoftInputWindowState.DESTROYED:
+ case WindowState.DESTROYED:
return "DESTROYED";
default:
throw new IllegalStateException("Unknown state=" + state);
@@ -373,10 +268,11 @@
void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
- proto.write(NAME, mName);
- proto.write(WINDOW_TYPE, mWindowType);
- proto.write(GRAVITY, mGravity);
- proto.write(TAKES_FOCUS, mTakesFocus);
+ // TODO(b/192412909): Deprecate the following 4 entries, as they are all constant.
+ proto.write(NAME, "InputMethod");
+ proto.write(WINDOW_TYPE, WindowManager.LayoutParams.TYPE_INPUT_METHOD);
+ proto.write(GRAVITY, Gravity.BOTTOM);
+ proto.write(TAKES_FOCUS, false);
mBounds.dumpDebug(proto, BOUNDS);
proto.write(WINDOW_STATE, mWindowState);
proto.end(token);
diff --git a/core/java/android/net/IInternalNetworkManagementListener.aidl b/core/java/android/net/IInternalNetworkManagementListener.aidl
new file mode 100644
index 0000000..69cde3b
--- /dev/null
+++ b/core/java/android/net/IInternalNetworkManagementListener.aidl
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.InternalNetworkManagementException;
+import android.net.Network;
+
+/** @hide */
+oneway interface IInternalNetworkManagementListener {
+ void onComplete(in Network network, in InternalNetworkManagementException exception);
+}
\ No newline at end of file
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index b18e9be..fab692c 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -142,8 +142,9 @@
boolean isBypassable,
boolean isMetered,
int maxMtu,
- boolean restrictToTestNetworks) {
- super(type);
+ boolean restrictToTestNetworks,
+ boolean excludeLocalRoutes) {
+ super(type, excludeLocalRoutes);
checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "Server address");
checkNotNull(userIdentity, MISSING_PARAM_MSG_TMPL, "User Identity");
@@ -403,7 +404,8 @@
&& mIsBypassable == other.mIsBypassable
&& mIsMetered == other.mIsMetered
&& mMaxMtu == other.mMaxMtu
- && mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks;
+ && mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks
+ && mExcludeLocalRoutes == other.mExcludeLocalRoutes;
}
/**
@@ -417,7 +419,7 @@
@NonNull
public VpnProfile toVpnProfile() throws IOException, GeneralSecurityException {
final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */,
- mIsRestrictedToTestNetworks);
+ mIsRestrictedToTestNetworks, mExcludeLocalRoutes);
profile.type = mType;
profile.server = mServerAddr;
profile.ipsecIdentifier = mUserIdentity;
@@ -518,6 +520,8 @@
throw new IllegalArgumentException("Invalid auth method set");
}
+ builder.setExcludeLocalRoutes(profile.excludeLocalRoutes);
+
return builder.build();
}
@@ -657,6 +661,7 @@
private boolean mIsMetered = true;
private int mMaxMtu = PlatformVpnProfile.MAX_MTU_DEFAULT;
private boolean mIsRestrictedToTestNetworks = false;
+ private boolean mExcludeLocalRoutes = false;
/**
* Creates a new builder with the basic parameters of an IKEv2/IPsec VPN.
@@ -902,6 +907,18 @@
}
/**
+ * Sets whether the local traffic is exempted from the VPN.
+ *
+ * @hide TODO(184750836): unhide once the implementation is completed
+ */
+ @NonNull
+ @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
+ public Builder setExcludeLocalRoutes(boolean excludeLocalRoutes) {
+ mExcludeLocalRoutes = excludeLocalRoutes;
+ return this;
+ }
+
+ /**
* Validates, builds and provisions the VpnProfile.
*
* @throws IllegalArgumentException if any of the required keys or values were invalid
@@ -924,7 +941,8 @@
mIsBypassable,
mIsMetered,
mMaxMtu,
- mIsRestrictedToTestNetworks);
+ mIsRestrictedToTestNetworks,
+ mExcludeLocalRoutes);
}
}
}
diff --git a/core/java/android/net/InternalNetworkManagementException.aidl b/core/java/android/net/InternalNetworkManagementException.aidl
new file mode 100644
index 0000000..dcce706
--- /dev/null
+++ b/core/java/android/net/InternalNetworkManagementException.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ package android.net;
+
+ parcelable InternalNetworkManagementException;
\ No newline at end of file
diff --git a/core/java/android/net/InternalNetworkManagementException.java b/core/java/android/net/InternalNetworkManagementException.java
new file mode 100644
index 0000000..7f4e403
--- /dev/null
+++ b/core/java/android/net/InternalNetworkManagementException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public final class InternalNetworkManagementException
+ extends RuntimeException implements Parcelable {
+
+ /* @hide */
+ public InternalNetworkManagementException(@NonNull final Throwable t) {
+ super(t);
+ }
+
+ private InternalNetworkManagementException(@NonNull final Parcel source) {
+ super(source.readString());
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(getCause().getMessage());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<InternalNetworkManagementException> CREATOR =
+ new Parcelable.Creator<InternalNetworkManagementException>() {
+ @Override
+ public InternalNetworkManagementException[] newArray(int size) {
+ return new InternalNetworkManagementException[size];
+ }
+
+ @Override
+ public InternalNetworkManagementException createFromParcel(@NonNull Parcel source) {
+ return new InternalNetworkManagementException(source);
+ }
+ };
+}
diff --git a/core/java/android/net/InternalNetworkUpdateRequest.aidl b/core/java/android/net/InternalNetworkUpdateRequest.aidl
new file mode 100644
index 0000000..da00cb9
--- /dev/null
+++ b/core/java/android/net/InternalNetworkUpdateRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ package android.net;
+
+ parcelable InternalNetworkUpdateRequest;
\ No newline at end of file
diff --git a/core/java/android/net/InternalNetworkUpdateRequest.java b/core/java/android/net/InternalNetworkUpdateRequest.java
new file mode 100644
index 0000000..6f09383
--- /dev/null
+++ b/core/java/android/net/InternalNetworkUpdateRequest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/** @hide */
+public final class InternalNetworkUpdateRequest implements Parcelable {
+ @NonNull
+ private final StaticIpConfiguration mIpConfig;
+ @Nullable
+ private final NetworkCapabilities mNetworkCapabilities;
+
+ @NonNull
+ public StaticIpConfiguration getIpConfig() {
+ return new StaticIpConfiguration(mIpConfig);
+ }
+
+ @NonNull
+ public NetworkCapabilities getNetworkCapabilities() {
+ return mNetworkCapabilities == null
+ ? null : new NetworkCapabilities(mNetworkCapabilities);
+ }
+
+ /** @hide */
+ public InternalNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig,
+ @Nullable final NetworkCapabilities networkCapabilities) {
+ Objects.requireNonNull(ipConfig);
+ mIpConfig = new StaticIpConfiguration(ipConfig);
+ if (null == networkCapabilities) {
+ mNetworkCapabilities = null;
+ } else {
+ mNetworkCapabilities = new NetworkCapabilities(networkCapabilities);
+ }
+ }
+
+ private InternalNetworkUpdateRequest(@NonNull final Parcel source) {
+ Objects.requireNonNull(source);
+ mIpConfig = StaticIpConfiguration.CREATOR.createFromParcel(source);
+ mNetworkCapabilities = NetworkCapabilities.CREATOR.createFromParcel(source);
+ }
+
+ @Override
+ public String toString() {
+ return "InternalNetworkUpdateRequest{"
+ + "mIpConfig=" + mIpConfig
+ + ", mNetworkCapabilities=" + mNetworkCapabilities + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ InternalNetworkUpdateRequest that = (InternalNetworkUpdateRequest) o;
+
+ return Objects.equals(that.getIpConfig(), mIpConfig)
+ && Objects.equals(that.getNetworkCapabilities(), mNetworkCapabilities);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mIpConfig, mNetworkCapabilities);
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ mIpConfig.writeToParcel(dest, flags);
+ mNetworkCapabilities.writeToParcel(dest, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<InternalNetworkUpdateRequest> CREATOR =
+ new Parcelable.Creator<InternalNetworkUpdateRequest>() {
+ @Override
+ public InternalNetworkUpdateRequest[] newArray(int size) {
+ return new InternalNetworkUpdateRequest[size];
+ }
+
+ @Override
+ public InternalNetworkUpdateRequest createFromParcel(@NonNull Parcel source) {
+ return new InternalNetworkUpdateRequest(source);
+ }
+ };
+}
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index f33a035..f4b427959f 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -18,9 +18,11 @@
import static android.net.NetworkStats.METERED_ALL;
import static android.net.NetworkStats.METERED_YES;
+import static android.net.NetworkTemplate.MATCH_BLUETOOTH;
import static android.net.NetworkTemplate.MATCH_CARRIER;
+import static android.net.NetworkTemplate.MATCH_ETHERNET;
import static android.net.NetworkTemplate.MATCH_MOBILE;
-import static android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT;
+import static android.net.NetworkTemplate.MATCH_WIFI;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -42,6 +44,7 @@
import java.time.ZonedDateTime;
import java.util.Iterator;
import java.util.Objects;
+import java.util.Set;
/**
* Policy for networks matching a {@link NetworkTemplate}, including usage cycle
@@ -59,15 +62,16 @@
* Initial Version of the NetworkTemplate backup serializer.
*/
private static final int TEMPLATE_BACKUP_VERSION_1_INIT = 1;
+ private static final int TEMPLATE_BACKUP_VERSION_2_UNSUPPORTED = 2;
/**
* Version of the NetworkTemplate backup serializer that added carrier template support.
*/
- private static final int TEMPLATE_BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE = 2;
+ private static final int TEMPLATE_BACKUP_VERSION_3_SUPPORT_CARRIER_TEMPLATE = 3;
/**
* Latest Version of the NetworkTemplate Backup Serializer.
*/
private static final int TEMPLATE_BACKUP_VERSION_LATEST =
- TEMPLATE_BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE;
+ TEMPLATE_BACKUP_VERSION_3_SUPPORT_CARRIER_TEMPLATE;
public static final int CYCLE_NONE = -1;
public static final long WARNING_DISABLED = -1;
@@ -324,7 +328,7 @@
@NonNull
private byte[] getNetworkTemplateBytesForBackup() throws IOException {
- if (!template.isPersistable()) {
+ if (!isTemplatePersistable(this.template)) {
Log.wtf(TAG, "Trying to backup non-persistable template: " + this);
}
@@ -334,10 +338,9 @@
out.writeInt(TEMPLATE_BACKUP_VERSION_LATEST);
out.writeInt(template.getMatchRule());
- BackupUtils.writeString(out, template.getSubscriberId());
- BackupUtils.writeString(out, template.getNetworkId());
+ BackupUtils.writeString(out, template.getSubscriberIds().iterator().next());
+ BackupUtils.writeString(out, template.getWifiNetworkKey());
out.writeInt(template.getMeteredness());
- out.writeInt(template.getSubscriberIdMatchRule());
return baos.toByteArray();
}
@@ -346,36 +349,61 @@
private static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in)
throws IOException, BackupUtils.BadVersionException {
int version = in.readInt();
- if (version < TEMPLATE_BACKUP_VERSION_1_INIT || version > TEMPLATE_BACKUP_VERSION_LATEST) {
+ if (version < TEMPLATE_BACKUP_VERSION_1_INIT || version > TEMPLATE_BACKUP_VERSION_LATEST
+ || version == TEMPLATE_BACKUP_VERSION_2_UNSUPPORTED) {
throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
}
int matchRule = in.readInt();
final String subscriberId = BackupUtils.readString(in);
- final String networkId = BackupUtils.readString(in);
+ final String wifiNetworkKey = BackupUtils.readString(in);
final int metered;
- final int subscriberIdMatchRule;
- if (version >= TEMPLATE_BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE) {
+ if (version >= TEMPLATE_BACKUP_VERSION_3_SUPPORT_CARRIER_TEMPLATE) {
metered = in.readInt();
- subscriberIdMatchRule = in.readInt();
} else {
// For backward compatibility, fill the missing filters from match rules.
- metered = (matchRule == MATCH_MOBILE
- || matchRule == NetworkTemplate.MATCH_MOBILE_WILDCARD
- || matchRule == MATCH_CARRIER) ? METERED_YES : METERED_ALL;
- subscriberIdMatchRule = SUBSCRIBER_ID_MATCH_RULE_EXACT;
+ metered = (matchRule == MATCH_MOBILE || matchRule == MATCH_CARRIER)
+ ? METERED_YES : METERED_ALL;
}
try {
- return new NetworkTemplate(matchRule,
- subscriberId, new String[]{subscriberId},
- networkId, metered, NetworkStats.ROAMING_ALL,
- NetworkStats.DEFAULT_NETWORK_ALL, NetworkTemplate.NETWORK_TYPE_ALL,
- NetworkTemplate.OEM_MANAGED_ALL, subscriberIdMatchRule);
+ final NetworkTemplate.Builder builder = new NetworkTemplate.Builder(matchRule)
+ .setMeteredness(metered);
+ if (subscriberId != null) {
+ builder.setSubscriberIds(Set.of(subscriberId));
+ }
+ if (wifiNetworkKey != null) {
+ builder.setWifiNetworkKeys(Set.of(wifiNetworkKey));
+ }
+ return builder.build();
} catch (IllegalArgumentException e) {
throw new BackupUtils.BadVersionException(
"Restored network template contains unknown match rule " + matchRule, e);
}
}
+
+ /**
+ * Check if the template can be persisted into disk.
+ */
+ public static boolean isTemplatePersistable(@NonNull NetworkTemplate template) {
+ switch (template.getMatchRule()) {
+ case MATCH_BLUETOOTH:
+ case MATCH_ETHERNET:
+ return true;
+ case MATCH_CARRIER:
+ case MATCH_MOBILE:
+ return !template.getSubscriberIds().isEmpty();
+ case MATCH_WIFI:
+ if (template.getWifiNetworkKeys().isEmpty()
+ && template.getSubscriberIds().isEmpty()) {
+ return false;
+ }
+ return true;
+ default:
+ // Don't allow persistable for unknown types or legacy types such as
+ // MATCH_MOBILE_WILDCARD, MATCH_PROXY, etc.
+ return false;
+ }
+ }
}
diff --git a/core/java/android/net/PlatformVpnProfile.java b/core/java/android/net/PlatformVpnProfile.java
index 445ec91..777a90c 100644
--- a/core/java/android/net/PlatformVpnProfile.java
+++ b/core/java/android/net/PlatformVpnProfile.java
@@ -66,15 +66,30 @@
@PlatformVpnType protected final int mType;
/** @hide */
- PlatformVpnProfile(@PlatformVpnType int type) {
+ protected final boolean mExcludeLocalRoutes;
+
+ /** @hide */
+ PlatformVpnProfile(@PlatformVpnType int type, boolean excludeLocalRoutes) {
mType = type;
+ mExcludeLocalRoutes = excludeLocalRoutes;
}
+
/** Returns the profile integer type. */
@PlatformVpnType
public final int getType() {
return mType;
}
+
+ /**
+ * Returns if the local traffic is exempted from the VPN.
+ *
+ * @hide TODO(184750836): unhide once the implementation is completed
+ */
+ public final boolean getExcludeLocalRoutes() {
+ return mExcludeLocalRoutes;
+ }
+
/** Returns a type string describing the VPN profile type */
@NonNull
public final String getTypeString() {
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index e2f5908..17f57a8 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -218,7 +218,8 @@
/**
* Checks whether a given data access chain described by the given {@link AttributionSource}
* has a given permission. Call this method if you are the datasource which would not blame you
- * for access to the data since you are the data.
+ * for access to the data since you are the data. Use this API if you are the datasource of the
+ * protected state.
*
* <strong>NOTE:</strong> Use this method only for permission checks at the
* point where you will deliver the permission protected data to clients.
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index f0e6624..658e033 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -318,7 +318,7 @@
String permGroup = usedPermGroups.get(permGroupNum);
ArrayMap<OpUsage, CharSequence> usagesWithLabels =
- getUniqueUsagesWithLabels(rawUsages.get(permGroup));
+ getUniqueUsagesWithLabels(permGroup, rawUsages.get(permGroup));
if (permGroup.equals(OPSTR_PHONE_CALL_MICROPHONE)) {
isPhone = true;
@@ -439,7 +439,8 @@
return ListFormatter.getInstance().format(labels);
}
- private ArrayMap<OpUsage, CharSequence> getUniqueUsagesWithLabels(List<OpUsage> usages) {
+ private ArrayMap<OpUsage, CharSequence> getUniqueUsagesWithLabels(String permGroup,
+ List<OpUsage> usages) {
ArrayMap<OpUsage, CharSequence> usagesAndLabels = new ArrayMap<>();
if (usages == null || usages.isEmpty()) {
@@ -474,7 +475,7 @@
// If this usage has a proxy, but is not a proxy, it is the end of a chain.
// TODO remove once camera converted
if (!proxies.containsKey(usageAttr) && usage.proxy != null
- && !usage.op.equals(OPSTR_RECORD_AUDIO)) {
+ && !MICROPHONE.equals(permGroup)) {
proxyLabels.put(usage, new ArrayList<>());
proxyPackages.add(usage.getPackageIdHash());
}
@@ -546,7 +547,7 @@
// TODO ntmyren: remove this proxy logic once camera is converted to AttributionSource
// For now: don't add mic proxy usages
- if (!start.op.equals(OPSTR_RECORD_AUDIO)) {
+ if (!MICROPHONE.equals(permGroup)) {
usagesAndLabels.put(start,
proxyLabelList.isEmpty() ? null : formatLabelList(proxyLabelList));
}
@@ -560,7 +561,8 @@
// if the list is empty or incomplete, do not show it.
if (usageList.isEmpty() || !usageList.get(lastVisible).isEnd()
|| !usageList.get(0).isStart()
- || !usageList.get(lastVisible).usage.op.equals(OPSTR_RECORD_AUDIO)) {
+ || !permGroup.equals(getGroupForOp(usageList.get(0).usage.op))
+ || !MICROPHONE.equals(permGroup)) {
continue;
}
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 22b9578..6349cde 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -564,6 +564,14 @@
public static final String NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT = "window_manager_native_boot";
/**
+ * Definitions for selection toolbar related functions.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final String NAMESPACE_SELECTION_TOOLBAR = "selection_toolbar";
+
+ /**
* List of namespaces which can be read without READ_DEVICE_CONFIG permission
*
* @hide
@@ -571,7 +579,7 @@
@NonNull
private static final List<String> PUBLIC_NAMESPACES =
Arrays.asList(NAMESPACE_TEXTCLASSIFIER, NAMESPACE_RUNTIME, NAMESPACE_STATSD_JAVA,
- NAMESPACE_STATSD_JAVA_BOOT);
+ NAMESPACE_STATSD_JAVA_BOOT, NAMESPACE_SELECTION_TOOLBAR);
/**
* Privacy related properties definitions.
*
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index edacffc..190b8f6 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5945,7 +5945,6 @@
MOVED_TO_GLOBAL.add(Settings.Global.CONNECTIVITY_CHANGE_DELAY);
MOVED_TO_GLOBAL.add(Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED);
MOVED_TO_GLOBAL.add(Settings.Global.CAPTIVE_PORTAL_SERVER);
- MOVED_TO_GLOBAL.add(Settings.Global.NSD_ON);
MOVED_TO_GLOBAL.add(Settings.Global.SET_INSTALL_LOCATION);
MOVED_TO_GLOBAL.add(Settings.Global.DEFAULT_INSTALL_LOCATION);
MOVED_TO_GLOBAL.add(Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY);
@@ -6496,6 +6495,27 @@
public static final String ALLOW_MOCK_LOCATION = "mock_location";
/**
+ * This is used by Bluetooth Manager to store adapter name
+ * @hide
+ */
+ @Readable(maxTargetSdk = Build.VERSION_CODES.S)
+ public static final String BLUETOOTH_NAME = "bluetooth_name";
+
+ /**
+ * This is used by Bluetooth Manager to store adapter address
+ * @hide
+ */
+ @Readable(maxTargetSdk = Build.VERSION_CODES.S)
+ public static final String BLUETOOTH_ADDRESS = "bluetooth_address";
+
+ /**
+ * This is used by Bluetooth Manager to store whether adapter address is valid
+ * @hide
+ */
+ @Readable(maxTargetSdk = Build.VERSION_CODES.S)
+ public static final String BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid";
+
+ /**
* Setting to indicate that on device captions are enabled.
*
* @hide
@@ -12857,13 +12877,6 @@
@Readable
public static final String MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS =
"min_duration_between_recovery_steps";
- /**
- * Whether network service discovery is enabled.
- *
- * @hide
- */
- @Readable
- public static final String NSD_ON = "nsd_on";
/**
* Let user pick default install location.
@@ -17045,6 +17058,15 @@
*/
public static final String CLOCKWORK_SYSUI_MAIN_ACTIVITY =
"clockwork_sysui_main_activity";
+
+ /**
+ * Setting to disable power button long press launching Assistant. It's boolean, i.e.
+ * enabled = 1, disabled = 0. By default, this setting is enabled.
+ *
+ * @hide
+ */
+ public static final String CLOCKWORK_LONG_PRESS_TO_ASSISTANT_ENABLED =
+ "clockwork_long_press_to_assistant_enabled";
}
}
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 13274c6..29c7796 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -465,7 +465,7 @@
* <p>Prior to Android {@link android.os.Build.VERSION_CODES#P}, the metrics covered just the
* scenarios where the service knew how to autofill an activity, but Android
* {@link android.os.Build.VERSION_CODES#P} introduced a new mechanism called field classification,
- * which allows the service to dinamically classify the meaning of fields based on the existing user
+ * which allows the service to dynamically classify the meaning of fields based on the existing user
* data known by the service.
*
* <p>Typically, field classification can be used to detect fields that can be autofilled with
diff --git a/core/java/android/service/games/CreateGameSessionRequest.aidl b/core/java/android/service/games/CreateGameSessionRequest.aidl
new file mode 100644
index 0000000..e09cc8e
--- /dev/null
+++ b/core/java/android/service/games/CreateGameSessionRequest.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.games;
+
+
+/**
+ * @hide
+ */
+parcelable CreateGameSessionRequest;
\ No newline at end of file
diff --git a/core/java/android/service/games/CreateGameSessionRequest.java b/core/java/android/service/games/CreateGameSessionRequest.java
new file mode 100644
index 0000000..2129cb1
--- /dev/null
+++ b/core/java/android/service/games/CreateGameSessionRequest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.games;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Request object providing the context in order to create a new {@link GameSession}.
+ *
+ * This is provided to the Game Service provider via
+ * {@link GameSessionService#onNewSession(CreateGameSessionRequest)}. It includes game
+ * (see {@link #getGamePackageName()}) that the session is associated with and a task
+ * (see {@link #getTaskId()}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class CreateGameSessionRequest implements Parcelable {
+
+ @NonNull
+ public static final Parcelable.Creator<CreateGameSessionRequest> CREATOR =
+ new Parcelable.Creator<CreateGameSessionRequest>() {
+ @Override
+ public CreateGameSessionRequest createFromParcel(Parcel source) {
+ return new CreateGameSessionRequest(
+ source.readInt(),
+ source.readString8());
+ }
+
+ @Override
+ public CreateGameSessionRequest[] newArray(int size) {
+ return new CreateGameSessionRequest[0];
+ }
+ };
+
+ private final int mTaskId;
+ private final String mGamePackageName;
+
+ public CreateGameSessionRequest(int taskId, @NonNull String gamePackageName) {
+ this.mTaskId = taskId;
+ this.mGamePackageName = gamePackageName;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mTaskId);
+ dest.writeString8(mGamePackageName);
+ }
+
+ /**
+ * Unique identifier for the task.
+ */
+ public int getTaskId() {
+ return mTaskId;
+ }
+
+ /**
+ * The package name of the game associated with the session.
+ */
+ @NonNull
+ public String getGamePackageName() {
+ return mGamePackageName;
+ }
+
+ @Override
+ public String toString() {
+ return "GameSessionRequest{"
+ + "mTaskId="
+ + mTaskId
+ + ", mGamePackageName='"
+ + mGamePackageName
+ + "\'}";
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof CreateGameSessionRequest)) {
+ return false;
+ }
+
+ CreateGameSessionRequest that = (CreateGameSessionRequest) o;
+ return mTaskId == that.mTaskId
+ && Objects.equals(mGamePackageName, that.mGamePackageName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTaskId, mGamePackageName);
+ }
+}
diff --git a/core/java/android/service/games/GameService.java b/core/java/android/service/games/GameService.java
index 4b440dd..b79c055 100644
--- a/core/java/android/service/games/GameService.java
+++ b/core/java/android/service/games/GameService.java
@@ -46,7 +46,7 @@
*/
@SystemApi
public class GameService extends Service {
- static final String TAG = "GameService";
+ private static final String TAG = "GameService";
/**
* The {@link Intent} that must be declared as handled by the service.
@@ -55,8 +55,16 @@
* that other applications can not abuse it.
*/
@SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
- public static final String SERVICE_INTERFACE =
- "android.service.games.GameService";
+ public static final String ACTION_GAME_SERVICE =
+ "android.service.games.action.GAME_SERVICE";
+
+ /**
+ * Name under which a GameService component publishes information about itself.
+ * This meta-data should reference an XML resource containing a
+ * <code><{@link
+ * android.R.styleable#GameService game-session-service}></code> tag.
+ */
+ public static final String SERVICE_META_DATA = "android.game_service";
private IGameManagerService mGameManagerService;
private final IGameService mInterface = new IGameService.Stub() {
@@ -72,6 +80,7 @@
GameService::onDisconnected, GameService.this));
}
};
+
private final IBinder.DeathRecipient mGameManagerServiceDeathRecipient = () -> {
Log.w(TAG, "System service binder died. Shutting down");
@@ -82,9 +91,10 @@
@Override
@Nullable
public IBinder onBind(@Nullable Intent intent) {
- if (SERVICE_INTERFACE.equals(intent.getAction())) {
+ if (ACTION_GAME_SERVICE.equals(intent.getAction())) {
return mInterface.asBinder();
}
+
return null;
}
diff --git a/core/java/android/service/games/GameSession.java b/core/java/android/service/games/GameSession.java
new file mode 100644
index 0000000..0ff08c0
--- /dev/null
+++ b/core/java/android/service/games/GameSession.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.games;
+
+import android.annotation.SystemApi;
+import android.os.Handler;
+
+import com.android.internal.util.function.pooled.PooledLambda;
+
+/**
+ * An active game session, providing a facility for the implementation to interact with the game.
+ *
+ * A Game Service provider should extend the {@link GameSession} to provide their own implementation
+ * which is then returned when a game session is created via
+ * {@link GameSessionService#onNewSession(CreateGameSessionRequest)}.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class GameSession {
+
+ final IGameSession mInterface = new IGameSession.Stub() {
+ @Override
+ public void destroy() {
+ Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
+ GameSession::doDestroy, GameSession.this));
+ }
+ };
+
+ void doCreate() {
+ onCreate();
+ }
+
+ void doDestroy() {
+ onDestroy();
+ }
+
+ /**
+ * Initializer called when the game session is starting.
+ *
+ * This should be used perform any setup required now that the game session is created.
+ */
+ public void onCreate() {}
+
+ /**
+ * Finalizer called when the game session is ending.
+ *
+ * This should be used to perform any cleanup before the game session is destroyed.
+ */
+ public void onDestroy() {}
+}
diff --git a/core/java/android/service/games/GameSessionService.java b/core/java/android/service/games/GameSessionService.java
new file mode 100644
index 0000000..a2c8870
--- /dev/null
+++ b/core/java/android/service/games/GameSessionService.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.games;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.util.function.pooled.PooledLambda;
+
+import java.util.Objects;
+
+/**
+ * Service that hosts active game sessions.
+ *
+ * This service should be in a separate process from the {@link GameService}. This
+ * allows it to perform the heavyweight operations associated with rendering a game
+ * session overlay while games are running and release these resources (by allowing
+ * the process to be killed) when games are not running.
+ *
+ * Game Service providers must extend {@link GameSessionService} and declare the service in their
+ * Manifest. The service must require the {@link android.Manifest.permission#BIND_GAME_SERVICE} so
+ * that other application can not abuse it. This service is used to create instances of
+ * {@link GameSession} via {@link #onNewSession(CreateGameSessionRequest)} and will remain bound to
+ * so long as at least one {@link GameSession} is running.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class GameSessionService extends Service {
+ private static final String TAG = "GameSessionService";
+
+ /**
+ * The {@link Intent} action used when binding to the service.
+ * To be supported, the service must require the
+ * {@link android.Manifest.permission#BIND_GAME_SERVICE} permission so
+ * that other applications can not abuse it.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String ACTION_GAME_SESSION_SERVICE =
+ "android.service.games.action.GAME_SESSION_SERVICE";
+
+ private final IGameSessionService mInterface = new IGameSessionService.Stub() {
+ @Override
+ public void create(CreateGameSessionRequest createGameSessionRequest,
+ AndroidFuture gameSessionFuture) {
+ Handler.getMain().post(PooledLambda.obtainRunnable(
+ GameSessionService::doCreate, GameSessionService.this,
+ createGameSessionRequest,
+ gameSessionFuture));
+ }
+ };
+
+ @Override
+ @Nullable
+ public IBinder onBind(@Nullable Intent intent) {
+ if (intent == null) {
+ return null;
+ }
+
+ if (!ACTION_GAME_SESSION_SERVICE.equals(intent.getAction())) {
+ return null;
+ }
+
+ return mInterface.asBinder();
+ }
+
+ private void doCreate(CreateGameSessionRequest createGameSessionRequest,
+ AndroidFuture<IBinder> gameSessionFuture) {
+ GameSession gameSession = onNewSession(createGameSessionRequest);
+ Objects.requireNonNull(gameSession);
+
+ gameSessionFuture.complete(gameSession.mInterface.asBinder());
+
+ gameSession.doCreate();
+ }
+
+ /**
+ * Request to create a new {@link GameSession}.
+ */
+ @NonNull
+ public abstract GameSession onNewSession(
+ @NonNull CreateGameSessionRequest createGameSessionRequest);
+}
diff --git a/core/java/android/service/games/IGameSession.aidl b/core/java/android/service/games/IGameSession.aidl
new file mode 100644
index 0000000..b2e9f1d
--- /dev/null
+++ b/core/java/android/service/games/IGameSession.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.games;
+
+/**
+ * @hide
+ */
+oneway interface IGameSession {
+ void destroy();
+}
diff --git a/core/java/android/service/games/IGameSessionService.aidl b/core/java/android/service/games/IGameSessionService.aidl
new file mode 100644
index 0000000..2a53ea7
--- /dev/null
+++ b/core/java/android/service/games/IGameSessionService.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.games;
+
+import android.service.games.IGameSession;
+import android.service.games.CreateGameSessionRequest;
+
+import com.android.internal.infra.AndroidFuture;
+
+
+/**
+ * @hide
+ */
+oneway interface IGameSessionService {
+ void create(
+ in CreateGameSessionRequest createGameSessionRequest,
+ in AndroidFuture /* T=IBinder for IGameSession */ gameSessionFuture);
+}
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index e64d685..4bbfbc2 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -38,7 +38,6 @@
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.Region;
-import android.inputmethodservice.SoftInputWindow;
import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -157,7 +156,7 @@
TypedArray mThemeAttrs;
View mRootView;
FrameLayout mContentFrame;
- SoftInputWindow mWindow;
+ VoiceInteractionWindow mWindow;
boolean mUiEnabled = true;
boolean mInitialized;
@@ -859,7 +858,7 @@
static final int MSG_REGISTER_VISIBLE_ACTIVITY_CALLBACK = 110;
static final int MSG_UNREGISTER_VISIBLE_ACTIVITY_CALLBACK = 111;
- class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
+ class MyCallbacks implements HandlerCaller.Callback, VoiceInteractionWindow.Callback {
@Override
public void executeMessage(Message msg) {
SomeArgs args = null;
@@ -1250,7 +1249,7 @@
mInitialized = true;
mInflater = (LayoutInflater)mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
- mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
+ mWindow = new VoiceInteractionWindow(mContext, "VoiceInteractionSession", mTheme,
mCallbacks, this, mDispatcherState,
WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.BOTTOM, true);
mWindow.getWindow().getAttributes().setFitInsetsTypes(0 /* types */);
diff --git a/core/java/android/service/voice/VoiceInteractionWindow.java b/core/java/android/service/voice/VoiceInteractionWindow.java
new file mode 100644
index 0000000..ba1fd45
--- /dev/null
+++ b/core/java/android/service/voice/VoiceInteractionWindow.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.voice;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.app.Dialog;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Debug;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.WindowManager;
+
+import java.lang.annotation.Retention;
+
+/**
+ * A {@link VoiceInteractionWindow} is a {@link Dialog} that is intended to be used for a top-level
+ * {@link VoiceInteractionSession}. It will be displayed along the edge of the screen, moving the
+ * application user interface away from it so that the focused item is always visible.
+ */
+final class VoiceInteractionWindow extends Dialog {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "VoiceInteractionWindow";
+
+ private final String mName;
+ private final Callback mCallback;
+ private final KeyEvent.Callback mKeyEventCallback;
+ private final KeyEvent.DispatcherState mDispatcherState;
+ private final int mWindowType;
+ private final int mGravity;
+ private final boolean mTakesFocus;
+ private final Rect mBounds = new Rect();
+
+ @Retention(SOURCE)
+ @IntDef(value = {WindowState.TOKEN_PENDING, WindowState.TOKEN_SET,
+ WindowState.SHOWN_AT_LEAST_ONCE, WindowState.REJECTED_AT_LEAST_ONCE,
+ WindowState.DESTROYED})
+ private @interface WindowState {
+ /**
+ * The window token is not set yet.
+ */
+ int TOKEN_PENDING = 0;
+ /**
+ * The window token was set, but the window is not shown yet.
+ */
+ int TOKEN_SET = 1;
+ /**
+ * The window was shown at least once.
+ */
+ int SHOWN_AT_LEAST_ONCE = 2;
+ /**
+ * {@link WindowManager.BadTokenException} was sent when calling
+ * {@link Dialog#show()} at least once.
+ */
+ int REJECTED_AT_LEAST_ONCE = 3;
+ /**
+ * The window is considered destroyed. Any incoming request should be ignored.
+ */
+ int DESTROYED = 4;
+ }
+
+ @WindowState
+ private int mWindowState = WindowState.TOKEN_PENDING;
+
+ /**
+ * Used to provide callbacks.
+ */
+ interface Callback {
+ /**
+ * Used to be notified when {@link Dialog#onBackPressed()} gets called.
+ */
+ void onBackPressed();
+ }
+
+ /**
+ * Set {@link IBinder} window token to the window.
+ *
+ * <p>This method can be called only once.</p>
+ * @param token {@link IBinder} token to be associated with the window.
+ */
+ void setToken(IBinder token) {
+ switch (mWindowState) {
+ case WindowState.TOKEN_PENDING:
+ // Normal scenario. Nothing to worry about.
+ WindowManager.LayoutParams lp = getWindow().getAttributes();
+ lp.token = token;
+ getWindow().setAttributes(lp);
+ updateWindowState(WindowState.TOKEN_SET);
+
+ // As soon as we have a token, make sure the window is added (but not shown) by
+ // setting visibility to INVISIBLE and calling show() on Dialog. Note that
+ // WindowInsetsController.OnControllableInsetsChangedListener relies on the window
+ // being added to function.
+ getWindow().getDecorView().setVisibility(View.INVISIBLE);
+ show();
+ return;
+ case WindowState.TOKEN_SET:
+ case WindowState.SHOWN_AT_LEAST_ONCE:
+ case WindowState.REJECTED_AT_LEAST_ONCE:
+ throw new IllegalStateException("setToken can be called only once");
+ case WindowState.DESTROYED:
+ // Just ignore. Since there are multiple event queues from the token is issued
+ // in the system server to the timing when it arrives here, it can be delivered
+ // after the is already destroyed. No one should be blamed because of such an
+ // unfortunate but possible scenario.
+ Log.i(TAG, "Ignoring setToken() because window is already destroyed.");
+ return;
+ default:
+ throw new IllegalStateException("Unexpected state=" + mWindowState);
+ }
+ }
+
+ /**
+ * Create a {@link VoiceInteractionWindow} that uses a custom style.
+ *
+ * @param context The Context in which the DockWindow should run. In
+ * particular, it uses the window manager and theme from this context
+ * to present its UI.
+ * @param theme A style resource describing the theme to use for the window.
+ * See <a href="{@docRoot}reference/available-resources.html#stylesandthemes">Style
+ * and Theme Resources</a> for more information about defining and
+ * using styles. This theme is applied on top of the current theme in
+ * <var>context</var>. If 0, the default dialog theme will be used.
+ */
+ VoiceInteractionWindow(Context context, String name, int theme, Callback callback,
+ KeyEvent.Callback keyEventCallback, KeyEvent.DispatcherState dispatcherState,
+ int windowType, int gravity, boolean takesFocus) {
+ super(context, theme);
+ mName = name;
+ mCallback = callback;
+ mKeyEventCallback = keyEventCallback;
+ mDispatcherState = dispatcherState;
+ mWindowType = windowType;
+ mGravity = gravity;
+ mTakesFocus = takesFocus;
+ initDockWindow();
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ mDispatcherState.reset();
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ getWindow().getDecorView().getHitRect(mBounds);
+
+ if (ev.isWithinBoundsNoHistory(mBounds.left, mBounds.top,
+ mBounds.right - 1, mBounds.bottom - 1)) {
+ return super.dispatchTouchEvent(ev);
+ } else {
+ MotionEvent temp = ev.clampNoHistory(mBounds.left, mBounds.top,
+ mBounds.right - 1, mBounds.bottom - 1);
+ boolean handled = super.dispatchTouchEvent(temp);
+ temp.recycle();
+ return handled;
+ }
+ }
+
+ private void updateWidthHeight(WindowManager.LayoutParams lp) {
+ if (lp.gravity == Gravity.TOP || lp.gravity == Gravity.BOTTOM) {
+ lp.width = WindowManager.LayoutParams.MATCH_PARENT;
+ lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
+ } else {
+ lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
+ lp.height = WindowManager.LayoutParams.MATCH_PARENT;
+ }
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (mKeyEventCallback != null && mKeyEventCallback.onKeyDown(keyCode, event)) {
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ if (mKeyEventCallback != null && mKeyEventCallback.onKeyLongPress(keyCode, event)) {
+ return true;
+ }
+ return super.onKeyLongPress(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (mKeyEventCallback != null && mKeyEventCallback.onKeyUp(keyCode, event)) {
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
+ if (mKeyEventCallback != null && mKeyEventCallback.onKeyMultiple(keyCode, count, event)) {
+ return true;
+ }
+ return super.onKeyMultiple(keyCode, count, event);
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (mCallback != null) {
+ mCallback.onBackPressed();
+ } else {
+ super.onBackPressed();
+ }
+ }
+
+ private void initDockWindow() {
+ WindowManager.LayoutParams lp = getWindow().getAttributes();
+
+ lp.type = mWindowType;
+ lp.setTitle(mName);
+
+ lp.gravity = mGravity;
+ updateWidthHeight(lp);
+
+ getWindow().setAttributes(lp);
+
+ int windowSetFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+ int windowModFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+
+ if (!mTakesFocus) {
+ windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ } else {
+ windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+ windowModFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+ }
+
+ getWindow().setFlags(windowSetFlags, windowModFlags);
+ }
+
+ @Override
+ public void show() {
+ switch (mWindowState) {
+ case WindowState.TOKEN_PENDING:
+ throw new IllegalStateException("Window token is not set yet.");
+ case WindowState.TOKEN_SET:
+ case WindowState.SHOWN_AT_LEAST_ONCE:
+ // Normal scenario. Nothing to worry about.
+ try {
+ super.show();
+ updateWindowState(WindowState.SHOWN_AT_LEAST_ONCE);
+ } catch (WindowManager.BadTokenException e) {
+ // Just ignore this exception. Since show() can be requested from other
+ // components such as the system and there could be multiple event queues before
+ // the request finally arrives here, the system may have already invalidated the
+ // window token attached to our window. In such a scenario, receiving
+ // BadTokenException here is an expected behavior. We just ignore it and update
+ // the state so that we do not touch this window later.
+ Log.i(TAG, "Probably the IME window token is already invalidated."
+ + " show() does nothing.");
+ updateWindowState(WindowState.REJECTED_AT_LEAST_ONCE);
+ }
+ return;
+ case WindowState.REJECTED_AT_LEAST_ONCE:
+ // Just ignore. In general we cannot completely avoid this kind of race condition.
+ Log.i(TAG, "Not trying to call show() because it was already rejected once.");
+ return;
+ case WindowState.DESTROYED:
+ // Just ignore. In general we cannot completely avoid this kind of race condition.
+ Log.i(TAG, "Ignoring show() because the window is already destroyed.");
+ return;
+ default:
+ throw new IllegalStateException("Unexpected state=" + mWindowState);
+ }
+ }
+
+ private void updateWindowState(@WindowState int newState) {
+ if (DEBUG) {
+ if (mWindowState != newState) {
+ Log.d(TAG, "WindowState: " + stateToString(mWindowState) + " -> "
+ + stateToString(newState) + " @ " + Debug.getCaller());
+ }
+ }
+ mWindowState = newState;
+ }
+
+ private static String stateToString(@WindowState int state) {
+ switch (state) {
+ case WindowState.TOKEN_PENDING:
+ return "TOKEN_PENDING";
+ case WindowState.TOKEN_SET:
+ return "TOKEN_SET";
+ case WindowState.SHOWN_AT_LEAST_ONCE:
+ return "SHOWN_AT_LEAST_ONCE";
+ case WindowState.REJECTED_AT_LEAST_ONCE:
+ return "REJECTED_AT_LEAST_ONCE";
+ case WindowState.DESTROYED:
+ return "DESTROYED";
+ default:
+ throw new IllegalStateException("Unknown state=" + state);
+ }
+ }
+}
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 5b9d69c..e5c9adb 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -743,6 +743,7 @@
* @see TelephonyManager#DATA_CONNECTING
* @see TelephonyManager#DATA_CONNECTED
* @see TelephonyManager#DATA_SUSPENDED
+ * @see TelephonyManager#DATA_HANDOVER_IN_PROGRESS
* @deprecated Use {@link TelephonyCallback.DataConnectionStateListener} instead.
*/
@Deprecated
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index 3028a6d..e8960b8 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -792,6 +792,7 @@
* @see TelephonyManager#DATA_CONNECTING
* @see TelephonyManager#DATA_CONNECTED
* @see TelephonyManager#DATA_SUSPENDED
+ * @see TelephonyManager#DATA_HANDOVER_IN_PROGRESS
*/
void onDataConnectionStateChanged(@TelephonyManager.DataState int state,
@Annotation.NetworkType int networkType);
@@ -1408,10 +1409,11 @@
*
* @param enabled {@code true} if data is enabled, otherwise disabled.
* @param reason Reason for data enabled/disabled.
- * See {@link TelephonyManager.DataEnabledReason}.
+ * See {@link TelephonyManager.DataEnabledChangedReason}.
*/
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
- void onDataEnabledChanged(boolean enabled, @TelephonyManager.DataEnabledReason int reason);
+ void onDataEnabledChanged(boolean enabled,
+ @TelephonyManager.DataEnabledChangedReason int reason);
}
/**
diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java
index dfe4119..4ebecb7 100644
--- a/core/java/android/text/InputType.java
+++ b/core/java/android/text/InputType.java
@@ -18,7 +18,7 @@
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.TextAttribute;
-import android.view.inputmethod.TextAttribute.TextAttributeBuilder;
+import android.view.inputmethod.TextAttribute.Builder;
import java.util.List;
@@ -200,7 +200,7 @@
* which has pronunciation characters and target characters. When the user is typing the
* pronunciation charactes, the IME could provide the possible target characters to the user.
* When this flag is set, the IME should insert the text conversion suggestions through
- * {@link TextAttributeBuilder#setTextConversionSuggestions(List)} and
+ * {@link Builder#setTextConversionSuggestions(List)} and
* the {@link TextAttribute} with initialized with the text conversion suggestions is provided
* by the IME to the application. To receive the additional information, the application needs
* to implement {@link InputConnection#setComposingText(CharSequence, int, TextAttribute)},
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index c1a5636..ae323226 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -585,8 +585,10 @@
* Returns a list of {@code Rect}s, each of which is the bounding rectangle for a non-functional
* area on the display.
*
- * There will be at most one non-functional area per short edge of the device, and none on
- * the long edges.
+ * There will be at most one non-functional area per edge of the device.
+ *
+ * <p>Note that there is no bounding rectangle for waterfall cutout since it just represents the
+ * curved areas of the display but not the non-functional areas.</p>
*
* @return a list of bounding {@code Rect}s, one for each display cutout area. No empty Rect is
* returned.
@@ -607,8 +609,10 @@
* functional area on the display. Ordinal value of BoundPosition is used as an index of
* the array.
*
- * There will be at most one non-functional area per short edge of the device, and none on
- * the long edges.
+ * There will be at most one non-functional area per edge of the device.
+ *
+ * <p>Note that there is no bounding rectangle for waterfall cutout since it just represents the
+ * curved areas of the display but not the non-functional areas.</p>
*
* @return an array of bounding {@code Rect}s, one for each display cutout area. This might
* contain ZERO_RECT, which means there is no cutout area at the position.
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index bf9de39..b1582cf 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -180,10 +180,7 @@
// If we have a new leash, make sure visibility is up-to-date, even though we
// didn't want to run an animation above.
- SurfaceControl newLeash = mSourceControl.getLeash();
- if (oldLeash == null || newLeash == null || !oldLeash.isSameSurface(newLeash)) {
- applyHiddenToControl();
- }
+ applyRequestedVisibilityToControl();
// Remove the surface that owned by last control when it lost.
if (!requestedVisible && !mIsAnimationPending && lastControl == null) {
@@ -388,18 +385,20 @@
}
}
- private void applyHiddenToControl() {
+ private void applyRequestedVisibilityToControl() {
if (mSourceControl == null || mSourceControl.getLeash() == null) {
return;
}
final Transaction t = mTransactionSupplier.get();
- if (DEBUG) Log.d(TAG, "applyHiddenToControl: " + mRequestedVisible);
+ if (DEBUG) Log.d(TAG, "applyRequestedVisibilityToControl: " + mRequestedVisible);
if (mRequestedVisible) {
t.show(mSourceControl.getLeash());
} else {
t.hide(mSourceControl.getLeash());
}
+ // Ensure the alpha value is aligned with the actual requested visibility.
+ t.setAlpha(mSourceControl.getLeash(), mRequestedVisible ? 1 : 0);
t.apply();
onPerceptible(mRequestedVisible);
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 3b52709..ab33fea 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -515,6 +515,15 @@
public static final int ENABLE_BACKPRESSURE = 0x00000100;
/**
+ * Buffers from this SurfaceControl should be considered display decorations.
+ *
+ * If the hardware has optimizations for display decorations (e.g. rounded corners, camera
+ * cutouts, etc), it should use them for this layer.
+ * @hide
+ */
+ public static final int DISPLAY_DECORATION = 0x00000200;
+
+ /**
* Surface creation flag: Creates a surface where color components are interpreted
* as "non pre-multiplied" by their alpha channel. Of course this flag is
* meaningless for surfaces without an alpha channel. By default
@@ -3266,6 +3275,21 @@
}
/**
+ * Sets whether the surface should take advantage of display decoration optimizations.
+ * @hide
+ */
+ public Transaction setDisplayDecoration(SurfaceControl sc, boolean displayDecoration) {
+ checkPreconditions(sc);
+ if (displayDecoration) {
+ nativeSetFlags(mNativeObject, sc.mNativeObject, DISPLAY_DECORATION,
+ DISPLAY_DECORATION);
+ } else {
+ nativeSetFlags(mNativeObject, sc.mNativeObject, 0, DISPLAY_DECORATION);
+ }
+ return this;
+ }
+
+ /**
* Indicates whether the surface must be considered opaque, even if its pixel format is
* set to translucent. This can be useful if an application needs full RGBA 8888 support
* for instance but will still draw every pixel opaque.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 3c0597c..d0a5835 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -138,20 +138,9 @@
private boolean mDisableBackgroundLayer = false;
/**
- * We use this lock in SOME cases when reading or writing SurfaceControl,
- * but use the following model so that the RenderThread can run locklessly
- * in the position up-date case.
- *
- * 1. UI Thread can read from mSurfaceControl (use in Transactions) without
- * holding the lock.
- * 2. UI Thread will hold the lock when writing to mSurfaceControl (calling release
- * or remove).
- * 3. Render thread will also hold the lock when writing to mSurfaceControl (e.g.
- * calling release from positionLost).
- * 3. RenderNode.PositionUpdateListener::positionChanged will only be called
- * when the UI thread is paused (blocked on the Render thread).
- * 4. positionChanged thus will not be required to hold the lock as the
- * UI thread is blocked, and the other writer is the RT itself.
+ * We use this lock to protect access to mSurfaceControl and
+ * SurfaceViewPositionUpdateListener#mPositionChangedTransaction. Both are accessed on the UI
+ * thread and the render thread.
*/
final Object mSurfaceControlLock = new Object();
final Rect mTmpRect = new Rect();
@@ -951,7 +940,9 @@
Transaction geometryTransaction) {
if (mPositionListener != null) {
mRenderNode.removePositionUpdateListener(mPositionListener);
- geometryTransaction = mPositionListener.getTransaction().merge(geometryTransaction);
+ synchronized (mSurfaceControlLock) {
+ geometryTransaction = mPositionListener.getTransaction().merge(geometryTransaction);
+ }
}
mPositionListener = new SurfaceViewPositionUpdateListener(surfaceWidth, surfaceHeight,
geometryTransaction);
@@ -1480,43 +1471,45 @@
if (mSurfaceControl == null) {
return;
}
- }
- if (mRTLastReportedPosition.left == left
- && mRTLastReportedPosition.top == top
- && mRTLastReportedPosition.right == right
- && mRTLastReportedPosition.bottom == bottom
- && mRTLastReportedSurfaceSize.x == mRtSurfaceWidth
- && mRTLastReportedSurfaceSize.y == mRtSurfaceHeight
- && !mPendingTransaction) {
- return;
- }
- try {
- if (DEBUG_POSITION) {
- Log.d(TAG, String.format(
- "%d updateSurfacePosition RenderWorker, frameNr = %d, "
- + "position = [%d, %d, %d, %d] surfaceSize = %dx%d",
- System.identityHashCode(SurfaceView.this), frameNumber,
- left, top, right, bottom, mRtSurfaceWidth, mRtSurfaceHeight));
+ if (mRTLastReportedPosition.left == left
+ && mRTLastReportedPosition.top == top
+ && mRTLastReportedPosition.right == right
+ && mRTLastReportedPosition.bottom == bottom
+ && mRTLastReportedSurfaceSize.x == mRtSurfaceWidth
+ && mRTLastReportedSurfaceSize.y == mRtSurfaceHeight
+ && !mPendingTransaction) {
+ return;
}
- mRTLastReportedPosition.set(left, top, right, bottom);
- mRTLastReportedSurfaceSize.set(mRtSurfaceWidth, mRtSurfaceHeight);
- onSetSurfacePositionAndScaleRT(mPositionChangedTransaction, mSurfaceControl,
- mRTLastReportedPosition.left /*positionLeft*/,
- mRTLastReportedPosition.top /*positionTop*/,
- mRTLastReportedPosition.width() / (float) mRtSurfaceWidth /*postScaleX*/,
- mRTLastReportedPosition.height() / (float) mRtSurfaceHeight /*postScaleY*/);
- if (mViewVisibility) {
- mPositionChangedTransaction.show(mSurfaceControl);
+ try {
+ if (DEBUG_POSITION) {
+ Log.d(TAG, String.format(
+ "%d updateSurfacePosition RenderWorker, frameNr = %d, "
+ + "position = [%d, %d, %d, %d] surfaceSize = %dx%d",
+ System.identityHashCode(SurfaceView.this), frameNumber,
+ left, top, right, bottom, mRtSurfaceWidth, mRtSurfaceHeight));
+ }
+ mRTLastReportedPosition.set(left, top, right, bottom);
+ mRTLastReportedSurfaceSize.set(mRtSurfaceWidth, mRtSurfaceHeight);
+ onSetSurfacePositionAndScaleRT(mPositionChangedTransaction, mSurfaceControl,
+ mRTLastReportedPosition.left /*positionLeft*/,
+ mRTLastReportedPosition.top /*positionTop*/,
+ mRTLastReportedPosition.width()
+ / (float) mRtSurfaceWidth /*postScaleX*/,
+ mRTLastReportedPosition.height()
+ / (float) mRtSurfaceHeight /*postScaleY*/);
+ if (mViewVisibility) {
+ mPositionChangedTransaction.show(mSurfaceControl);
+ }
+ final ViewRootImpl viewRoot = getViewRootImpl();
+ if (viewRoot != null) {
+ applyChildSurfaceTransaction_renderWorker(mPositionChangedTransaction,
+ viewRoot.mSurface, frameNumber);
+ }
+ applyOrMergeTransaction(mPositionChangedTransaction, frameNumber);
+ mPendingTransaction = false;
+ } catch (Exception ex) {
+ Log.e(TAG, "Exception from repositionChild", ex);
}
- final ViewRootImpl viewRoot = getViewRootImpl();
- if (viewRoot != null) {
- applyChildSurfaceTransaction_renderWorker(mPositionChangedTransaction,
- viewRoot.mSurface, frameNumber);
- }
- applyOrMergeTransaction(mPositionChangedTransaction, frameNumber);
- mPendingTransaction = false;
- } catch (Exception ex) {
- Log.e(TAG, "Exception from repositionChild", ex);
}
}
@@ -1539,18 +1532,18 @@
}
mRTLastReportedPosition.setEmpty();
mRTLastReportedSurfaceSize.set(-1, -1);
- if (mPendingTransaction) {
- Log.w(TAG, System.identityHashCode(SurfaceView.this)
- + "Pending transaction cleared.");
- mPositionChangedTransaction.clear();
- mPendingTransaction = false;
- }
/**
* positionLost can be called while UI thread is un-paused so we
* need to hold the lock here.
*/
synchronized (mSurfaceControlLock) {
+ if (mPendingTransaction) {
+ Log.w(TAG, System.identityHashCode(SurfaceView.this)
+ + "Pending transaction cleared.");
+ mPositionChangedTransaction.clear();
+ mPendingTransaction = false;
+ }
if (mSurfaceControl == null) {
return;
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 00754af..1566f9e 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -478,6 +478,19 @@
}
/**
+ * Remove a frame drawing callback that was added via
+ * {@link #registerRtFrameCallback(FrameDrawingCallback)}
+ *
+ * @param callback The callback to unregister.
+ */
+ void unregisterRtFrameCallback(@NonNull FrameDrawingCallback callback) {
+ if (mNextRtFrameCallbacks == null) {
+ return;
+ }
+ mNextRtFrameCallbacks.remove(callback);
+ }
+
+ /**
* Destroys all hardware rendering resources associated with the specified
* view hierarchy.
*
@@ -679,9 +692,31 @@
if (mNextRtFrameCallbacks != null) {
final ArrayList<FrameDrawingCallback> frameCallbacks = mNextRtFrameCallbacks;
mNextRtFrameCallbacks = null;
- setFrameCallback(frame -> {
- for (int i = 0; i < frameCallbacks.size(); ++i) {
- frameCallbacks.get(i).onFrameDraw(frame);
+ setFrameCallback(new FrameDrawingCallback() {
+ @Override
+ public void onFrameDraw(long frame) {
+ }
+
+ @Override
+ public FrameCommitCallback onFrameDraw(int syncResult, long frame) {
+ ArrayList<FrameCommitCallback> frameCommitCallbacks = new ArrayList<>();
+ for (int i = 0; i < frameCallbacks.size(); ++i) {
+ FrameCommitCallback frameCommitCallback = frameCallbacks.get(i)
+ .onFrameDraw(syncResult, frame);
+ if (frameCommitCallback != null) {
+ frameCommitCallbacks.add(frameCommitCallback);
+ }
+ }
+
+ if (frameCommitCallbacks.isEmpty()) {
+ return null;
+ }
+
+ return didProduceBuffer -> {
+ for (int i = 0; i < frameCommitCallbacks.size(); ++i) {
+ frameCommitCallbacks.get(i).onFrameCommit(didProduceBuffer);
+ }
+ };
}
});
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index c371202..748e551 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -16,6 +16,8 @@
package android.view;
+import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED;
+import static android.graphics.HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND;
import static android.os.IInputConstants.INVALID_INPUT_EVENT_ID;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
@@ -491,6 +493,9 @@
protected final ViewFrameInfo mViewFrameInfo = new ViewFrameInfo();
private final InputEventAssigner mInputEventAssigner = new InputEventAssigner();
+ // Whether to draw this surface as DISPLAY_DECORATION.
+ boolean mDisplayDecorationCached = false;
+
/**
* Update the Choreographer's FrameInfo object with the timing information for the current
* ViewRootImpl instance. Erase the data in the current ViewFrameInfo to prepare for the next
@@ -1141,7 +1146,7 @@
final Rect displayCutoutSafe = mTempRect;
state.getDisplayCutoutSafe(displayCutoutSafe);
final WindowConfiguration winConfig = getConfiguration().windowConfiguration;
- mWindowLayout.computeWindowFrames(mWindowAttributes, state,
+ mWindowLayout.computeFrames(mWindowAttributes, state,
displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH,
mInsetsController.getRequestedVisibilities(),
@@ -1392,11 +1397,20 @@
*/
public void registerRtFrameCallback(@NonNull FrameDrawingCallback callback) {
if (mAttachInfo.mThreadedRenderer != null) {
- mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frame -> {
- try {
- callback.onFrameDraw(frame);
- } catch (Exception e) {
- Log.e(TAG, "Exception while executing onFrameDraw", e);
+ mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() {
+ @Override
+ public void onFrameDraw(long frame) {
+ }
+
+ @Override
+ public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult,
+ long frame) {
+ try {
+ return callback.onFrameDraw(syncResult, frame);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while executing onFrameDraw", e);
+ }
+ return null;
}
});
}
@@ -1959,26 +1973,29 @@
return mBoundsLayer;
}
- Surface getOrCreateBLASTSurface() {
+ void updateBlastSurfaceIfNeeded() {
if (!mSurfaceControl.isValid()) {
- return null;
+ return;
}
- Surface ret = null;
- if (mBlastBufferQueue == null) {
- mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
- mSurfaceSize.x, mSurfaceSize.y,
- mWindowAttributes.format);
- // We only return the Surface the first time, as otherwise
- // it hasn't changed and there is no need to update.
- ret = mBlastBufferQueue.createSurface();
- } else {
+ if (mBlastBufferQueue != null && mBlastBufferQueue.isSameSurfaceControl(mSurfaceControl)) {
mBlastBufferQueue.update(mSurfaceControl,
mSurfaceSize.x, mSurfaceSize.y,
mWindowAttributes.format);
+ return;
}
- return ret;
+ // If the SurfaceControl has been updated, destroy and recreate the BBQ to reset the BQ and
+ // BBQ states.
+ if (mBlastBufferQueue != null) {
+ mBlastBufferQueue.destroy();
+ }
+ mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
+ mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);
+ Surface blastSurface = mBlastBufferQueue.createSurface();
+ // Only call transferFrom if the surface has changed to prevent inc the generation ID and
+ // causing EGL resources to be recreated.
+ mSurface.transferFrom(blastSurface);
}
private void setBoundsLayerCrop(Transaction t) {
@@ -2842,6 +2859,12 @@
if (mSurfaceControl.isValid()) {
updateOpacity(mWindowAttributes, dragResizing,
surfaceControlChanged /*forceUpdate */);
+ // No need to updateDisplayDecoration if it's a new SurfaceControl and
+ // mDisplayDecorationCached is false, since that's the default for a new
+ // SurfaceControl.
+ if (surfaceControlChanged && mDisplayDecorationCached) {
+ updateDisplayDecoration();
+ }
}
if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
@@ -4020,61 +4043,6 @@
return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled();
}
- private boolean addFrameCompleteCallbackIfNeeded(boolean useBlastSync,
- boolean reportNextDraw) {
- if (!isHardwareEnabled()) {
- return false;
- }
-
- if (!useBlastSync && !reportNextDraw) {
- return false;
- }
-
- if (DEBUG_BLAST) {
- Log.d(mTag, "Creating frameCompleteCallback");
- }
-
- final Consumer<SurfaceControl.Transaction> blastSyncConsumer = mBLASTDrawConsumer;
- mBLASTDrawConsumer = null;
-
- mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(() -> {
- long frameNr = mBlastBufferQueue.getLastAcquiredFrameNum();
- if (DEBUG_BLAST) {
- Log.d(mTag, "Received frameCompleteCallback "
- + " lastAcquiredFrameNum=" + frameNr
- + " lastAttemptedDrawFrameNum=" + mRtLastAttemptedDrawFrameNum);
- }
-
- boolean frameWasNotDrawn = frameNr != mRtLastAttemptedDrawFrameNum;
- // If frame wasn't drawn, clear out the next transaction so it doesn't affect the next
- // draw attempt. The next transaction and transaction complete callback were only set
- // for the current draw attempt.
- if (frameWasNotDrawn) {
- mBlastBufferQueue.setSyncTransaction(null);
- // Apply the transactions that were sent to mergeWithNextTransaction since the
- // frame didn't draw on this vsync. It's possible the frame will draw later, but
- // it's better to not be sync than to block on a frame that may never come.
- mBlastBufferQueue.applyPendingTransactions(mRtLastAttemptedDrawFrameNum);
- }
-
- Transaction tmpTransaction = new Transaction();
- tmpTransaction.merge(mRtBLASTSyncTransaction);
- mHandler.postAtFrontOfQueue(() -> {
- if (useBlastSync) {
- mSurfaceChangedTransaction.merge(tmpTransaction);
- if (blastSyncConsumer != null) {
- blastSyncConsumer.accept(mSurfaceChangedTransaction);
- }
- }
-
- if (reportNextDraw) {
- pendingDrawFinished();
- }
- });
- });
- return true;
- }
-
private void addFrameCommitCallbackIfNeeded() {
if (!isHardwareEnabled()) {
return;
@@ -4105,51 +4073,131 @@
});
}
- private void addFrameCallbackIfNeeded(boolean useBlastSync) {
+ private HardwareRenderer.FrameCommitCallback createFrameCommitCallbackForSync(
+ boolean useBlastSync, boolean reportNextDraw, Consumer<Transaction> blastSyncConsumer) {
+ return didProduceBuffer -> {
+ if (DEBUG_BLAST) {
+ Log.d(mTag, "Received frameCommittedCallback "
+ + " lastAttemptedDrawFrameNum=" + mRtLastAttemptedDrawFrameNum
+ + " didProduceBuffer=" + didProduceBuffer);
+ }
+
+ // If frame wasn't drawn, clear out the next transaction so it doesn't affect the next
+ // draw attempt. The next transaction and transaction complete callback were only set
+ // for the current draw attempt.
+ if (!didProduceBuffer) {
+ mBlastBufferQueue.setSyncTransaction(null);
+ // Apply the transactions that were sent to mergeWithNextTransaction since the
+ // frame didn't draw on this vsync. It's possible the frame will draw later, but
+ // it's better to not be sync than to block on a frame that may never come.
+ mBlastBufferQueue.applyPendingTransactions(mRtLastAttemptedDrawFrameNum);
+ }
+
+ Transaction tmpTransaction = new Transaction();
+ tmpTransaction.merge(mRtBLASTSyncTransaction);
+ // Post at front of queue so the buffer can be processed immediately and allow RT
+ // to continue processing new buffers. If RT tries to process buffers before the sync
+ // buffer is applied, the new buffers will not get acquired and could result in a
+ // deadlock. UI thread would wait on RT, but RT would be blocked waiting for a free
+ // buffer.
+ mHandler.postAtFrontOfQueue(() -> {
+ if (useBlastSync) {
+ mSurfaceChangedTransaction.merge(tmpTransaction);
+ if (blastSyncConsumer != null) {
+ blastSyncConsumer.accept(mSurfaceChangedTransaction);
+ }
+ }
+
+ if (reportNextDraw) {
+ pendingDrawFinished();
+ }
+ });
+ };
+ }
+
+ @Nullable
+ private FrameDrawingCallback createFrameDrawingCallbackIfNeeded(boolean useBlastSync,
+ boolean reportNextDraw) {
+ if (!isHardwareEnabled()) {
+ return null;
+ }
final boolean hasBlurUpdates = mBlurRegionAggregator.hasUpdates();
final boolean needsCallbackForBlur = hasBlurUpdates || mBlurRegionAggregator.hasRegions();
- if (!useBlastSync && !needsCallbackForBlur) {
- return;
+ if (!useBlastSync && !needsCallbackForBlur && !reportNextDraw) {
+ return null;
}
+ final Consumer<SurfaceControl.Transaction> blastSyncConsumer = mBLASTDrawConsumer;
+ mBLASTDrawConsumer = null;
+
if (DEBUG_BLAST) {
Log.d(mTag, "Creating frameDrawingCallback"
+ " nextDrawUseBlastSync=" + useBlastSync
- + " hasBlurUpdates=" + hasBlurUpdates);
+ + " reportNextDraw=" + reportNextDraw
+ + " hasBlurUpdates=" + hasBlurUpdates
+ + " hasBlastSyncConsumer=" + (blastSyncConsumer != null));
}
+
final BackgroundBlurDrawable.BlurRegion[] blurRegionsForFrame =
needsCallbackForBlur ? mBlurRegionAggregator.getBlurRegionsCopyForRT() : null;
// The callback will run on the render thread.
- HardwareRenderer.FrameDrawingCallback frameDrawingCallback = frame -> {
- if (DEBUG_BLAST) {
- Log.d(mTag, "Received frameDrawingCallback frameNum=" + frame + "."
- + " Creating transactionCompleteCallback=" + useBlastSync);
+ return new FrameDrawingCallback() {
+ @Override
+ public void onFrameDraw(long frame) {
}
- mRtLastAttemptedDrawFrameNum = frame;
+ @Override
+ public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) {
+ if (DEBUG_BLAST) {
+ Log.d(mTag,
+ "Received frameDrawingCallback syncResult=" + syncResult + " frameNum="
+ + frame + ".");
+ }
- if (needsCallbackForBlur) {
- mBlurRegionAggregator
- .dispatchBlurTransactionIfNeeded(frame, blurRegionsForFrame, hasBlurUpdates);
- }
+ mRtLastAttemptedDrawFrameNum = frame;
- if (mBlastBufferQueue == null) {
- return;
- }
+ if (needsCallbackForBlur) {
+ mBlurRegionAggregator.dispatchBlurTransactionIfNeeded(frame,
+ blurRegionsForFrame, hasBlurUpdates);
+ }
- if (useBlastSync) {
- // Frame callbacks will always occur after submitting draw requests and before
- // the draw actually occurs. This will ensure that we set the next transaction
- // for the frame that's about to get drawn and not on a previous frame that.
+ if (mBlastBufferQueue == null) {
+ return null;
+ }
- // We don't need to synchronize mRtBLASTSyncTransaction here since it's not
- // being modified and only sent to BlastBufferQueue.
- mBlastBufferQueue.setSyncTransaction(mRtBLASTSyncTransaction);
+ if (!useBlastSync && !reportNextDraw) {
+ return null;
+ }
+
+ // If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or
+ // SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up
+ // any blast sync or commit callback, and the code should directly call
+ // pendingDrawFinished.
+ if ((syncResult
+ & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) {
+ if (reportNextDraw) {
+ mHandler.postAtFrontOfQueue(() -> pendingDrawFinished());
+ }
+ return null;
+ }
+
+ if (DEBUG_BLAST) {
+ Log.d(mTag, "Setting up sync and frameCommitCallback");
+ }
+
+ if (useBlastSync) {
+ // Frame callbacks will always occur after submitting draw requests and before
+ // the draw actually occurs. This will ensure that we set the next transaction
+ // for the frame that's about to get drawn and not on a previous frame.
+ mBlastBufferQueue.setSyncTransaction(mRtBLASTSyncTransaction);
+ }
+
+ return createFrameCommitCallbackForSync(useBlastSync, reportNextDraw,
+ blastSyncConsumer);
}
};
- registerRtFrameCallback(frameDrawingCallback);
}
private void performDraw(boolean useBlastSync) {
@@ -4165,15 +4213,20 @@
mIsDrawing = true;
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
- addFrameCallbackIfNeeded(useBlastSync);
+ FrameDrawingCallback frameDrawingCallback = createFrameDrawingCallbackIfNeeded(useBlastSync,
+ mReportNextDraw);
+ if (frameDrawingCallback != null) {
+ mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frameDrawingCallback);
+ }
addFrameCommitCallbackIfNeeded();
- boolean usingAsyncReport = addFrameCompleteCallbackIfNeeded(useBlastSync, mReportNextDraw);
+ boolean usingAsyncReport = isHardwareEnabled() && (useBlastSync || mReportNextDraw);
try {
boolean canUseAsync = draw(fullRedrawNeeded);
if (usingAsyncReport && !canUseAsync) {
- mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(null);
+ mAttachInfo.mThreadedRenderer.setFrameCallback(null);
usingAsyncReport = false;
+ mAttachInfo.mThreadedRenderer.unregisterRtFrameCallback(frameDrawingCallback);
}
} finally {
mIsDrawing = false;
@@ -7843,13 +7896,7 @@
if (!useBLAST()) {
mSurface.copyFrom(mSurfaceControl);
} else {
- final Surface blastSurface = getOrCreateBLASTSurface();
- // If blastSurface == null that means it hasn't changed since the last time we
- // called. In this situation, avoid calling transferFrom as we would then
- // inc the generation ID and cause EGL resources to be recreated.
- if (blastSurface != null) {
- mSurface.transferFrom(blastSurface);
- }
+ updateBlastSurfaceIfNeeded();
}
if (mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl);
@@ -10399,6 +10446,23 @@
}
/**
+ * @hide
+ */
+ public void setDisplayDecoration(boolean displayDecoration) {
+ if (displayDecoration == mDisplayDecorationCached) return;
+
+ mDisplayDecorationCached = displayDecoration;
+
+ if (mSurfaceControl.isValid()) {
+ updateDisplayDecoration();
+ }
+ }
+
+ private void updateDisplayDecoration() {
+ mTransaction.setDisplayDecoration(mSurfaceControl, mDisplayDecorationCached).apply();
+ }
+
+ /**
* Sends a list of blur regions to SurfaceFlinger, tagged with a frame.
*
* @param regionCopy List of regions
diff --git a/core/java/android/view/WindowLayout.java b/core/java/android/view/WindowLayout.java
index 7dfc95e..e5c7d6d 100644
--- a/core/java/android/view/WindowLayout.java
+++ b/core/java/android/view/WindowLayout.java
@@ -52,7 +52,7 @@
private final Rect mTempDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
private final Rect mTempRect = new Rect();
- public boolean computeWindowFrames(WindowManager.LayoutParams attrs, InsetsState state,
+ public boolean computeFrames(WindowManager.LayoutParams attrs, InsetsState state,
Rect displayCutoutSafe, Rect windowBounds, @WindowingMode int windowingMode,
int requestedWidth, int requestedHeight, InsetsVisibilities requestedVisibilities,
Rect attachedWindowFrame, float compatScale, Rect outDisplayFrame, Rect outParentFrame,
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f69bb6a..cd9f3eb6 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -105,6 +105,7 @@
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.IInputConstants;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -120,6 +121,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -2755,7 +2757,7 @@
*
* <p>Applications that target {@link android.os.Build.VERSION_CODES#P} and later, this flag
* is ignored unless there is a focused view that returns {@code true} from
- * {@link View#isInEditMode()} when the window is focused.</p>
+ * {@link View#onCheckIsTextEditor()} when the window is focused.</p>
*/
public static final int SOFT_INPUT_STATE_VISIBLE = 4;
@@ -2765,7 +2767,7 @@
*
* <p>Applications that target {@link android.os.Build.VERSION_CODES#P} and later, this flag
* is ignored unless there is a focused view that returns {@code true} from
- * {@link View#isInEditMode()} when the window is focused.</p>
+ * {@link View#onCheckIsTextEditor()} when the window is focused.</p>
*/
public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;
@@ -3325,21 +3327,13 @@
public static final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 3;
/**
- * When this window has focus, disable touch pad pointer gesture processing.
- * The window will receive raw position updates from the touch pad instead
- * of pointer movements and synthetic touch events.
- *
- * @hide
- */
- public static final int INPUT_FEATURE_DISABLE_POINTER_GESTURES = 0x00000001;
-
- /**
* Does not construct an input channel for this window. The channel will therefore
* be incapable of receiving input.
*
* @hide
*/
- public static final int INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002;
+ public static final int INPUT_FEATURE_NO_INPUT_CHANNEL =
+ IInputConstants.InputFeature.NO_INPUT_CHANNEL;
/**
* When this window has focus, does not call user activity for all input events so
@@ -3352,7 +3346,35 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004;
+ public static final int INPUT_FEATURE_DISABLE_USER_ACTIVITY =
+ IInputConstants.InputFeature.DISABLE_USER_ACTIVITY;
+
+ /**
+ * An input spy window. This window will receive all pointer events within its touchable
+ * area, but will will not stop events from being sent to other windows below it in z-order.
+ * An input event will be dispatched to all spy windows above the top non-spy window at the
+ * event's coordinates.
+ * @hide
+ */
+ public static final int INPUT_FEATURE_SPY =
+ IInputConstants.InputFeature.SPY;
+
+ /**
+ * When used with the window flag {@link #FLAG_NOT_TOUCHABLE}, this window will continue
+ * to receive events from a stylus device within its touchable region. All other pointer
+ * events, such as from a mouse or touchscreen, will be dispatched to the windows behind it.
+ *
+ * This input feature has no effect when the window flag {@link #FLAG_NOT_TOUCHABLE} is
+ * not set.
+ *
+ * The window must be a trusted overlay to use this input feature.
+ *
+ * @see #FLAG_NOT_TOUCHABLE
+ *
+ * @hide
+ */
+ public static final int INPUT_FEATURE_INTERCEPTS_STYLUS =
+ IInputConstants.InputFeature.INTERCEPTS_STYLUS;
/**
* An internal annotation for flags that can be specified to {@link #inputFeatures}.
@@ -3361,18 +3383,20 @@
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "INPUT_FEATURE_" }, value = {
- INPUT_FEATURE_DISABLE_POINTER_GESTURES,
INPUT_FEATURE_NO_INPUT_CHANNEL,
INPUT_FEATURE_DISABLE_USER_ACTIVITY,
+ INPUT_FEATURE_SPY,
+ INPUT_FEATURE_INTERCEPTS_STYLUS,
})
public @interface InputFeatureFlags {}
/**
* Control special features of the input subsystem.
*
- * @see #INPUT_FEATURE_DISABLE_POINTER_GESTURES
* @see #INPUT_FEATURE_NO_INPUT_CHANNEL
* @see #INPUT_FEATURE_DISABLE_USER_ACTIVITY
+ * @see #INPUT_FEATURE_SPY
+ * @see #INPUT_FEATURE_INTERCEPTS_STYLUS
* @hide
*/
@InputFeatureFlags
@@ -4476,7 +4500,7 @@
sb.append(hasSystemUiListeners);
}
if (inputFeatures != 0) {
- sb.append(" if=").append(inputFeatureToString(inputFeatures));
+ sb.append(" if=").append(inputFeaturesToString(inputFeatures));
}
if (userActivityTimeout >= 0) {
sb.append(" userActivityTimeout=").append(userActivityTimeout);
@@ -4778,17 +4802,28 @@
}
}
- private static String inputFeatureToString(int inputFeature) {
- switch (inputFeature) {
- case INPUT_FEATURE_DISABLE_POINTER_GESTURES:
- return "DISABLE_POINTER_GESTURES";
- case INPUT_FEATURE_NO_INPUT_CHANNEL:
- return "NO_INPUT_CHANNEL";
- case INPUT_FEATURE_DISABLE_USER_ACTIVITY:
- return "DISABLE_USER_ACTIVITY";
- default:
- return Integer.toString(inputFeature);
+ private static String inputFeaturesToString(int inputFeatures) {
+ final List<String> features = new ArrayList<>();
+ if ((inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) != 0) {
+ inputFeatures &= ~INPUT_FEATURE_NO_INPUT_CHANNEL;
+ features.add("INPUT_FEATURE_NO_INPUT_CHANNEL");
}
+ if ((inputFeatures & INPUT_FEATURE_DISABLE_USER_ACTIVITY) != 0) {
+ inputFeatures &= ~INPUT_FEATURE_DISABLE_USER_ACTIVITY;
+ features.add("INPUT_FEATURE_DISABLE_USER_ACTIVITY");
+ }
+ if ((inputFeatures & INPUT_FEATURE_SPY) != 0) {
+ inputFeatures &= ~INPUT_FEATURE_SPY;
+ features.add("INPUT_FEATURE_SPY");
+ }
+ if ((inputFeatures & INPUT_FEATURE_INTERCEPTS_STYLUS) != 0) {
+ inputFeatures &= ~INPUT_FEATURE_INTERCEPTS_STYLUS;
+ features.add("INPUT_FEATURE_INTERCEPTS_STYLUS");
+ }
+ if (inputFeatures != 0) {
+ features.add(Integer.toHexString(inputFeatures));
+ }
+ return String.join(" | ", features);
}
/**
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 83712b4..a427ab8 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -24,7 +24,6 @@
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
-import android.util.Pools.SynchronizedPool;
import com.android.internal.util.BitUtils;
@@ -806,10 +805,6 @@
*/
public static final int TYPES_ALL_MASK = 0xFFFFFFFF;
- private static final int MAX_POOL_SIZE = 10;
- private static final SynchronizedPool<AccessibilityEvent> sPool =
- new SynchronizedPool<>(MAX_POOL_SIZE);
-
@UnsupportedAppUsage
private @EventType int mEventType;
private CharSequence mPackageName;
@@ -1170,7 +1165,7 @@
*/
public static AccessibilityEvent obtainWindowsChangedEvent(
int windowId, int windowChangeTypes) {
- final AccessibilityEvent event = AccessibilityEvent.obtain(TYPE_WINDOWS_CHANGED);
+ final AccessibilityEvent event = new AccessibilityEvent(TYPE_WINDOWS_CHANGED);
event.setWindowId(windowId);
event.setWindowChanges(windowChangeTypes);
event.setImportantForAccessibility(true);
@@ -1178,69 +1173,58 @@
}
/**
- * Returns a cached instance if such is available or a new one is
- * instantiated with its type property set.
+ * Instantiates a new AccessibilityEvent instance with its type property set.
*
- * <p>In most situations object pooling is not beneficial. Create a new instance using the
- * constructor {@link #AccessibilityEvent(int)} instead.
- *
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
+ * constructor {@link #AccessibilityEvent()} instead.
* @param eventType The event type.
* @return An instance.
*/
+ @Deprecated
public static AccessibilityEvent obtain(int eventType) {
- AccessibilityEvent event = AccessibilityEvent.obtain();
+ AccessibilityEvent event = new AccessibilityEvent();
event.setEventType(eventType);
return event;
}
/**
- * Returns a cached instance if such is available or a new one is
- * created. The returned instance is initialized from the given
+ * Instantiates a new AccessibilityEvent instance.
+ * The returned instance is initialized from the given
* <code>event</code>.
*
- * <p>In most situations object pooling is not beneficial. Create a new instance using the
- * constructor {@link #AccessibilityEvent(AccessibilityEvent)} instead.
- *
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
+ * constructor {@link #AccessibilityEvent()} instead.
* @param event The other event.
* @return An instance.
*/
+ @Deprecated
public static AccessibilityEvent obtain(AccessibilityEvent event) {
- AccessibilityEvent eventClone = AccessibilityEvent.obtain();
+ AccessibilityEvent eventClone = new AccessibilityEvent();
eventClone.init(event);
return eventClone;
}
/**
- * Returns a cached instance if such is available or a new one is
- * instantiated.
+ * Instantiates a new AccessibilityEvent instance.
*
- * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
* constructor {@link #AccessibilityEvent()} instead.
- *
* @return An instance.
*/
+ @Deprecated
public static AccessibilityEvent obtain() {
- AccessibilityEvent event = sPool.acquire();
- if (event == null) event = new AccessibilityEvent();
- if (DEBUG_ORIGIN) event.originStackTrace = Thread.currentThread().getStackTrace();
- return event;
+ return new AccessibilityEvent();
}
/**
- * Recycles an instance back to be reused.
- * <p>
- * <b>Note: You must not touch the object after calling this function.</b>
- * </p>
+ * Previously would recycle an instance back to be reused.
*
- * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
- *
- * @throws IllegalStateException If the event is already recycled.
+ * @deprecated Object pooling has been discontinued. Calling this function now will have
+ * no effect.
*/
@Override
- public void recycle() {
- clear();
- sPool.release(this);
- }
+ @Deprecated
+ public void recycle() {}
/**
* Clears the state of this instance.
@@ -1260,7 +1244,6 @@
if (mRecords != null) {
while (!mRecords.isEmpty()) {
AccessibilityRecord record = mRecords.remove(0);
- record.recycle();
}
}
if (DEBUG_ORIGIN) originStackTrace = null;
@@ -1288,7 +1271,7 @@
if (recordCount > 0) {
mRecords = new ArrayList<>(recordCount);
for (int i = 0; i < recordCount; i++) {
- AccessibilityRecord record = AccessibilityRecord.obtain();
+ AccessibilityRecord record = new AccessibilityRecord();
readAccessibilityRecordFromParcel(record, parcel);
record.mConnectionId = mConnectionId;
mRecords.add(record);
@@ -1527,7 +1510,7 @@
public static final @android.annotation.NonNull Parcelable.Creator<AccessibilityEvent> CREATOR =
new Parcelable.Creator<AccessibilityEvent>() {
public AccessibilityEvent createFromParcel(Parcel parcel) {
- AccessibilityEvent event = AccessibilityEvent.obtain();
+ AccessibilityEvent event = new AccessibilityEvent();
event.initFromParcel(parcel);
return event;
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 9511958..db7c663 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -50,7 +50,6 @@
import android.util.ArraySet;
import android.util.Log;
import android.util.LongArray;
-import android.util.Pools.SynchronizedPool;
import android.util.Size;
import android.util.TypedValue;
import android.view.SurfaceView;
@@ -68,7 +67,6 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* This class represents a node of the window content as well as actions that
@@ -723,9 +721,6 @@
*/
private static final int VIRTUAL_DESCENDANT_ID_SHIFT = 32;
- // TODO(b/129300068): Remove sNumInstancesInUse.
- private static AtomicInteger sNumInstancesInUse;
-
/**
* Gets the accessibility view id which identifies a View in the view three.
*
@@ -769,11 +764,6 @@
return (((long) virtualDescendantId) << VIRTUAL_DESCENDANT_ID_SHIFT) | accessibilityViewId;
}
- // Housekeeping.
- private static final int MAX_POOL_SIZE = 50;
- private static final SynchronizedPool<AccessibilityNodeInfo> sPool =
- new SynchronizedPool<>(MAX_POOL_SIZE);
-
private static final AccessibilityNodeInfo DEFAULT = new AccessibilityNodeInfo();
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -869,7 +859,7 @@
* @param info The other info.
*/
public AccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) {
- init(info, false /* usePoolingInfo */);
+ init(info);
}
/**
@@ -1009,13 +999,7 @@
if (refreshedInfo == null) {
return false;
}
- // Hard-to-reproduce bugs seem to be due to some tools recycling a node on another
- // thread. If that happens, the init will re-seal the node, which then is in a bad state
- // when it is obtained. Enforce sealing again before we init to fail when a node has been
- // recycled during a refresh to catch such errors earlier.
- enforceSealed();
- init(refreshedInfo, true /* usePoolingInfo */);
- refreshedInfo.recycle();
+ init(refreshedInfo);
return true;
}
@@ -3599,25 +3583,23 @@
* Returns a cached instance if such is available otherwise a new one
* and sets the source.
*
- * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
* constructor {@link #AccessibilityNodeInfo(View)} instead.
- *
* @param source The source view.
* @return An instance.
*
* @see #setSource(View)
*/
+ @Deprecated
public static AccessibilityNodeInfo obtain(View source) {
- AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
- info.setSource(source);
- return info;
+ return new AccessibilityNodeInfo(source);
}
/**
* Returns a cached instance if such is available otherwise a new one
* and sets the source.
*
- * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
* constructor {@link #AccessibilityNodeInfo(View, int)} instead.
*
* @param root The root of the virtual subtree.
@@ -3626,71 +3608,45 @@
*
* @see #setSource(View, int)
*/
+ @Deprecated
public static AccessibilityNodeInfo obtain(View root, int virtualDescendantId) {
- AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
- info.setSource(root, virtualDescendantId);
- return info;
+ return new AccessibilityNodeInfo(root, virtualDescendantId);
}
/**
- * Returns a cached instance if such is available otherwise a new one.
+ * Instantiates a new AccessibilityNodeInfo.
*
- * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
* constructor {@link #AccessibilityNodeInfo()} instead.
- *
* @return An instance.
*/
+ @Deprecated
public static AccessibilityNodeInfo obtain() {
- AccessibilityNodeInfo info = sPool.acquire();
- if (sNumInstancesInUse != null) {
- sNumInstancesInUse.incrementAndGet();
- }
- return (info != null) ? info : new AccessibilityNodeInfo();
+ return new AccessibilityNodeInfo();
}
/**
- * Returns a cached instance if such is available or a new one is
- * create. The returned instance is initialized from the given
+ * Instantiates a new AccessibilityNodeInfo initialized from the given
* <code>info</code>.
*
- * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
* constructor {@link #AccessibilityNodeInfo(AccessibilityNodeInfo)} instead.
- *
* @param info The other info.
* @return An instance.
*/
+ @Deprecated
public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) {
- AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain();
- infoClone.init(info, true /* usePoolingInfo */);
- return infoClone;
+ return new AccessibilityNodeInfo(info);
}
/**
- * Return an instance back to be reused.
- * <p>
- * <strong>Note:</strong> You must not touch the object after calling this function.
+ * Would previously return an instance back to be reused.
*
- * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
- *
- * @throws IllegalStateException If the info is already recycled.
+ * @deprecated Object pooling has been discontinued. Calling this function now will have
+ * no effect.
*/
- public void recycle() {
- clear();
- sPool.release(this);
- if (sNumInstancesInUse != null) {
- sNumInstancesInUse.decrementAndGet();
- }
- }
-
- /**
- * Specify a counter that will be incremented on obtain() and decremented on recycle()
- *
- * @hide
- */
- @TestApi
- public static void setNumInstancesInUseCounter(AtomicInteger counter) {
- sNumInstancesInUse = counter;
- }
+ @Deprecated
+ public void recycle() {}
/**
* {@inheritDoc}
@@ -3704,7 +3660,6 @@
writeToParcelNoRecycle(parcel, flags);
// Since instances of this class are fetched via synchronous i.e. blocking
// calls in IPCs we always recycle as soon as the instance is marshaled.
- recycle();
}
/** @hide */
@@ -4000,9 +3955,8 @@
* Initializes this instance from another one.
*
* @param other The other instance.
- * @param usePoolingInfos whether using pooled object internally or not
*/
- private void init(AccessibilityNodeInfo other, boolean usePoolingInfos) {
+ private void init(AccessibilityNodeInfo other) {
mSealed = other.mSealed;
mSourceNodeId = other.mSourceNodeId;
mParentNodeId = other.mParentNodeId;
@@ -4062,11 +4016,7 @@
mExtras = other.mExtras != null ? new Bundle(other.mExtras) : null;
- if (usePoolingInfos) {
- initPoolingInfos(other);
- } else {
- initCopyInfos(other);
- }
+ initCopyInfos(other);
final TouchDelegateInfo otherInfo = other.mTouchDelegateInfo;
mTouchDelegateInfo = (otherInfo != null)
@@ -4077,21 +4027,6 @@
mLeashedParentNodeId = other.mLeashedParentNodeId;
}
- private void initPoolingInfos(AccessibilityNodeInfo other) {
- if (mRangeInfo != null) mRangeInfo.recycle();
- mRangeInfo = (other.mRangeInfo != null)
- ? RangeInfo.obtain(other.mRangeInfo) : null;
- if (mCollectionInfo != null) mCollectionInfo.recycle();
- mCollectionInfo = (other.mCollectionInfo != null)
- ? CollectionInfo.obtain(other.mCollectionInfo) : null;
- if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
- mCollectionItemInfo = (other.mCollectionItemInfo != null)
- ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
- if (mExtraRenderingInfo != null) mExtraRenderingInfo.recycle();
- mExtraRenderingInfo = (other.mExtraRenderingInfo != null)
- ? ExtraRenderingInfo.obtain(other.mExtraRenderingInfo) : null;
- }
-
private void initCopyInfos(AccessibilityNodeInfo other) {
RangeInfo ri = other.mRangeInfo;
mRangeInfo = (ri == null) ? null
@@ -4205,27 +4140,24 @@
? parcel.readBundle()
: null;
- if (mRangeInfo != null) mRangeInfo.recycle();
mRangeInfo = isBitSet(nonDefaultFields, fieldIndex++)
- ? RangeInfo.obtain(
+ ? new RangeInfo(
parcel.readInt(),
parcel.readFloat(),
parcel.readFloat(),
parcel.readFloat())
: null;
- if (mCollectionInfo != null) mCollectionInfo.recycle();
mCollectionInfo = isBitSet(nonDefaultFields, fieldIndex++)
- ? CollectionInfo.obtain(
+ ? new CollectionInfo(
parcel.readInt(),
parcel.readInt(),
parcel.readInt() == 1,
parcel.readInt())
: null;
- if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
mCollectionItemInfo = isBitSet(nonDefaultFields, fieldIndex++)
- ? CollectionItemInfo.obtain(
+ ? new CollectionItemInfo(
parcel.readString(),
parcel.readInt(),
parcel.readInt(),
@@ -4241,8 +4173,7 @@
}
if (isBitSet(nonDefaultFields, fieldIndex++)) {
- if (mExtraRenderingInfo != null) mExtraRenderingInfo.recycle();
- mExtraRenderingInfo = ExtraRenderingInfo.obtain();
+ mExtraRenderingInfo = new ExtraRenderingInfo(null);
mExtraRenderingInfo.mLayoutSize = (Size) parcel.readValue(null);
mExtraRenderingInfo.mTextSizeInPx = parcel.readFloat();
mExtraRenderingInfo.mTextSizeUnit = parcel.readInt();
@@ -4265,7 +4196,7 @@
* Clears the state of this instance.
*/
private void clear() {
- init(DEFAULT, true /* usePoolingInfo */);
+ init(DEFAULT);
}
private static boolean isDefaultStandardAction(AccessibilityAction action) {
@@ -5235,7 +5166,6 @@
* handled by the {@link AccessibilityNodeInfo} to which this object is attached.
*/
public static final class RangeInfo {
- private static final int MAX_POOL_SIZE = 10;
/** Range type: integer. */
public static final int RANGE_TYPE_INT = 0;
@@ -5244,35 +5174,16 @@
/** Range type: percent with values from zero to one hundred. */
public static final int RANGE_TYPE_PERCENT = 2;
- private static final SynchronizedPool<RangeInfo> sPool =
- new SynchronizedPool<AccessibilityNodeInfo.RangeInfo>(MAX_POOL_SIZE);
-
private int mType;
private float mMin;
private float mMax;
private float mCurrent;
-
/**
- * Obtains a pooled instance that is a clone of another one.
+ * Instantiates a new RangeInfo.
*
- * <p>In most situations object pooling is not beneficial. Create a new instance using the
- * constructor {@link AccessibilityNodeInfo.RangeInfo#RangeInfo(int,
- * float, float, float)} instead.
- *
- * @param other The instance to clone.
- *
- * @hide
- */
- public static RangeInfo obtain(RangeInfo other) {
- return obtain(other.mType, other.mMin, other.mMax, other.mCurrent);
- }
-
- /**
- * Obtains a pooled instance.
- *
- * <p>In most situations object pooling is not beneficial. Create a new instance using the
- * constructor {@link AccessibilityNodeInfo.RangeInfo#RangeInfo(int,
- * float, float, float)} instead.
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
+ * constructor {@link AccessibilityNodeInfo.RangeInfo#RangeInfo(int, float, float,
+ * float)} instead.
*
* @param type The type of the range.
* @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no
@@ -5281,17 +5192,9 @@
* maximum.
* @param current The current value.
*/
+ @Deprecated
public static RangeInfo obtain(int type, float min, float max, float current) {
- RangeInfo info = sPool.acquire();
- if (info == null) {
- return new RangeInfo(type, min, max, current);
- }
-
- info.mType = type;
- info.mMin = min;
- info.mMax = max;
- info.mCurrent = current;
- return info;
+ return new RangeInfo(type, min, max, current);
}
/**
@@ -5354,12 +5257,11 @@
/**
* Recycles this instance.
*
- * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+ * @deprecated Object pooling has been discontinued. Calling this function now will have
+ * no effect.
*/
- void recycle() {
- clear();
- sPool.release(this);
- }
+ @Deprecated
+ void recycle() {}
private void clear() {
mType = 0;
@@ -5392,20 +5294,15 @@
/** Selection mode where multiple items may be selected. */
public static final int SELECTION_MODE_MULTIPLE = 2;
- private static final int MAX_POOL_SIZE = 20;
-
- private static final SynchronizedPool<CollectionInfo> sPool =
- new SynchronizedPool<>(MAX_POOL_SIZE);
-
private int mRowCount;
private int mColumnCount;
private boolean mHierarchical;
private int mSelectionMode;
/**
- * Obtains a pooled instance that is a clone of another one.
+ * Instantiates a CollectionInfo that is a clone of another one.
*
- * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
* constructor {@link
* AccessibilityNodeInfo.CollectionInfo#CollectionInfo} instead.
*
@@ -5413,14 +5310,14 @@
* @hide
*/
public static CollectionInfo obtain(CollectionInfo other) {
- return CollectionInfo.obtain(other.mRowCount, other.mColumnCount, other.mHierarchical,
+ return new CollectionInfo(other.mRowCount, other.mColumnCount, other.mHierarchical,
other.mSelectionMode);
}
/**
* Obtains a pooled instance.
*
- * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
* constructor {@link
* AccessibilityNodeInfo.CollectionInfo#CollectionInfo(int, int,
* boolean)} instead.
@@ -5431,13 +5328,13 @@
*/
public static CollectionInfo obtain(int rowCount, int columnCount,
boolean hierarchical) {
- return obtain(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE);
+ return new CollectionInfo(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE);
}
/**
* Obtains a pooled instance.
*
- * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
* constructor {@link
* AccessibilityNodeInfo.CollectionInfo#CollectionInfo(int, int,
* boolean, int)} instead.
@@ -5454,16 +5351,7 @@
*/
public static CollectionInfo obtain(int rowCount, int columnCount,
boolean hierarchical, int selectionMode) {
- final CollectionInfo info = sPool.acquire();
- if (info == null) {
- return new CollectionInfo(rowCount, columnCount, hierarchical, selectionMode);
- }
-
- info.mRowCount = rowCount;
- info.mColumnCount = columnCount;
- info.mHierarchical = hierarchical;
- info.mSelectionMode = selectionMode;
- return info;
+ return new CollectionInfo(rowCount, columnCount, hierarchical, selectionMode);
}
/**
@@ -5535,14 +5423,13 @@
}
/**
- * Recycles this instance.
+ * Previously would recycle this instance.
*
- * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+ * @deprecated Object pooling has been discontinued. Calling this function now will have
+ * no effect.
*/
- void recycle() {
- clear();
- sPool.release(this);
- }
+ @Deprecated
+ void recycle() {}
private void clear() {
mRowCount = 0;
@@ -5566,15 +5453,10 @@
* </p>
*/
public static final class CollectionItemInfo {
- private static final int MAX_POOL_SIZE = 20;
-
- private static final SynchronizedPool<CollectionItemInfo> sPool =
- new SynchronizedPool<>(MAX_POOL_SIZE);
-
/**
- * Obtains a pooled instance that is a clone of another one.
+ * Instantiates a CollectionItemInfo that is a clone of another one.
*
- * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
* constructor {@link
* AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo}
* instead.
@@ -5582,20 +5464,20 @@
* @param other The instance to clone.
* @hide
*/
+ @Deprecated
public static CollectionItemInfo obtain(CollectionItemInfo other) {
- return CollectionItemInfo.obtain(other.mRowTitle, other.mRowIndex, other.mRowSpan,
- other.mColumnTitle, other.mColumnIndex, other.mColumnSpan, other.mHeading,
- other.mSelected);
+ return new CollectionItemInfo(other.mRowTitle, other.mRowIndex, other.mRowSpan,
+ other.mColumnTitle, other.mColumnIndex, other.mColumnSpan, other.mHeading,
+ other.mSelected);
}
/**
- * Obtains a pooled instance.
+ * Instantiates a new CollectionItemInfo.
*
- * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
* constructor {@link
* AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo(int,
* int, int, int, boolean)} instead.
- *
* @param rowIndex The row index at which the item is located.
* @param rowSpan The number of rows the item spans.
* @param columnIndex The column index at which the item is located.
@@ -5603,37 +5485,39 @@
* @param heading Whether the item is a heading. (Prefer
* {@link AccessibilityNodeInfo#setHeading(boolean)}).
*/
+ @Deprecated
public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
int columnIndex, int columnSpan, boolean heading) {
- return obtain(rowIndex, rowSpan, columnIndex, columnSpan, heading, false);
+ return new CollectionItemInfo(rowIndex, rowSpan, columnIndex, columnSpan, heading,
+ false);
}
/**
- * Obtains a pooled instance.
+ * Instantiates a new CollectionItemInfo.
*
- * <p>In most situations object pooling is not beneficial. Creates a new instance using the
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
* constructor {@link
* AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo(int,
- * int, int, int, boolean, boolean)} instead.
- *
+ * int, int, int, boolean)} instead.
* @param rowIndex The row index at which the item is located.
* @param rowSpan The number of rows the item spans.
* @param columnIndex The column index at which the item is located.
* @param columnSpan The number of columns the item spans.
* @param heading Whether the item is a heading. (Prefer
- * {@link AccessibilityNodeInfo#setHeading(boolean)})
+ * {@link AccessibilityNodeInfo#setHeading(boolean)}).
* @param selected Whether the item is selected.
*/
+ @Deprecated
public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
int columnIndex, int columnSpan, boolean heading, boolean selected) {
- return obtain(null, rowIndex, rowSpan, null, columnIndex,
- columnSpan, heading, selected);
+ return new CollectionItemInfo(rowIndex, rowSpan, columnIndex, columnSpan, heading,
+ selected);
}
/**
- * Obtains a pooled instance.
+ * Instantiates a new CollectionItemInfo.
*
- * <p>In most situations object pooling is not beneficial. Creates a new instance using the
+ * @deprecated Object pooling has been discontinued. Creates a new instance using the
* constructor {@link
* AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo(int,
* int, int, int, boolean, boolean)} instead.
@@ -5648,25 +5532,13 @@
* {@link AccessibilityNodeInfo#setHeading(boolean)})
* @param selected Whether the item is selected.
*/
+ @Deprecated
@NonNull
public static CollectionItemInfo obtain(@Nullable String rowTitle, int rowIndex,
int rowSpan, @Nullable String columnTitle, int columnIndex, int columnSpan,
boolean heading, boolean selected) {
- final CollectionItemInfo info = sPool.acquire();
- if (info == null) {
- return new CollectionItemInfo(rowTitle, rowIndex, rowSpan, columnTitle,
- columnIndex, columnSpan, heading, selected);
- }
-
- info.mRowIndex = rowIndex;
- info.mRowSpan = rowSpan;
- info.mColumnIndex = columnIndex;
- info.mColumnSpan = columnSpan;
- info.mHeading = heading;
- info.mSelected = selected;
- info.mRowTitle = rowTitle;
- info.mColumnTitle = columnTitle;
- return info;
+ return new CollectionItemInfo(rowTitle, rowIndex, rowSpan, columnTitle, columnIndex,
+ columnSpan, heading, selected);
}
private boolean mHeading;
@@ -5817,12 +5689,11 @@
/**
* Recycles this instance.
*
- * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+ * @deprecated Object pooling has been discontinued. Calling this function now will have
+ * no effect.
*/
- void recycle() {
- clear();
- sPool.release(this);
- }
+ @Deprecated
+ void recycle() {}
private void clear() {
mColumnIndex = 0;
@@ -6151,34 +6022,34 @@
*/
public static final class ExtraRenderingInfo {
private static final int UNDEFINED_VALUE = -1;
- private static final int MAX_POOL_SIZE = 20;
- private static final SynchronizedPool<ExtraRenderingInfo> sPool =
- new SynchronizedPool<>(MAX_POOL_SIZE);
private Size mLayoutSize;
private float mTextSizeInPx = UNDEFINED_VALUE;
private int mTextSizeUnit = UNDEFINED_VALUE;
/**
- * Obtains a pooled instance.
+ * Instantiates an ExtraRenderingInfo, by copying an existing one.
+ *
* @hide
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
+ * constructor {@link #ExtraRenderingInfo(ExtraRenderingInfo)} instead.
*/
+ @Deprecated
@NonNull
public static ExtraRenderingInfo obtain() {
- final ExtraRenderingInfo info = sPool.acquire();
- if (info == null) {
- return new ExtraRenderingInfo(null);
- }
- return info;
+ return new ExtraRenderingInfo(null);
}
- /** Obtains a pooled instance that is a clone of another one. */
+ /**
+ * Instantiates an ExtraRenderingInfo, by copying an existing one.
+ *
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
+ * constructor {@link #ExtraRenderingInfo(ExtraRenderingInfo)} instead.
+ * @param other
+ */
+ @Deprecated
private static ExtraRenderingInfo obtain(ExtraRenderingInfo other) {
- ExtraRenderingInfo extraRenderingInfo = ExtraRenderingInfo.obtain();
- extraRenderingInfo.mLayoutSize = other.mLayoutSize;
- extraRenderingInfo.mTextSizeInPx = other.mTextSizeInPx;
- extraRenderingInfo.mTextSizeUnit = other.mTextSizeUnit;
- return extraRenderingInfo;
+ return new ExtraRenderingInfo(other);
}
/**
@@ -6268,14 +6139,13 @@
}
/**
- * Recycles this instance.
+ * Previously would recycle this instance.
*
- * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+ * @deprecated Object pooling has been discontinued. Calling this function now will have
+ * no effect.
*/
- void recycle() {
- clear();
- sPool.release(this);
- }
+ @Deprecated
+ void recycle() {}
private void clear() {
mLayoutSize = null;
@@ -6291,7 +6161,7 @@
new Parcelable.Creator<AccessibilityNodeInfo>() {
@Override
public AccessibilityNodeInfo createFromParcel(Parcel parcel) {
- AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+ AccessibilityNodeInfo info = new AccessibilityNodeInfo();
info.initFromParcel(parcel);
return info;
}
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index f26abb2..426a3f4 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -78,13 +78,6 @@
| AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS
| AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS;
- // Housekeeping
- private static final int MAX_POOL_SIZE = 10;
- private static final Object sPoolLock = new Object();
- private static AccessibilityRecord sPool;
- private static int sPoolSize;
- private AccessibilityRecord mNext;
- private boolean mIsInPool;
@UnsupportedAppUsage
boolean mSealed;
@@ -821,15 +814,14 @@
}
/**
- * Returns a cached instance if such is available or a new one is
- * instantiated. The instance is initialized with data from the
+ * Instantiates a new record initialized with data from the
* given record.
*
- * <p>In most situations object pooling is not beneficial. Create a new instance using the
- * constructor {@link #AccessibilityRecord(AccessibilityRecord)} instead.
- *
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
+ * constructor {@link #AccessibilityRecord()} instead.
* @return An instance.
*/
+ @Deprecated
public static AccessibilityRecord obtain(AccessibilityRecord record) {
AccessibilityRecord clone = AccessibilityRecord.obtain();
clone.init(record);
@@ -837,51 +829,25 @@
}
/**
- * Returns a cached instance if such is available or a new one is
- * instantiated.
+ * Instantiates a new record.
*
- * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * @deprecated Object pooling has been discontinued. Create a new instance using the
* constructor {@link #AccessibilityRecord()} instead.
- *
* @return An instance.
*/
+ @Deprecated
public static AccessibilityRecord obtain() {
- synchronized (sPoolLock) {
- if (sPool != null) {
- AccessibilityRecord record = sPool;
- sPool = sPool.mNext;
- sPoolSize--;
- record.mNext = null;
- record.mIsInPool = false;
- return record;
- }
- return new AccessibilityRecord();
- }
+ return new AccessibilityRecord();
}
/**
- * Return an instance back to be reused.
- * <p>
- * <strong>Note:</strong> You must not touch the object after calling this function.
+ * Would previously return an instance back to be reused.
*
- * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
- *
- * @throws IllegalStateException If the record is already recycled.
+ * @deprecated Object pooling has been discontinued. Calling this function now will have
+ * no effect.
*/
- public void recycle() {
- if (mIsInPool) {
- throw new IllegalStateException("Record already recycled!");
- }
- clear();
- synchronized (sPoolLock) {
- if (sPoolSize <= MAX_POOL_SIZE) {
- mNext = sPool;
- sPool = this;
- mIsInPool = true;
- sPoolSize++;
- }
- }
- }
+ @Deprecated
+ public void recycle() { }
/**
* Initialize this record from another one.
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 7566cea..0bb3cc2 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -86,6 +86,7 @@
import android.view.autofill.AutofillManager;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.inputmethod.DirectBootAwareness;
import com.android.internal.inputmethod.ImeTracing;
import com.android.internal.inputmethod.InputBindResult;
import com.android.internal.inputmethod.InputMethodDebug;
@@ -1234,6 +1235,26 @@
}
/**
+ * Returns the list of installed input methods for the specified user.
+ *
+ * @param userId user ID to query
+ * @param directBootAwareness {@code true} if caller want to query installed input methods list
+ * on user locked state.
+ * @return {@link List} of {@link InputMethodInfo}.
+ * @hide
+ */
+ @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
+ @NonNull
+ public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId,
+ @DirectBootAwareness int directBootAwareness) {
+ try {
+ return mService.getAwareLockedInputMethodList(userId, directBootAwareness);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns the list of enabled input methods.
*
* <p>On multi user environment, this API returns a result for the calling process user.</p>
diff --git a/core/java/android/view/inputmethod/TextAttribute.java b/core/java/android/view/inputmethod/TextAttribute.java
index bc76e78..57a555b9 100644
--- a/core/java/android/view/inputmethod/TextAttribute.java
+++ b/core/java/android/view/inputmethod/TextAttribute.java
@@ -36,7 +36,7 @@
private final @NonNull List<String> mTextConversionSuggestions;
private final @NonNull PersistableBundle mExtras;
- private TextAttribute(TextAttributeBuilder builder) {
+ private TextAttribute(Builder builder) {
mTextConversionSuggestions = builder.mTextConversionSuggestions;
mExtras = builder.mExtras;
}
@@ -48,7 +48,7 @@
/**
* Get the list of text conversion suggestions. More text conversion details in
- * {@link TextAttributeBuilder#setTextConversionSuggestions(List)}.
+ * {@link Builder#setTextConversionSuggestions(List)}.
*
* @return List of text conversion suggestions. If the list is empty, it means that IME not set
* this field or IME didn't have suggestions for applications.
@@ -59,7 +59,7 @@
/**
* Get the extras data. More extras data details in
- * {@link TextAttributeBuilder#setExtras(PersistableBundle)}.
+ * {@link Builder#setExtras(PersistableBundle)}.
*
* @return Extras data. If the Bundle is empty, it means that IME not set this field or IME
* didn't have extras data.
@@ -71,7 +71,7 @@
/**
* Builder for creating a {@link TextAttribute}.
*/
- public static final class TextAttributeBuilder {
+ public static final class Builder {
private List<String> mTextConversionSuggestions = new ArrayList<>();
private PersistableBundle mExtras = new PersistableBundle();
@@ -87,7 +87,7 @@
* @param textConversionSuggestions The list of text conversion suggestions.
* @return This builder
*/
- public @NonNull TextAttributeBuilder setTextConversionSuggestions(
+ public @NonNull Builder setTextConversionSuggestions(
@NonNull List<String> textConversionSuggestions) {
mTextConversionSuggestions = Collections.unmodifiableList(textConversionSuggestions);
return this;
@@ -101,7 +101,7 @@
*
* @return This builder.
*/
- public @NonNull TextAttributeBuilder setExtras(@NonNull PersistableBundle extras) {
+ public @NonNull Builder setExtras(@NonNull PersistableBundle extras) {
mExtras = extras;
return this;
}
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 862829b..dbf3570 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -74,6 +74,9 @@
* <p>
* Note that toasts being sent from the background are rate limited, so avoid sending such toasts
* in quick succession.
+ * <p>
+ * Starting with Android 12 (API level 31), apps targeting Android 12 or newer will have
+ * their toasts limited to two lines.
*
* <div class="special reference">
* <h3>Developer Guides</h3>
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 7208930..915c8fb 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -18,6 +18,7 @@
import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
import static android.app.ActivityOptions.ANIM_CUSTOM;
+import static android.app.ActivityOptions.ANIM_FROM_STYLE;
import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
import static android.app.ActivityOptions.ANIM_SCALE_UP;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
@@ -46,6 +47,7 @@
import android.os.Parcelable;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.view.WindowManager;
import java.util.ArrayList;
import java.util.List;
@@ -581,6 +583,7 @@
private String mPackageName;
private final Rect mTransitionBounds = new Rect();
private HardwareBuffer mThumbnail;
+ private int mAnimations;
private AnimationOptions(int type) {
mType = type;
@@ -594,6 +597,15 @@
mPackageName = in.readString();
mTransitionBounds.readFromParcel(in);
mThumbnail = in.readTypedObject(HardwareBuffer.CREATOR);
+ mAnimations = in.readInt();
+ }
+
+ public static AnimationOptions makeAnimOptionsFromLayoutParameters(
+ WindowManager.LayoutParams lp) {
+ AnimationOptions options = new AnimationOptions(ANIM_FROM_STYLE);
+ options.mPackageName = lp.packageName;
+ options.mAnimations = lp.windowAnimations;
+ return options;
}
public static AnimationOptions makeCustomAnimOptions(String packageName, int enterResId,
@@ -662,6 +674,10 @@
return mThumbnail;
}
+ public int getAnimations() {
+ return mAnimations;
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
@@ -671,6 +687,7 @@
dest.writeString(mPackageName);
mTransitionBounds.writeToParcel(dest, flags);
dest.writeTypedObject(mThumbnail, flags);
+ dest.writeInt(mAnimations);
}
@NonNull
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index bc3c2f5..025f711 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -190,7 +190,7 @@
* the handover intent.
* TODO: investigate whether the privileged query is necessary to determine the availability.
*/
- protected static final String EXTRA_IS_APP_PREDICTION_SERVICE_AVAILABLE =
+ public static final String EXTRA_IS_APP_PREDICTION_SERVICE_AVAILABLE =
"com.android.internal.app.ChooserActivity.EXTRA_IS_APP_PREDICTION_SERVICE_AVAILABLE";
/**
diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.aidl b/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.aidl
new file mode 100644
index 0000000..eed4015
--- /dev/null
+++ b/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.compat;
+
+parcelable CompatibilityOverridesByPackageConfig;
diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.java b/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.java
new file mode 100644
index 0000000..8652bb6
--- /dev/null
+++ b/core/java/com/android/internal/compat/CompatibilityOverridesByPackageConfig.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.compat;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Parcelable containing compat config overrides by application.
+ * @hide
+ */
+public final class CompatibilityOverridesByPackageConfig implements Parcelable {
+ public final Map<String, CompatibilityOverrideConfig> packageNameToOverrides;
+
+ public CompatibilityOverridesByPackageConfig(
+ Map<String, CompatibilityOverrideConfig> packageNameToOverrides) {
+ this.packageNameToOverrides = packageNameToOverrides;
+ }
+
+ private CompatibilityOverridesByPackageConfig(Parcel in) {
+ int keyCount = in.readInt();
+ packageNameToOverrides = new HashMap<>();
+ for (int i = 0; i < keyCount; i++) {
+ String key = in.readString();
+ packageNameToOverrides.put(key,
+ CompatibilityOverrideConfig.CREATOR.createFromParcel(in));
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(packageNameToOverrides.size());
+ for (String key : packageNameToOverrides.keySet()) {
+ dest.writeString(key);
+ packageNameToOverrides.get(key).writeToParcel(dest, /* flags= */ 0);
+ }
+ }
+
+ public static final Parcelable.Creator<CompatibilityOverridesByPackageConfig> CREATOR =
+ new Parcelable.Creator<CompatibilityOverridesByPackageConfig>() {
+
+ @Override
+ public CompatibilityOverridesByPackageConfig createFromParcel(Parcel in) {
+ return new CompatibilityOverridesByPackageConfig(in);
+ }
+
+ @Override
+ public CompatibilityOverridesByPackageConfig[] newArray(int size) {
+ return new CompatibilityOverridesByPackageConfig[size];
+ }
+ };
+}
diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.aidl b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.aidl
new file mode 100644
index 0000000..b9d0cef
--- /dev/null
+++ b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.compat;
+
+parcelable CompatibilityOverridesToRemoveByPackageConfig;
diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.java b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.java
new file mode 100644
index 0000000..b408d64
--- /dev/null
+++ b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveByPackageConfig.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.compat;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Parcelable containing compat config change IDs for which to remove overrides by application.
+ *
+ * <p>This class is separate from CompatibilityOverridesByPackageConfig since we only need change
+ * IDs.
+ * @hide
+ */
+public final class CompatibilityOverridesToRemoveByPackageConfig implements Parcelable {
+ public final Map<String, CompatibilityOverridesToRemoveConfig> packageNameToOverridesToRemove;
+
+ public CompatibilityOverridesToRemoveByPackageConfig(
+ Map<String, CompatibilityOverridesToRemoveConfig> packageNameToOverridesToRemove) {
+ this.packageNameToOverridesToRemove = packageNameToOverridesToRemove;
+ }
+
+ private CompatibilityOverridesToRemoveByPackageConfig(Parcel in) {
+ int keyCount = in.readInt();
+ packageNameToOverridesToRemove = new HashMap<>();
+ for (int i = 0; i < keyCount; i++) {
+ String key = in.readString();
+ packageNameToOverridesToRemove.put(key,
+ CompatibilityOverridesToRemoveConfig.CREATOR.createFromParcel(in));
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(packageNameToOverridesToRemove.size());
+ for (String key : packageNameToOverridesToRemove.keySet()) {
+ dest.writeString(key);
+ packageNameToOverridesToRemove.get(key).writeToParcel(dest, /* flags= */ 0);
+ }
+ }
+
+ public static final Parcelable.Creator<CompatibilityOverridesToRemoveByPackageConfig> CREATOR =
+ new Parcelable.Creator<CompatibilityOverridesToRemoveByPackageConfig>() {
+
+ @Override
+ public CompatibilityOverridesToRemoveByPackageConfig createFromParcel(Parcel in) {
+ return new CompatibilityOverridesToRemoveByPackageConfig(in);
+ }
+
+ @Override
+ public CompatibilityOverridesToRemoveByPackageConfig[] newArray(int size) {
+ return new CompatibilityOverridesToRemoveByPackageConfig[size];
+ }
+ };
+}
diff --git a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java
index 642f79c..e85afef 100644
--- a/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java
+++ b/core/java/com/android/internal/compat/CompatibilityOverridesToRemoveConfig.java
@@ -26,6 +26,8 @@
/**
* Parcelable containing compat config change IDs for which to remove overrides for a given
* application.
+ *
+ * <p>This class is separate from CompatibilityOverrideConfig since we only need change IDs.
* @hide
*/
public final class CompatibilityOverridesToRemoveConfig implements Parcelable {
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 418d16e..8847a49 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -22,6 +22,8 @@
parcelable CompatibilityChangeConfig;
parcelable CompatibilityOverrideConfig;
+parcelable CompatibilityOverridesByPackageConfig;
+parcelable CompatibilityOverridesToRemoveByPackageConfig;
parcelable CompatibilityOverridesToRemoveConfig;
parcelable CompatibilityChangeInfo;
/**
@@ -152,6 +154,26 @@
void setOverrides(in CompatibilityChangeConfig overrides, in String packageName);
/**
+ * Adds overrides to compatibility changes on release builds for multiple apps.
+ *
+ * <p>The caller to this API needs to hold
+ * {@code android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD} and all change ids
+ * in {@code overridesByPackage} need to annotated with {@link
+ * android.compat.annotation.Overridable}.
+ *
+ * A release build in this definition means that {@link android.os.Build#IS_DEBUGGABLE} needs to
+ * be {@code false}.
+ *
+ * <p>Note that this does not kill the app, and therefore overrides read from the app process
+ * will not be updated. Overrides read from the system process do take effect.
+ *
+ * @param overridesByPackage parcelable containing the compat change overrides to be applied
+ * on specific apps by their package name
+ * @throws SecurityException if overriding changes is not permitted
+ */
+ void putAllOverridesOnReleaseBuilds(in CompatibilityOverridesByPackageConfig overridesByPackage);
+
+ /**
* Adds overrides to compatibility changes on release builds.
*
* <p>The caller to this API needs to hold
@@ -206,6 +228,26 @@
boolean clearOverrideForTest(long changeId, String packageName);
/**
+ * Restores the default behaviour for compatibility changes on release builds for multiple apps.
+ *
+ * <p>The caller to this API needs to hold
+ * {@code android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD} and all change ids
+ * in {@code overridesToRemoveByPackage} need to annotated with {@link
+ * android.compat.annotation.Overridable}.
+ *
+ * A release build in this definition means that {@link android.os.Build#IS_DEBUGGABLE} needs to
+ * be {@code false}.
+ *
+ * <p>Note that this does not kill the app, and therefore overrides read from the app process
+ * will not be updated. Overrides read from the system process do take effect.
+ *
+ * @param overridesToRemoveByPackage parcelable containing the compat change overrides to be
+ * removed for specific apps by their package name
+ * @throws SecurityException if overriding changes is not permitted
+ */
+ void removeAllOverridesOnReleaseBuilds(in CompatibilityOverridesToRemoveByPackageConfig overridesToRemoveByPackage);
+
+ /**
* Restores the default behaviour for compatibility changes on release builds.
*
* <p>The caller to this API needs to hold
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 6a6f60e..f904610 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -157,6 +157,12 @@
*/
public static final String PROPERTY_LOCATION_INDICATORS_ENABLED = "location_indicators_enabled";
+ /**
+ * Whether to show old location indicator on all location accesses.
+ */
+ public static final String PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED =
+ "location_indicators_small_enabled";
+
// Flags related to Assistant
/**
diff --git a/core/java/com/android/internal/inputmethod/DirectBootAwareness.java b/core/java/com/android/internal/inputmethod/DirectBootAwareness.java
new file mode 100644
index 0000000..51f914f
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/DirectBootAwareness.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+
+/**
+ * Specifies the decided filtering mode regarding IMEs' DirectBoot awareness when querying IMEs.
+ */
+@Retention(SOURCE)
+@IntDef({DirectBootAwareness.AUTO, DirectBootAwareness.ANY})
+public @interface DirectBootAwareness {
+ /**
+ * The same semantics as {@link android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO}, that
+ * is, if the user to be queried is still locked, then only DirectBoot-aware IMEs will be
+ * matched. If the user to be queried is already unlocked, then IMEs will not be filtered out
+ * based on their DirectBoot awareness.
+ */
+ int AUTO = 0;
+ /**
+ * The same semantics as specifying <strong>both</strong>
+ * {@link android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE} and
+ * {@link android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE}, that is, IME will never
+ * be filtered out based on their DirectBoot awareness, no matter whether the user to be queried
+ * is still locked or already unlocked.
+ */
+ int ANY = 1;
+}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index ea38db3..0d4ad38 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -42,6 +42,8 @@
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_UNLOCK_ANIMATION;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF_SHOW_AOD;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_PAGE_SCROLL;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON;
@@ -177,6 +179,8 @@
public static final int CUJ_USER_SWITCH = 37;
public static final int CUJ_SPLASHSCREEN_AVD = 38;
public static final int CUJ_SPLASHSCREEN_EXIT_ANIM = 39;
+ public static final int CUJ_SCREEN_OFF = 40;
+ public static final int CUJ_SCREEN_OFF_SHOW_AOD = 41;
private static final int NO_STATSD_LOGGING = -1;
@@ -225,6 +229,8 @@
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_AVD,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_EXIT_ANIM,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF_SHOW_AOD,
};
private static volatile InteractionJankMonitor sInstance;
@@ -285,6 +291,8 @@
CUJ_USER_SWITCH,
CUJ_SPLASHSCREEN_AVD,
CUJ_SPLASHSCREEN_EXIT_ANIM,
+ CUJ_SCREEN_OFF,
+ CUJ_SCREEN_OFF_SHOW_AOD,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -423,6 +431,16 @@
}
/**
+ * @param cujType cuj type
+ * @return true if the cuj is under instrumenting, false otherwise.
+ */
+ public boolean isInstrumenting(@CujType int cujType) {
+ synchronized (mLock) {
+ return mRunningTrackers.contains(cujType);
+ }
+ }
+
+ /**
* Begins a trace session.
*
* @param v an attached view.
@@ -690,6 +708,10 @@
return "SPLASHSCREEN_AVD";
case CUJ_SPLASHSCREEN_EXIT_ANIM:
return "SPLASHSCREEN_EXIT_ANIM";
+ case CUJ_SCREEN_OFF:
+ return "SCREEN_OFF";
+ case CUJ_SCREEN_OFF_SHOW_AOD:
+ return "SCREEN_OFF_SHOW_AOD";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index d0a8c32..519faa8 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -143,17 +143,24 @@
public boolean areAuthParamsInline = false; // 23
public final boolean isRestrictedToTestNetworks; // 24
+ public final boolean excludeLocalRoutes; // 25
+
// Helper fields.
@UnsupportedAppUsage
public transient boolean saveLogin = false;
public VpnProfile(String key) {
- this(key, false);
+ this(key, false, false);
}
public VpnProfile(String key, boolean isRestrictedToTestNetworks) {
+ this(key, isRestrictedToTestNetworks, false);
+ }
+
+ public VpnProfile(String key, boolean isRestrictedToTestNetworks, boolean excludeLocalRoutes) {
this.key = key;
this.isRestrictedToTestNetworks = isRestrictedToTestNetworks;
+ this.excludeLocalRoutes = excludeLocalRoutes;
}
@UnsupportedAppUsage
@@ -183,6 +190,7 @@
maxMtu = in.readInt();
areAuthParamsInline = in.readBoolean();
isRestrictedToTestNetworks = in.readBoolean();
+ excludeLocalRoutes = in.readBoolean();
}
/**
@@ -230,6 +238,7 @@
out.writeInt(maxMtu);
out.writeBoolean(areAuthParamsInline);
out.writeBoolean(isRestrictedToTestNetworks);
+ out.writeBoolean(excludeLocalRoutes);
}
/**
@@ -249,8 +258,9 @@
// 14-19: Standard profile, with option for serverCert, proxy
// 24: Standard profile with serverCert, proxy and platform-VPN parameters
// 25: Standard profile with platform-VPN parameters and isRestrictedToTestNetworks
+ // 26: Standard profile with platform-VPN parameters and excludeLocalRoutes
if ((values.length < 14 || values.length > 19)
- && values.length != 24 && values.length != 25) {
+ && values.length != 24 && values.length != 25 && values.length != 26) {
return null;
}
@@ -261,7 +271,15 @@
isRestrictedToTestNetworks = false;
}
- VpnProfile profile = new VpnProfile(key, isRestrictedToTestNetworks);
+ final boolean excludeLocalRoutes;
+ if (values.length >= 26) {
+ excludeLocalRoutes = Boolean.parseBoolean(values[25]);
+ } else {
+ excludeLocalRoutes = false;
+ }
+
+ VpnProfile profile = new VpnProfile(key, isRestrictedToTestNetworks,
+ excludeLocalRoutes);
profile.name = values[0];
profile.type = Integer.parseInt(values[1]);
if (profile.type < 0 || profile.type > TYPE_MAX) {
@@ -371,6 +389,8 @@
builder.append(VALUE_DELIMITER).append(areAuthParamsInline);
builder.append(VALUE_DELIMITER).append(isRestrictedToTestNetworks);
+ builder.append(VALUE_DELIMITER).append(excludeLocalRoutes);
+
return builder.toString().getBytes(StandardCharsets.UTF_8);
}
@@ -451,7 +471,7 @@
key, type, server, username, password, dnsServers, searchDomains, routes, mppe,
l2tpSecret, ipsecIdentifier, ipsecSecret, ipsecUserCert, ipsecCaCert, ipsecServerCert,
proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline,
- isRestrictedToTestNetworks);
+ isRestrictedToTestNetworks, excludeLocalRoutes);
}
/** Checks VPN profiles for interior equality. */
@@ -484,7 +504,8 @@
&& isMetered == other.isMetered
&& maxMtu == other.maxMtu
&& areAuthParamsInline == other.areAuthParamsInline
- && isRestrictedToTestNetworks == other.isRestrictedToTestNetworks;
+ && isRestrictedToTestNetworks == other.isRestrictedToTestNetworks
+ && excludeLocalRoutes == other.excludeLocalRoutes;
}
@NonNull
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index 88425be..c1111ec 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -21,11 +21,13 @@
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
+import android.os.Parcel;
import android.os.SystemClock;
import android.os.UidBatteryConsumer;
import android.util.Log;
import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
@@ -133,9 +135,12 @@
*/
@VisibleForTesting
public BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query) {
- return getBatteryUsageStats(query, currentTimeMillis());
+ synchronized (mStats) {
+ return getBatteryUsageStats(query, currentTimeMillis());
+ }
}
+ @GuardedBy("mStats")
private BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query,
long currentTimeMs) {
if (query.getToTimestamp() == 0) {
@@ -145,6 +150,7 @@
}
}
+ @GuardedBy("mStats")
private BatteryUsageStats getCurrentBatteryUsageStats(BatteryUsageStatsQuery query,
long currentTimeMs) {
final long realtimeUs = elapsedRealtime() * 1000;
@@ -189,7 +195,12 @@
}
BatteryStatsImpl batteryStatsImpl = (BatteryStatsImpl) mStats;
- batteryUsageStatsBuilder.setBatteryHistory(batteryStatsImpl.mHistoryBuffer);
+
+ // Make a copy of battery history to avoid concurrent modification.
+ Parcel historyBuffer = Parcel.obtain();
+ historyBuffer.appendFrom(batteryStatsImpl.mHistoryBuffer, 0,
+ batteryStatsImpl.mHistoryBuffer.dataSize());
+ batteryUsageStatsBuilder.setBatteryHistory(historyBuffer);
}
return batteryUsageStatsBuilder.build();
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index 76aa7a0..36b7ee5 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -15,6 +15,7 @@
*/
package com.android.internal.policy;
+import android.content.Intent;
import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardStateCallback;
@@ -113,7 +114,20 @@
/**
* Notifies the Keyguard that the power key was pressed while locked and launched Home rather
- * than putting the device to sleep or waking up.
+ * than putting the device to sleep or waking up. Note that it's called only if the device is
+ * interactive.
*/
void onShortPowerPressedGoHome();
+
+ /**
+ * Notifies the Keyguard that it needs to bring up a bouncer and then launch the intent as soon
+ * as user unlocks the watch.
+ */
+ void dismissKeyguardToLaunch(in Intent intentToLaunch);
+
+ /**
+ * Notifies the Keyguard that a key was pressed while locked so the Keyguard can handle it.
+ * Note that it's called only if the device is interactive.
+ */
+ void onSystemKeyPressed(int keycode);
}
diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index d3224b1..faea7706e 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -260,25 +260,39 @@
return null;
}
- /** Load animation by attribute Id from android package. */
+ /** Load animation by attribute Id from a specific AnimationStyle resource. */
@Nullable
- public Animation loadDefaultAnimationAttr(int animAttr) {
+ public Animation loadAnimationAttr(String packageName, int animStyleResId, int animAttr,
+ boolean translucent) {
+ if (animStyleResId == 0) {
+ return null;
+ }
int resId = Resources.ID_NULL;
Context context = mContext;
if (animAttr >= 0) {
- AttributeCache.Entry ent = getCachedAnimations(DEFAULT_PACKAGE,
- mDefaultWindowAnimationStyleResId);
+ packageName = packageName != null ? packageName : DEFAULT_PACKAGE;
+ AttributeCache.Entry ent = getCachedAnimations(packageName, animStyleResId);
if (ent != null) {
context = ent.context;
resId = ent.array.getResourceId(animAttr, 0);
}
}
+ if (translucent) {
+ resId = updateToTranslucentAnimIfNeeded(resId);
+ }
if (ResourceId.isValid(resId)) {
return loadAnimationSafely(context, resId, mTag);
}
return null;
}
+ /** Load animation by attribute Id from android package. */
+ @Nullable
+ public Animation loadDefaultAnimationAttr(int animAttr) {
+ return loadAnimationAttr(DEFAULT_PACKAGE, mDefaultWindowAnimationStyleResId, animAttr,
+ false /* translucent */);
+ }
+
@Nullable
private AttributeCache.Entry getCachedAnimations(LayoutParams lp) {
if (mDebug) {
@@ -1024,6 +1038,16 @@
return anim;
}
+ private static int updateToTranslucentAnimIfNeeded(int anim) {
+ if (anim == R.anim.activity_open_enter) {
+ return R.anim.activity_translucent_open_enter;
+ }
+ if (anim == R.anim.activity_close_exit) {
+ return R.anim.activity_translucent_close_exit;
+ }
+ return anim;
+ }
+
private static @TransitionOldType int getTransitCompatType(@TransitionType int transit,
int wallpaperTransit) {
if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) {
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index e95ba88..1cd758c 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -127,6 +127,11 @@
*/
public static final int ACTION_SWITCH_DISPLAY_UNFOLD = 13;
+ /**
+ * Time it takes for a UDFPS sensor to appear ready after it is touched.
+ */
+ public static final int ACTION_UDFPS_ILLUMINATE = 14;
+
private static final int[] ACTIONS_ALL = {
ACTION_EXPAND_PANEL,
ACTION_TOGGLE_RECENTS,
@@ -141,7 +146,8 @@
ACTION_ROTATE_SCREEN_CAMERA_CHECK,
ACTION_LOCKSCREEN_UNLOCK,
ACTION_USER_SWITCH,
- ACTION_SWITCH_DISPLAY_UNFOLD
+ ACTION_SWITCH_DISPLAY_UNFOLD,
+ ACTION_UDFPS_ILLUMINATE
};
/** @hide */
@@ -159,7 +165,8 @@
ACTION_ROTATE_SCREEN_CAMERA_CHECK,
ACTION_LOCKSCREEN_UNLOCK,
ACTION_USER_SWITCH,
- ACTION_SWITCH_DISPLAY_UNFOLD
+ ACTION_SWITCH_DISPLAY_UNFOLD,
+ ACTION_UDFPS_ILLUMINATE
})
@Retention(RetentionPolicy.SOURCE)
public @interface Action {
@@ -179,7 +186,8 @@
FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK,
FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK,
FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_USER_SWITCH,
- FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD,
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_UDFPS_ILLUMINATE
};
private static LatencyTracker sLatencyTracker;
@@ -267,6 +275,8 @@
return "ACTION_USER_SWITCH";
case 14:
return "ACTION_SWITCH_DISPLAY_UNFOLD";
+ case 15:
+ return "ACTION_UDFPS_ILLUMINATE";
default:
throw new IllegalArgumentException("Invalid action");
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 350ec33..2dc7c42c 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -35,6 +35,7 @@
// TODO: Use ParceledListSlice instead
List<InputMethodInfo> getInputMethodList(int userId);
+ List<InputMethodInfo> getAwareLockedInputMethodList(int userId, int directBootAwareness);
// TODO: Use ParceledListSlice instead
List<InputMethodInfo> getEnabledInputMethodList(int userId);
List<InputMethodSubtype> getEnabledInputMethodSubtypeList(in String imiId,
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 04fafb4..21ec64b 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -232,8 +232,7 @@
// TODO: Rename the server-level flag or remove.
static const char* ENABLE_JITZYGOTE_IMAGE = "enable_apex_image";
// Flag to pass to the runtime when using the JIT Zygote image.
-static const char* kJitZygoteImageOption =
- "-Ximage:boot.art:/nonx/boot-framework.art!/system/etc/boot-image.prof";
+static const char* kJitZygoteImageOption = "-Xforcejitzygote";
// Feature flag name for disabling lock profiling.
static const char* DISABLE_LOCK_PROFILING = "disable_lock_profiling";
@@ -987,9 +986,9 @@
"--instruction-set-features=", "-Xcompiler-option");
/*
- * When running with debug.generate-debug-info, add --generate-debug-info to
- * the compiler options so that both JITted code and the boot image extension,
- * if it is compiled on device, will include native debugging information.
+ * When running with debug.generate-debug-info, add --generate-debug-info to the compiler
+ * options so that both JITted code and the boot image, if it is compiled on device, will
+ * include native debugging information.
*/
property_get("debug.generate-debug-info", propBuf, "");
bool generate_debug_info = (strcmp(propBuf, "true") == 0);
@@ -1012,7 +1011,7 @@
property_get("dalvik.vm.extra-opts", extraOptsBuf, "");
parseExtraOpts(extraOptsBuf, NULL);
- // Extra options for boot image extension generation.
+ // Extra options for boot image generation.
if (skip_compilation) {
addOption("-Xnoimage-dex2oat");
} else {
@@ -1035,8 +1034,8 @@
parseCompilerOption("dalvik.vm.image-dex2oat-cpu-set", dex2oatCpuSetImageBuf, "--cpu-set=",
"-Ximage-compiler-option");
- // The runtime may compile a boot image extension, when necessary, not using installd.
- // Thus, we need to pass the instruction-set-features/variant as an image-compiler-option.
+ // The runtime may compile a boot image, when necessary, not using installd. Thus, we need
+ // to pass the instruction-set-features/variant as an image-compiler-option.
// Note: it is OK to reuse the buffer, as the values are exactly the same between
// * compiler-option, used for runtime compilation (DexClassLoader)
// * image-compiler-option, used for boot-image compilation on device
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index f2bcb02..4357729 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -59,13 +59,17 @@
per-file android_media_midi_* = file:/media/java/android/media/midi/OWNERS
per-file android_opengl_* = file:/opengl/java/android/opengl/OWNERS
per-file android_os_storage_* = file:/core/java/android/os/storage/OWNERS
-per-file android_se_* = file:/core/java/android/se/OWNERS
+per-file android_se_* = file:/omapi/java/android/se/OWNERS
per-file android_security_* = file:/core/java/android/security/OWNERS
per-file android_view_* = file:/core/java/android/view/OWNERS
per-file com_android_internal_net_* = file:/services/core/java/com/android/server/net/OWNERS
### Graphics ###
per-file android_graphics_* = file:/graphics/java/android/graphics/OWNERS
+
+### Text ###
+per-file android_text_* = file:/core/java/android/text/OWNERS
+
# These are highly common-use files
per-file Android.bp = file:/graphics/java/android/graphics/OWNERS
per-file AndroidRuntime.cpp = file:/graphics/java/android/graphics/OWNERS
diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp
index 78e5adc..55f1369 100644
--- a/core/jni/android_graphics_BLASTBufferQueue.cpp
+++ b/core/jni/android_graphics_BLASTBufferQueue.cpp
@@ -37,16 +37,6 @@
return reinterpret_cast<jlong>(queue.get());
}
-static jlong nativeCreateAndUpdate(JNIEnv* env, jclass clazz, jstring jName, jlong surfaceControl,
- jlong width, jlong height, jint format) {
- ScopedUtfChars name(env, jName);
- sp<BLASTBufferQueue> queue =
- new BLASTBufferQueue(name.c_str(), reinterpret_cast<SurfaceControl*>(surfaceControl),
- width, height, format);
- queue->incStrong((void*)nativeCreate);
- return reinterpret_cast<jlong>(queue.get());
-}
-
static void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
queue->decStrong((void*)nativeCreate);
@@ -91,11 +81,15 @@
queue->applyPendingTransactions(frameNum);
}
+static bool nativeIsSameSurfaceControl(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl) {
+ sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
+ return queue->isSameSurfaceControl(reinterpret_cast<SurfaceControl*>(surfaceControl));
+}
+
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
// clang-format off
{"nativeCreate", "(Ljava/lang/String;)J", (void*)nativeCreate},
- {"nativeCreateAndUpdate", "(Ljava/lang/String;JJJI)J", (void*)nativeCreateAndUpdate},
{"nativeGetSurface", "(JZ)Landroid/view/Surface;", (void*)nativeGetSurface},
{"nativeDestroy", "(J)V", (void*)nativeDestroy},
{"nativeSetSyncTransaction", "(JJZ)V", (void*)nativeSetSyncTransaction},
@@ -103,6 +97,7 @@
{"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction},
{"nativeGetLastAcquiredFrameNum", "(J)J", (void*)nativeGetLastAcquiredFrameNum},
{"nativeApplyPendingTransactions", "(JJ)V", (void*)nativeApplyPendingTransactions},
+ {"nativeIsSameSurfaceControl", "(JJ)Z", (void*)nativeIsSameSurfaceControl},
// clang-format on
};
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 8b45907..3e2b258 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2774,6 +2774,46 @@
return canBeSpatialized;
}
+// keep these values in sync with AudioSystem.java
+#define DIRECT_NOT_SUPPORTED 0
+#define DIRECT_OFFLOAD_SUPPORTED 1
+#define DIRECT_OFFLOAD_GAPLESS_SUPPORTED 3
+#define DIRECT_BITSTREAM_SUPPORTED 4
+
+static jint convertAudioDirectModeFromNative(audio_direct_mode_t directMode) {
+ jint result = DIRECT_NOT_SUPPORTED;
+ if ((directMode & AUDIO_DIRECT_OFFLOAD_SUPPORTED) != AUDIO_DIRECT_NOT_SUPPORTED) {
+ result |= DIRECT_OFFLOAD_SUPPORTED;
+ }
+ if ((directMode & AUDIO_DIRECT_OFFLOAD_GAPLESS_SUPPORTED) != AUDIO_DIRECT_NOT_SUPPORTED) {
+ result |= DIRECT_OFFLOAD_GAPLESS_SUPPORTED;
+ }
+ if ((directMode & AUDIO_DIRECT_BITSTREAM_SUPPORTED) != AUDIO_DIRECT_NOT_SUPPORTED) {
+ result |= DIRECT_BITSTREAM_SUPPORTED;
+ }
+ return result;
+}
+
+static jint android_media_AudioSystem_getDirectPlaybackSupport(JNIEnv *env, jobject thiz,
+ jobject jFormat, jobject jaa) {
+ JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
+ jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
+ if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ return DIRECT_NOT_SUPPORTED;
+ }
+
+ audio_config_t nConfig;
+ javaAudioFormatToNativeAudioConfig(env, &nConfig, jFormat, false /*isInput*/);
+
+ audio_direct_mode_t directMode;
+ status_t status = AudioSystem::getDirectPlaybackSupport(paa.get(), &nConfig, &directMode);
+ if (status != NO_ERROR) {
+ ALOGW("%s native returned error %d", __func__, status);
+ return DIRECT_NOT_SUPPORTED;
+ }
+ return convertAudioDirectModeFromNative(directMode);
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] =
@@ -2917,7 +2957,10 @@
{"canBeSpatialized",
"(Landroid/media/AudioAttributes;Landroid/media/AudioFormat;"
"[Landroid/media/AudioDeviceAttributes;)Z",
- (void *)android_media_AudioSystem_canBeSpatialized}};
+ (void *)android_media_AudioSystem_canBeSpatialized},
+ {"getDirectPlaybackSupport",
+ "(Landroid/media/AudioFormat;Landroid/media/AudioAttributes;)I",
+ (void *)android_media_AudioSystem_getDirectPlaybackSupport}};
static const JNINativeMethod gEventHandlerMethods[] = {
{"native_setup",
diff --git a/core/jni/android_text_Hyphenator.cpp b/core/jni/android_text_Hyphenator.cpp
index 21402b6..0eb8c6a 100644
--- a/core/jni/android_text_Hyphenator.cpp
+++ b/core/jni/android_text_Hyphenator.cpp
@@ -83,6 +83,7 @@
constexpr int INDIC_MIN_PREFIX = 2;
constexpr int INDIC_MIN_SUFFIX = 2;
+ addHyphenator("am", 1, 1); // Amharic
addHyphenator("as", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Assamese
addHyphenator("be", 2, 2); // Belarusian
addHyphenator("bg", 2, 2); // Bulgarian
@@ -100,6 +101,7 @@
addHyphenator("eu", 2, 2); // Basque
addHyphenator("fr", 2, 3); // French
addHyphenator("ga", 2, 3); // Irish
+ addHyphenator("gl", 2, 2); // Galician
addHyphenator("gu", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Gujarati
addHyphenator("hi", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Hindi
addHyphenator("hr", 2, 2); // Croatian
@@ -107,8 +109,10 @@
// texhyphen sources say Armenian may be (1, 2); but that it needs confirmation.
// Going with a more conservative value of (2, 2) for now.
addHyphenator("hy", 2, 2); // Armenian
+ addHyphenator("it", 2, 2); // Italian
addHyphenator("kn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Kannada
addHyphenator("la", 2, 2); // Latin
+ addHyphenator("lt", 2, 2); // Lithuanian
addHyphenator("ml", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Malayalam
addHyphenator("mn-Cyrl", 2, 2); // Mongolian in Cyrillic script
addHyphenator("mr", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Marathi
@@ -121,6 +125,7 @@
addHyphenator("ta", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Tamil
addHyphenator("te", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Telugu
addHyphenator("tk", 2, 2); // Turkmen
+ addHyphenator("uk", 2, 2); // Ukrainian
addHyphenator("und-Ethi", 1, 1); // Any language in Ethiopic script
// Following two hyphenators do not have pattern files but there is some special logic based on
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index b406578..f76b211 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -716,8 +716,6 @@
optional SettingProto nr_nsa_tracking_screen_off_mode = 153 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto nsd_on = 83 [ (android.privacy).dest = DEST_AUTOMATIC ];
-
message Ntp {
option (android.msg_privacy).dest = DEST_EXPLICIT;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e2a2ac6..d0fee11 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1489,8 +1489,26 @@
android:permissionGroup="android.permission-group.UNDEFINED"
android:label="@string/permlab_bodySensors"
android:description="@string/permdesc_bodySensors"
+ android:backgroundPermission="android.permission.BODY_SENSORS_BACKGROUND"
android:protectionLevel="dangerous" />
+ <!-- Allows an application to access data from sensors that the user uses to measure what is
+ happening inside their body, such as heart rate. If you're requesting this permission, you
+ must also request {@link #BODY_SENSORS}. Requesting this permission by itself doesn't give
+ you Body sensors access.
+ <p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record whitelists the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+ -->
+ <permission android:name="android.permission.BODY_SENSORS_BACKGROUND"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_bodySensors_background"
+ android:description="@string/permdesc_bodySensors_background"
+ android:protectionLevel="dangerous"
+ android:permissionFlags="hardRestricted" />
+
<!-- Allows an app to use fingerprint hardware.
<p>Protection level: normal
@deprecated Applications should request {@link
@@ -6071,6 +6089,13 @@
<permission android:name="android.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES"
android:protectionLevel="signature|role" />
+ <!-- @SystemApi Allows an app to read whether SafetyCenter is enabled/disabled.
+ <p>Protection level: signature|privileged
+ @hide
+ -->
+ <permission android:name="android.permission.READ_SAFETY_CENTER_STATUS"
+ android:protectionLevel="signature|privileged" />
+
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 585c372..ddaff68 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Gepasmaakte programkennisgewing"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep (\'n gebruiker met hierdie rekening bestaan reeds)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Voeg gebruiker onder toesig by"</string>
<string name="language_selection_title" msgid="52674936078683285">"Voeg \'n taal by"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Streekvoorkeur"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Voer taalnaam in"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index f338166..cee4da6 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"ብጁ የመተግበሪያ ማሳወቂያ"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> በ<xliff:g id="ACCOUNT">%2$s</xliff:g> አዲስ ተጠቃሚ እንዲፈጥር ይፈቀድለት (ይህ መለያ ያለው ተጠቃሚ አስቀድሞ አለ)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> አዲስ ተጠቃሚ ከ <xliff:g id="ACCOUNT">%2$s</xliff:g> ጋር መፍጠር እንዲችል ይፍቀዱ?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"ቋንቋ ያክሉ"</string>
<string name="country_selection_title" msgid="5221495687299014379">"የክልል ምርጫ"</string>
<string name="search_language_hint" msgid="7004225294308793583">"የቋንቋ ስም ይተይቡ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index c15f298..4927fa9 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -287,7 +287,7 @@
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"إشعار جديد"</string>
<string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"لوحة المفاتيح الافتراضية"</string>
- <string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"لوحة المفاتيح الفعلية"</string>
+ <string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"لوحة المفاتيح الخارجية"</string>
<string name="notification_channel_security" msgid="8516754650348238057">"الأمان"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"وضع السيارة"</string>
<string name="notification_channel_account" msgid="6436294521740148173">"حالة الحساب"</string>
@@ -2117,6 +2117,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"إشعار تطبيق مخصّص"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"هل تسمح لتطبيق <xliff:g id="APP">%1$s</xliff:g> بإنشاء مستخدم جديد باستخدام <xliff:g id="ACCOUNT">%2$s</xliff:g> (يوجد مستخدم بهذا الحساب مسبقًا)؟"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"هل تسمح لتطبيق <xliff:g id="APP">%1$s</xliff:g> بإنشاء مستخدم جديد باستخدام <xliff:g id="ACCOUNT">%2$s</xliff:g> ؟"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"إضافة لغة"</string>
<string name="country_selection_title" msgid="5221495687299014379">"تفضيل المنطقة"</string>
<string name="search_language_hint" msgid="7004225294308793583">"اكتب اسم اللغة"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 9dbfb2e..0c09239 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"কাষ্টম এপৰ জাননী"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>ক <xliff:g id="ACCOUNT">%2$s</xliff:g>ৰ (এই একাউণ্টটোৰ এজন ব্যৱহাৰকাৰী ইতিমধ্যে আছে) জৰিয়তে এজন নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰিবলৈ অনুমতি দিবনে ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>ক <xliff:g id="ACCOUNT">%2$s</xliff:g>ৰ জৰিয়তে এজন নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰিবলৈ অনুমতি দিবনে?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"নিৰীক্ষণত থকা ব্যৱহাৰকাৰী যোগ দিয়ক"</string>
<string name="language_selection_title" msgid="52674936078683285">"ভাষা যোগ কৰক"</string>
<string name="country_selection_title" msgid="5221495687299014379">"অঞ্চলৰ অগ্ৰাধিকাৰ"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ভাষাৰ নাম লিখক"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 1c93552..a11b68d 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Fərdi tətbiq bildirişi"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə <xliff:g id="ACCOUNT">%2$s</xliff:g> (artıq bu hesabı olan İstifadəçi mövcuddur) ilə yeni İstifadəçi yaratmağa icazə verilsin?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə <xliff:g id="ACCOUNT">%2$s</xliff:g> ilə yeni İstifadəçi yartmağa icazə verilsin?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Nəzarət edilən istifadəçi əlavə edin"</string>
<string name="language_selection_title" msgid="52674936078683285">"Dil əlavə edin"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Region seçimi"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Dil adını daxil edin"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 9241631..b8e0d9a 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -2021,6 +2021,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Prilagođeno obaveštenje o aplikaciji"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Želite li da dozvolite da <xliff:g id="APP">%1$s</xliff:g> napravi novog korisnika sa nalogom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik sa tim nalogom već postoji)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Želite li da dozvolite da <xliff:g id="APP">%1$s</xliff:g> napravi novog korisnika sa nalogom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Dodajte korisnika pod nadzorom"</string>
<string name="language_selection_title" msgid="52674936078683285">"Dodajte jezik"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Podešavanje regiona"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Unesite naziv jezika"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 849d53b..26d2e73 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -2053,6 +2053,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Апавяшчэнне пра карыстальніцкую праграму"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Дазволіць праграме \"<xliff:g id="APP">%1$s</xliff:g>\" стварыць новага Карыстальніка з уліковым запісам <xliff:g id="ACCOUNT">%2$s</xliff:g> (Карыстальнік з гэтым уліковым запісам ужо існуе)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Дазволіць праграме \"<xliff:g id="APP">%1$s</xliff:g>\" стварыць новага Карыстальніка з уліковым запісам <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Дадаць мову"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Параметры рэгіёна"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Увядзіце назву мовы"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index dad2f03..5250956 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Персонализирано известие за приложение"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Да се разреши ли на <xliff:g id="APP">%1$s</xliff:g> да създаде нов потребител с профила <xliff:g id="ACCOUNT">%2$s</xliff:g> (вече съществува потребител с този профил)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Да се разреши ли на <xliff:g id="APP">%1$s</xliff:g> да създаде нов потребител с профила <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Добавяне на контролиран потребител"</string>
<string name="language_selection_title" msgid="52674936078683285">"Добавяне на език"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Предпочитание за региона"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Въведете име на език"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index d560d5c..657596f 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"কাস্টম অ্যাপ বিজ্ঞপ্তি"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g>-এ (একজন ব্যবহারকারী এই অ্যাকাউন্টে আগে থেকেই রয়েছেন) একজন নতুন ব্যবহারকারী তৈরি করার অনুমতি <xliff:g id="APP">%1$s</xliff:g>-কে দেবেন?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g>-এ একজন নতুন ব্যবহারকারী তৈরি করার অনুমতি <xliff:g id="APP">%1$s</xliff:g>-কে দেবেন?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"একটি ভাষা যোগ করুন"</string>
<string name="country_selection_title" msgid="5221495687299014379">"পছন্দের অঞ্চল"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ভাষার নাম লিখুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 68ccf15..6e8cd97 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -331,19 +331,19 @@
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"pristupa podacima senzora o vašim vitalnim funkcijama"</string>
<string name="permgrouplab_notifications" msgid="5472972361980668884">"Obavještenja"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"prikaz obavještenja"</string>
- <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Preuzima sadržaj prozora"</string>
+ <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"preuzima sadržaj prozora"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Pregleda sadržaj prozora koji trenutno koristite."</string>
- <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Uključi opciju Istraživanje dodirom"</string>
+ <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"uključi opciju Istraživanje dodirom"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Stavke koje dodirnete bit će izgovorene naglas, a ekran možete istraživati koristeći pokrete."</string>
- <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Prati tekst koji unosite"</string>
+ <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"prati tekst koji unosite"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Obuhvata lične podatke kao što su brojevi kreditnih kartica i lozinke."</string>
- <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Kontrolira uvećavanje prikaza na ekranu"</string>
+ <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"kontrolira uvećavanje prikaza na ekranu"</string>
<string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Kontrolira stepen uvećanja prikaza na ekranu i podešavanje položaja."</string>
- <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Praviti pokrete"</string>
+ <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"izvodi pokrete"</string>
<string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Može dodirivati, prevlačiti, hvatati prstima i praviti druge pokrete."</string>
- <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Pokreti otiska prsta"</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"prepoznaje pokrete za otisak prsta"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Moguće je zabilježiti pokrete na senzoru za otisak prsta uređaja."</string>
- <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Snimanje ekrana"</string>
+ <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"pravi snimke ekrana"</string>
<string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Moguće je snimiti ekran."</string>
<string name="permlab_statusBar" msgid="8798267849526214017">"onemogućavanje ili mijenjanje statusne trake"</string>
<string name="permdesc_statusBar" msgid="5809162768651019642">"Dozvoljava aplikaciji onemogućavanje statusne trake ili dodavanje i uklanjanje sistemskih ikona."</string>
@@ -1920,7 +1920,7 @@
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je vaš administrator"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Uredu"</string>
<string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Ušteda baterije uključuje tamnu temu i ograničava ili isključuje aktivnost u pozadini, određene vizuelne efekte i funkcije te neke mrežne veze."</string>
- <string name="battery_saver_description" msgid="8518809702138617167">"Ušteda baterije uključuje Tamnu temu i ograničava ili isključuje aktivnost u pozadini, određene vizuelne efekte i funkcije te neke mrežne veze."</string>
+ <string name="battery_saver_description" msgid="8518809702138617167">"Ušteda baterije uključuje tamnu temu i ograničava ili isključuje aktivnost u pozadini, određene vizuelne efekte i funkcije te neke mrežne veze."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Radi smanjenja prijenosa podataka, Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali će to činiti rjeđe. Naprimjer, to može značiti da se slike ne prikazuju dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Uključiti Uštedu podataka?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Uključi"</string>
@@ -2021,6 +2021,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Prilagođeno obavještenje aplikacije"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Dozvoliti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da kreira novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik s ovim računom već postoji)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Dozvoliti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da kreira novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Dodaj korisnika pod nadzorom"</string>
<string name="language_selection_title" msgid="52674936078683285">"Dodajte jezik"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Izbor regije"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Upišite ime jezika"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 726bb3f..41af878 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificació d\'aplicació personalitzada"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Concedeixes permís a <xliff:g id="APP">%1$s</xliff:g> per crear un usuari amb el compte <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Ja hi ha un usuari amb aquest compte.)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Concedeixes permís a <xliff:g id="APP">%1$s</xliff:g> per crear un usuari amb el compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Afegeix un idioma"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferència de regió"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Escriu el nom de l\'idioma"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index abbcc2c..72ad45b 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -2053,6 +2053,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Vlastní oznámení aplikace"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> vytvořit nového uživatele s účtem <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Uživatel s tímto účtem již existuje.)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> vytvořit nového uživatele s účtem <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Přidat jazyk"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferovaná oblast"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Zadejte název jazyka"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 57673f4..8f4039f 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Tilpasset appnotifikation"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en ny bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g> (der findes allerede en bruger med denne konto)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en nye bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Tilføj et sprog"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Områdeindstilling"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Angiv sprog"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index fde9b0c..5e5e578 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Benutzerdefinierte App-Benachrichtigung"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Es gibt bereits einen Nutzer mit <xliff:g id="ACCOUNT">%2$s</xliff:g>. Möchtest du zulassen, dass <xliff:g id="APP">%1$s</xliff:g> einen neuen Nutzer mit diesem Konto erstellt?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Möchtest du zulassen, dass <xliff:g id="APP">%1$s</xliff:g> einen neuen Nutzer mit <xliff:g id="ACCOUNT">%2$s</xliff:g> erstellt?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Sprache hinzufügen"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Region auswählen"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Sprache eingeben"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index b0ad4da..f184200 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Προσαρμοσμένη ειδοποίηση εφαρμογής"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Επιτρέπετε στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να δημιουργήσει έναν νέο χρήστη με τον λογαριασμό <xliff:g id="ACCOUNT">%2$s</xliff:g> (υπάρχει ήδη χρήστης με αυτόν τον λογαριασμό);"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Επιτρέπετε στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να δημιουργήσει έναν νέο χρήστη με τον λογαριασμό <xliff:g id="ACCOUNT">%2$s</xliff:g>;"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Προσθήκη γλώσσας"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Προτίμηση περιοχής"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Εισαγ. όνομα γλώσσας"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index fd68ddd..2bf964b 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Custom app notification"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Add supervised user"</string>
<string name="language_selection_title" msgid="52674936078683285">"Add a language"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 265d2e6..b4d1c82 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Custom app notification"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Add supervised user"</string>
<string name="language_selection_title" msgid="52674936078683285">"Add a language"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 8ee21a3..e47a2c2 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Custom app notification"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Add supervised user"</string>
<string name="language_selection_title" msgid="52674936078683285">"Add a language"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 7fada24..2108367 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Custom app notification"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Add supervised user"</string>
<string name="language_selection_title" msgid="52674936078683285">"Add a language"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 0eaf8ef..68b1de3 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Custom app notification"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Add supervised user"</string>
<string name="language_selection_title" msgid="52674936078683285">"Add a language"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 93a316f..517ee57 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -325,7 +325,7 @@
<string name="permgrouplab_phone" msgid="570318944091926620">"Teléfono"</string>
<string name="permgroupdesc_phone" msgid="270048070781478204">"hacer y administrar llamadas telefónicas"</string>
<string name="permgrouplab_sensors" msgid="9134046949784064495">"Sensores corporales"</string>
- <string name="permgroupdesc_sensors" msgid="2610631290633747752">"acceder a los datos del sensor acerca de tus signos vitales"</string>
+ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"acceder a los datos de sensores acerca de tus signos vitales"</string>
<string name="permgrouplab_notifications" msgid="5472972361980668884">"Notificaciones"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"mostrar notificaciones"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Recuperar el contenido de las ventanas"</string>
@@ -733,8 +733,8 @@
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Permite que el propietario inicie el uso de permisos para una app. No debería requerirse para apps normales."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"iniciar vista de funciones de la app"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permite que el propietario vea la información de las funciones de una app."</string>
- <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"Acceder a los datos del sensor a una tasa de muestreo alta"</string>
- <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Permite que la app tome una muestra de los datos del sensor a una tasa superior a 200 Hz"</string>
+ <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"Acceder a los datos de sensores a una tasa de muestreo alta"</string>
+ <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Permite que la app tome una muestra de los datos de sensores a una tasa superior a 200 Hz"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"Establecer reglas de contraseña"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"Controlar la longitud y los caracteres permitidos en las contraseñas y los PIN para el bloqueo de pantalla."</string>
<string name="policylab_watchLogin" msgid="7599669460083719504">"Supervisa los intentos para desbloquear la pantalla"</string>
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificación de app personalizada"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"¿Quieres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario nuevo con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Ya existe un usuario con esta cuenta)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"¿Deseas permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario nuevo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Agregar un idioma"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferencia de región"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Nombre del idioma"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 22de5d1..b58d116 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificación de aplicación personalizada"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"¿Permitir que <xliff:g id="APP">%1$s</xliff:g> cree otro usuario con la cuenta <xliff:g id="ACCOUNT">%2$s</xliff:g>, que ya tiene uno?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"¿Permitir que <xliff:g id="APP">%1$s</xliff:g> cree otro usuario con la cuenta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Añadir un idioma"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferencia de región"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Nombre de idioma"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 334a666..3afe63dd 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Rakenduse kohandatud märguanne"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Kas lubada rakendusel <xliff:g id="APP">%1$s</xliff:g> luua uus kasutaja kontoga <xliff:g id="ACCOUNT">%2$s</xliff:g> (selle kontoga kasutaja on juba olemas)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Kas lubada rakendusel <xliff:g id="APP">%1$s</xliff:g> luua uus kasutaja kontoga <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Keele lisamine"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Piirkonnaeelistus"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Sisestage keele nimi"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index df16b73..b4b4ec2 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Aplikazio-jakinarazpen pertsonalizatua"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzeko baimena eman nahi diozu <xliff:g id="APP">%1$s</xliff:g> aplikazioari? (Badago kontu hori duen erabiltzaile bat)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzeko baimena eman nahi diozu <xliff:g id="APP">%1$s</xliff:g> aplikazioari?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Gehitu gainbegiratutako erabiltzaile bat"</string>
<string name="language_selection_title" msgid="52674936078683285">"Gehitu hizkuntza bat"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Lurralde-hobespena"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Adierazi hizkuntza"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index e66c783..b8f2673 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"اعلان برنامه سفارشی"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"به<xliff:g id="APP">%1$s</xliff:g> اجازه میدهید با <xliff:g id="ACCOUNT">%2$s</xliff:g> (کاربری با این حساب درحالحاضر وجود دارد) کاربری جدید ایجاد کند؟"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"به <xliff:g id="APP">%1$s</xliff:g> اجازه میدهید با <xliff:g id="ACCOUNT">%2$s</xliff:g> کاربری جدید ایجاد کند؟"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"افزودن زبان"</string>
<string name="country_selection_title" msgid="5221495687299014379">"اولویتهای منطقه"</string>
<string name="search_language_hint" msgid="7004225294308793583">"نام زبان را تایپ کنید"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index ff17fc1..618cd52 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Oma sovellusilmoitus"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Saako <xliff:g id="APP">%1$s</xliff:g> luoda uuden käyttäjän (<xliff:g id="ACCOUNT">%2$s</xliff:g>) – tällä käyttäjällä on jo tili?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Saako <xliff:g id="APP">%1$s</xliff:g> luoda uuden käyttäjän (<xliff:g id="ACCOUNT">%2$s</xliff:g>)?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Lisää kieli"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Alueasetus"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Anna kielen nimi"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index e367f32..4cc5c14 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -624,8 +624,7 @@
<string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Touchez pour supprimer votre modèle facial, puis ajoutez votre visage de nouveau"</string>
<string name="face_setup_notification_title" msgid="8843461561970741790">"Configurer le déverrouillage par reconnaissance faciale"</string>
<string name="face_setup_notification_content" msgid="5463999831057751676">"Déverrouillez votre téléphone en le regardant"</string>
- <!-- no translation found for face_sensor_privacy_enabled (7407126963510598508) -->
- <skip />
+ <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Pour utiliser le déverrouillage par reconnaissance faciale, activez l\'"<b>"accès à l\'appareil photo"</b>" dans Paramètres > Confidentialité"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configurer d\'autres méthodes de déverrouillage"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Touchez pour ajouter une empreinte digitale"</string>
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Déverrouillage par empreinte digitale"</string>
@@ -1990,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notification d\'application personnalisée"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un utilisateur <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Un utilisateur est déjà associé à ce compte)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil d\'utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Ajouter une langue"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Préférences régionales"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Entrez la langue"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index e00304b..19adf8a 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notification d\'application personnalisée"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g> (un utilisateur associé à ce compte existe déjà) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Ajouter une langue"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Préférences régionales"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Saisissez la langue"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 6f9ee8f..a61ef81 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificación de aplicacións personalizada"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Xa existe un usuario con esta conta)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Engadir usuario supervisado"</string>
<string name="language_selection_title" msgid="52674936078683285">"Engadir un idioma"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferencia de rexión"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Escribe o nome do idioma"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 533d3fb..9971033 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"ઍપનું કસ્ટમ નોટિફિકેશન"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>ને <xliff:g id="ACCOUNT">%2$s</xliff:g> માટે એક નવા વપરાશકર્તા બનાવવાની મંજૂરી આપીએ (આ એકાઉન્ટ માટે એક વપરાશકર્તા પહેલાંથી અસ્તિત્વમાં છે) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>ને <xliff:g id="ACCOUNT">%2$s</xliff:g> માટે એક નવા વપરાશકર્તા બનાવવાની મંજૂરી આપીએ ?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"ભાષા ઉમેરો"</string>
<string name="country_selection_title" msgid="5221495687299014379">"પ્રદેશ પસંદગી"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ભાષાનું નામ ટાઇપ કરો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 8459437..a30c9a9 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"ऐप्लिकेशन की सूचना पसंद के मुताबिक बनाएं"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> को <xliff:g id="ACCOUNT">%2$s</xliff:g> के नाम से एक नया उपयोगकर्ता बनाने की अनुमति दें (इस नाम से एक खाता पहले से मौजूद है)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"निगरानी में रखा गया उपयोगकर्ता जोड़ें"</string>
<string name="language_selection_title" msgid="52674936078683285">"भाषा जोड़ें"</string>
<string name="country_selection_title" msgid="5221495687299014379">"क्षेत्र प्राथमिकता"</string>
<string name="search_language_hint" msgid="7004225294308793583">"भाषा का नाम लिखें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 69905ec..6afc049 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -2021,6 +2021,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Prilagođena obavijest aplikacije"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Dopustiti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da izradi novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik s ovim računom već postoji)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Dopustiti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da izradi novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Dodaj nadziranog korisnika"</string>
<string name="language_selection_title" msgid="52674936078683285">"Dodavanje jezika"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Postavke regije"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Unesite naziv jezika"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 4f04016..c736246 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Egyéni alkalmazásértesítés"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> számára, hogy új felhasználót hozzon létre a(z) <xliff:g id="ACCOUNT">%2$s</xliff:g> fiókkal? (Már létezik felhasználó ezzel a fiókkal.)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> számára, hogy új felhasználót hozzon létre a(z) <xliff:g id="ACCOUNT">%2$s</xliff:g> fiókkal?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Felügyelt felhasználó hozzáadása"</string>
<string name="language_selection_title" msgid="52674936078683285">"Nyelv hozzáadása"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Régió beállítása"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Adja meg a nyelvet"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 141780e..4f8f8e8 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Հավելվածի հատուկ ծանուցում"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Թույլատրե՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտատեր ստեղծել (նման հաշվով Օգտատեր արդեն գոյություն ունի):"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Թույլատրե՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտատեր ստեղծել:"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Ավելացնել վերահսկվող օգտատեր"</string>
<string name="language_selection_title" msgid="52674936078683285">"Ավելացնել լեզու"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Նախընտրելի տարածաշրջան"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Մուտքագրեք լեզուն"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index e1e8ea9..1457450 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notifikasi aplikasi kustom"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Izinkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baru dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> (Pengguna dengan akun ini sudah ada) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Izinkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baru dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Tambahkan bahasa"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferensi wilayah"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Ketik nama bahasa"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 0678ab2..cd28dc9 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Sérsniðin forritatilkynning"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Viltu leyfa <xliff:g id="APP">%1$s</xliff:g> að stofna nýjan notanda með <xliff:g id="ACCOUNT">%2$s</xliff:g> (notandi með þennan reikning er þegar fyrir hendi)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Leyfa <xliff:g id="APP">%1$s</xliff:g> að stofna nýjan notanda með <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Bæta við tungumáli"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Svæðisval"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Sláðu inn heiti tungumáls"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index a63fbd8..6571f23 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notifica app personalizzata"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Consentire a <xliff:g id="APP">%1$s</xliff:g> di creare un nuovo utente con l\'account <xliff:g id="ACCOUNT">%2$s</xliff:g> (esiste già un utente con questo account)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Consentire a <xliff:g id="APP">%1$s</xliff:g> di creare un nuovo utente con l\'account <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Aggiungi utente supervisionato"</string>
<string name="language_selection_title" msgid="52674936078683285">"Aggiungi una lingua"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Area geografica preferita"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Digita nome lingua"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 7a594d8..4214bc2 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -2053,6 +2053,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"התראות אפליקציה בהתאמה אישית"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"האם לאפשר לאפליקציה <xliff:g id="APP">%1$s</xliff:g> ליצור משתמש חדש באמצעות <xliff:g id="ACCOUNT">%2$s</xliff:g> (כבר קיים משתמש לחשבון הזה)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"לאפשר לאפליקציה <xliff:g id="APP">%1$s</xliff:g> ליצור משתמש חדש באמצעות <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"הוספת שפה"</string>
<string name="country_selection_title" msgid="5221495687299014379">"העדפת אזור"</string>
<string name="search_language_hint" msgid="7004225294308793583">"יש להקליד את שם השפה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 241105f..7a6b566 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"カスタムアプリ通知"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> が <xliff:g id="ACCOUNT">%2$s</xliff:g> で新しいユーザーを作成できるようにしますか?(このアカウントのユーザーはすでに存在します)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> が <xliff:g id="ACCOUNT">%2$s</xliff:g> で新しいユーザーを作成できるようにしますか?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"監視対象ユーザーを追加"</string>
<string name="language_selection_title" msgid="52674936078683285">"言語を追加"</string>
<string name="country_selection_title" msgid="5221495687299014379">"地域設定"</string>
<string name="search_language_hint" msgid="7004225294308793583">"言語名を入力"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 2137e0f..6ab9312 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"აპის მორგებული შეტყობინება"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"მიეცეს უფლება <xliff:g id="APP">%1$s</xliff:g>-ს <xliff:g id="ACCOUNT">%2$s</xliff:g>-ის მეშვეობით ახალი მომხმარებელი შექმნას (ამ ანგარიშის მქონე მომხმარებელი უკვე არსებობს)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"მიეცეს უფლება <xliff:g id="APP">%1$s</xliff:g>-ს <xliff:g id="ACCOUNT">%2$s</xliff:g>-ის მეშვეობით ახალი მომხმარებელი შექმნას?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"კონტროლის ქვეშ მყოფი მომხმარებლის დამატება"</string>
<string name="language_selection_title" msgid="52674936078683285">"ენის დამატება"</string>
<string name="country_selection_title" msgid="5221495687299014379">"რეგიონის პარამეტრები"</string>
<string name="search_language_hint" msgid="7004225294308793583">"აკრიფეთ ენის სახელი"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 3042c64..b231be1 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Арнаулы хабар хабарландыруы"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунты бар жаңа пайдаланушы (мұндай аккаунтқа ие пайдаланушы бұрыннан бар) жасауға рұқсат етілсін бе?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунты бар жаңа пайдаланушы жасауға рұқсат етілсін бе?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Тіл қосу"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Аймақ параметрі"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Тіл атауын теріңіз"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 81fbca5..6d72625 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"ការជូនដំណឹងកម្មវិធីផ្ទាល់ខ្លួន"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"អនុញ្ញាតឱ្យ <xliff:g id="APP">%1$s</xliff:g> បង្កើតអ្នកប្រើប្រាស់ថ្មីដោយប្រើ <xliff:g id="ACCOUNT">%2$s</xliff:g> (អ្នកប្រើប្រាស់ដែលមានគណនីនេះមានរួចហើយ) ដែរឬទេ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"អនុញ្ញាតឱ្យ <xliff:g id="APP">%1$s</xliff:g> បង្កើតអ្នកប្រើប្រាស់ថ្មីដោយប្រើ <xliff:g id="ACCOUNT">%2$s</xliff:g> ដែរឬទេ?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"បញ្ចូលអ្នកប្រើប្រាស់ដែលស្ថិតក្រោមការគ្រប់គ្រង"</string>
<string name="language_selection_title" msgid="52674936078683285">"បន្ថែមភាសា"</string>
<string name="country_selection_title" msgid="5221495687299014379">"ចំណូលចិត្តតំបន់"</string>
<string name="search_language_hint" msgid="7004225294308793583">"វាយបញ្ចូលឈ្មោះភាសា"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 569f6a5..5ec2013 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"ಕಸ್ಟಮ್ ಆ್ಯಪ್ ಅಧಿಸೂಚನೆ"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> (ಈ ಖಾತೆಯ ಬಳಕೆದಾರರು ಈಗಾಗಲೇ ಅಸ್ತಿತ್ವದಲ್ಲಿದ್ದಾರೆ) ಮೂಲಕ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು <xliff:g id="APP">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಬೇಕೆ ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> ಮೂಲಕ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು <xliff:g id="APP">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸುವುದೇ ?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"ಭಾಷೆ ಸೇರಿಸಿ"</string>
<string name="country_selection_title" msgid="5221495687299014379">"ಪ್ರದೇಶ ಪ್ರಾಶಸ್ತ್ಯ"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ಭಾಷೆ ಹೆಸರನ್ನು ಟೈಪ್ ಮಾಡಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 01d040f..3b58e62 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"맞춤 앱 알림"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>에서 <xliff:g id="ACCOUNT">%2$s</xliff:g> 계정으로 신규 사용자를 만들도록 허용하시겠습니까? 이 계정으로 등록된 사용자가 이미 존재합니다."</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>에서 <xliff:g id="ACCOUNT">%2$s</xliff:g> 계정으로 신규 사용자를 만들도록 허용하시겠습니까?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"언어 추가"</string>
<string name="country_selection_title" msgid="5221495687299014379">"지역 환경설정"</string>
<string name="search_language_hint" msgid="7004225294308793583">"언어 이름 입력"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index e153773..ab2ab9b 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Колдонмонун ыңгайлаштырылган билдирмеси"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> колдонмосуна <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунту менен жаңы колдонуучу түзүүгө уруксат бересизби (мындай аккаунту бар колдонуучу мурунтан эле бар)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> колдонмосуна <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунту менен жаңы колдонуучу түзүүгө уруксат бересизби?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Көзөмөлдөнгөн колдонуучуну кошуу"</string>
<string name="language_selection_title" msgid="52674936078683285">"Тил кошуу"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Чөлкөмдүк жөндөөлөр"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Тилди киргизиңиз"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index b3cb5af..2018524 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"ການແຈ້ງເຕືອນແອັບແບບກຳນົດເອງ"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"ອະນຸຍາດໃຫ້ <xliff:g id="APP">%1$s</xliff:g> ສ້າງຜູ້ໃຊ້ໃໝ່ກັບ <xliff:g id="ACCOUNT">%2$s</xliff:g> ໄດ້ບໍ່ (ມີຜູ້ໃຊ້ທີ່ໃຊ້ບັນຊີນີ້ຢູ່ກ່ອນແລ້ວ) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"ອະນຸຍາດໃຫ້ <xliff:g id="APP">%1$s</xliff:g> ສ້າງຜູ້ໃຊ້ໃໝ່ກັບ <xliff:g id="ACCOUNT">%2$s</xliff:g> ໄດ້ບໍ?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"ເພີ່ມພາສາ"</string>
<string name="country_selection_title" msgid="5221495687299014379">"ການຕັ້ງຄ່າພາກພື້ນ"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ພິມຊື່ພາສາ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 70f0f42..aea67f2 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -2053,6 +2053,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Tinkintas programos pranešimas"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją (šią paskyrą naudojantis naudotojas jau yra)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Pridėti prižiūrimą naudotoją"</string>
<string name="language_selection_title" msgid="52674936078683285">"Pridėkite kalbą"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Regiono nuostata"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Įveskite kalbos pav."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 1df7774..495bc38 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -2021,6 +2021,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Pielāgots lietotnes paziņojums"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Vai atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> izveidot jaunu lietotāju, izmantojot e-pasta adresi <xliff:g id="ACCOUNT">%2$s</xliff:g> (lietotājs ar šādu kontu jau pastāv)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Vai atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> izveidot jaunu lietotāju, izmantojot e-pasta adresi <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Pievienot valodu"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Reģiona preference"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Ierakstiet valodas nosaukumu"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index cc86005..92e1d5f 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Приспособено известување за апликација"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Дозволувате <xliff:g id="APP">%1$s</xliff:g> да создаде нов корисник со <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Веќе постои корисник со оваа сметка.)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Дозволувате <xliff:g id="APP">%1$s</xliff:g> да создаде нов корисник со <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Додајте надгледуван корисник"</string>
<string name="language_selection_title" msgid="52674936078683285">"Додајте јазик"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Претпочитувања за регион"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Внесете име на јазик"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 2517704..0d76eae 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"ഇഷ്ടാനുസൃത ആപ്പ് അറിയിപ്പുകൾ"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> എന്ന അക്കൗണ്ട് (ഈ അക്കൗണ്ട് ഉപയോഗിക്കുന്ന ഒരു ഉപയോക്താവ് നിലവിലുണ്ട്) ഉപയോഗിച്ച് പുതിയ ഉപയോക്താവിനെ സൃഷ്ടിക്കാൻ <xliff:g id="APP">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കണോ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> എന്ന അക്കൗണ്ട് ഉപയോഗിച്ച് പുതിയ ഉപയോക്താവിനെ സൃഷ്ടിക്കാൻ <xliff:g id="APP">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കണോ?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"മേൽനോട്ടത്തിലുള്ള ഉപയോക്താവിനെ ചേർക്കൂ"</string>
<string name="language_selection_title" msgid="52674936078683285">"ഒരു ഭാഷ ചേർക്കുക"</string>
<string name="country_selection_title" msgid="5221495687299014379">"മേഖലാ മുൻഗണന"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ഭാഷ ടൈപ്പ് ചെയ്യുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 6be8243..24cad85 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Аппын захиалгат мэдэгдэл"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>-д <xliff:g id="ACCOUNT">%2$s</xliff:g>-тай (ийм бүртгэлтэй хэрэглэгч аль хэдийн байна) шинэ хэрэглэгч үүсгэхийг зөвшөөрөх үү ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>-д <xliff:g id="ACCOUNT">%2$s</xliff:g>-тай шинэ хэрэглэгч үүсгэхийг зөвшөөрөх үү?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Хяналттай хэрэглэгч нэмэх"</string>
<string name="language_selection_title" msgid="52674936078683285">"Хэл нэмэх"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Бүс нутгийн тохиргоо"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Улсын хэлийг бичнэ үү"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 69279ee..162b4ae 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"कस्टम ॲप सूचना"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सह नवीन वापरकर्ता तयार करण्याची (हे खाते असलेला वापरकर्ता आधीपासून अस्तित्वात आहे) <xliff:g id="APP">%1$s</xliff:g> ला अनुमती द्यायची आहे का?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सह नवीन वापरकर्ता तयार करण्याची <xliff:g id="APP">%1$s</xliff:g> ला अनुमती द्यायची आहे का?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"व्यवस्थापित वापरकर्ता जोडा"</string>
<string name="language_selection_title" msgid="52674936078683285">"एक भाषा जोडा"</string>
<string name="country_selection_title" msgid="5221495687299014379">"प्रदेश प्राधान्य"</string>
<string name="search_language_hint" msgid="7004225294308793583">"भाषा नाव टाइप करा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 27aac1a..4a50bc9 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Pemberitahuan apl tersuai"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Benarkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baharu dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> (Pengguna dengan akaun ini sudah wujud) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Benarkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baharu dengan <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Tambahkan bahasa"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Pilihan wilayah"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Taipkan nama bahasa"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index eefbe15..169c0fd 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"စိတ်ကြိုက်အက်ပ် အကြောင်းကြားချက်"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> ဖြင့်အသုံးပြုသူအသစ်ကို <xliff:g id="APP">%1$s</xliff:g> အား ဖန်တီးခွင့်ပြုလိုပါသလား (ဤအကောင့်ဖြင့် အသုံးပြုသူ ရှိနှင့်ပြီးဖြစ်သည်) ။"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> ဖြင့်အသုံးပြုသူအသစ်ကို <xliff:g id="APP">%1$s</xliff:g> အား ဖန်တီးခွင့်ပြုလိုပါသလား ။"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"ဘာသာစကားတစ်ခု ထည့်ပါ"</string>
<string name="country_selection_title" msgid="5221495687299014379">"ဒေသရွေးချယ်မှု"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ဘာသာစကားအမည် ထည့်ပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 4d8d2b0..7c5ae01 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Tilpasset appvarsel"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Vil du la <xliff:g id="APP">%1$s</xliff:g> opprette en ny bruker med <xliff:g id="ACCOUNT">%2$s</xliff:g> (en bruker med denne kontoen eksisterer allerede)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Vil du la <xliff:g id="APP">%1$s</xliff:g> opprette en ny bruker med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Legg til et språk"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Regionsinnstilling"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Skriv inn språknavn"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 12c4464..7f9a832 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"एपसम्बन्धी आफ्नो रोजाइअनुसारको सूचना"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> (यस खाताको प्रयोगकर्ता पहिले नै अवस्थित छ) मा नयाँ प्रयोगकर्ता सिर्जना गर्न <xliff:g id="APP">%1$s</xliff:g> लाई अनुमति दिने हो?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> मा नयाँ प्रयोगकर्ता सिर्जना गर्न <xliff:g id="APP">%1$s</xliff:g> लाई अनुमति दिने हो?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"सुपरिवेक्षित प्रयोगकर्ता हाल्नुहोस्"</string>
<string name="language_selection_title" msgid="52674936078683285">"भाषा थप्नुहोस्"</string>
<string name="country_selection_title" msgid="5221495687299014379">"क्षेत्रको प्राथमिकता"</string>
<string name="search_language_hint" msgid="7004225294308793583">"भाषाको नाम टाइप गर्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 858ca00..5dcdda4 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -37,7 +37,7 @@
<string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Kan instellingen voor doorschakelen van gesprekken niet wijzigen vanaf je telefoon tijdens roaming."</string>
<string name="serviceEnabled" msgid="7549025003394765639">"Service staat aan."</string>
<string name="serviceEnabledFor" msgid="1463104778656711613">"Service staat aan voor:"</string>
- <string name="serviceDisabled" msgid="641878791205871379">"Service staat uit."</string>
+ <string name="serviceDisabled" msgid="641878791205871379">"Service is uitgezet."</string>
<string name="serviceRegistered" msgid="3856192211729577482">"De registratie is voltooid."</string>
<string name="serviceErased" msgid="997354043770513494">"Wissen uitgevoerd."</string>
<string name="passwordIncorrect" msgid="917087532676155877">"Onjuist wachtwoord."</string>
@@ -1733,7 +1733,7 @@
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tik op een functie om deze te gebruiken:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Functies kiezen voor gebruik met de knop Toegankelijkheid"</string>
<string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Functies kiezen voor gebruik met de sneltoets via de volumeknop"</string>
- <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> staat uit"</string>
+ <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> is uitgezet"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Snelkoppelingen bewerken"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Klaar"</string>
<string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Sneltoets uitzetten"</string>
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Aangepaste app-melding"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Toestaan dat <xliff:g id="APP">%1$s</xliff:g> een nieuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> maakt (er is al een gebruiker met dit account)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Toestaan dat <xliff:g id="APP">%1$s</xliff:g> een nieuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> maakt?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Gebr. met beperkte rechten maken"</string>
<string name="language_selection_title" msgid="52674936078683285">"Taal toevoegen"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Regiovoorkeur"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Typ de naam van een taal"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 52015c2..919d193 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"କଷ୍ଟମ୍ ଆପ୍ ବିଜ୍ଞପ୍ତି"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>ରେ ଏକ ନୂଆ ଉପଯୋଗକର୍ତ୍ତା ତିଆରି କରିବା ପାଇଁ <xliff:g id="ACCOUNT">%2$s</xliff:g>କୁ (ପୂର୍ବରୁ ଏହି ଆକାଉଣ୍ଟ ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ନାମରେ ଅଛି) ଅନୁମତି ଦେବେ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>ରେ ଏକ ନୂଆ ଉପଯୋଗକର୍ତ୍ତା ତିଆରି କରିବା ପାଇଁ <xliff:g id="ACCOUNT">%2$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"ଏକ ଭାଷା ଯୋଗ କରନ୍ତୁ"</string>
<string name="country_selection_title" msgid="5221495687299014379">"ପସନ୍ଦର ଅଞ୍ଚଳ"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ଭାଷାର ନାମ ଟାଇପ୍ କରନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 6826a2d..c628f1f 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"ਵਿਉਂਤੀ ਐਪ ਸੂਚਨਾ"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"ਕੀ <xliff:g id="APP">%1$s</xliff:g> ਨੂੰ <xliff:g id="ACCOUNT">%2$s</xliff:g> ਨਾਲ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਉਣ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣੀ ਹੈ (ਇਸ ਖਾਤੇ ਨਾਲ ਇੱਕ ਵਰਤੋਂਕਾਰ ਪਹਿਲਾਂ ਤੋਂ ਹੀ ਮੌਜੂਦ ਹੈ)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"ਕੀ <xliff:g id="APP">%1$s</xliff:g> ਨੂੰ <xliff:g id="ACCOUNT">%2$s</xliff:g> ਨਾਲ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਉਣ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣੀ ਹੈ?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"ਨਿਗਰਾਨੀ ਕੀਤਾ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="language_selection_title" msgid="52674936078683285">"ਇੱਕ ਭਾਸ਼ਾ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="country_selection_title" msgid="5221495687299014379">"ਖੇਤਰ ਤਰਜੀਹ"</string>
<string name="search_language_hint" msgid="7004225294308793583">"ਭਾਸ਼ਾ ਦਾ ਨਾਮ ਟਾਈਪ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index e16d2af..6689a1a 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -2053,6 +2053,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Niestandardowe powiadomienie z aplikacji"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Zezwolić aplikacji <xliff:g id="APP">%1$s</xliff:g> na utworzenie nowego użytkownika dla konta <xliff:g id="ACCOUNT">%2$s</xliff:g> (użytkownik dla tego konta już istnieje)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Zezwolić aplikacji <xliff:g id="APP">%1$s</xliff:g> na utworzenie nowego użytkownika dla konta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Dodaj język"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Ustawienie regionu"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Wpisz nazwę języka"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 52d7992..e2bd6c5 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificação personalizada do app"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um usuário com essa conta)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Adicionar usuário supervisionado"</string>
<string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Digitar nome do idioma"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 2ea9f39..1daf451 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificação de app personalizada"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Permitir que a app <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um utilizador com esta conta)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Permitir que a app <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Intr. nome do idioma"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 52d7992..e2bd6c5 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificação personalizada do app"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um usuário com essa conta)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Adicionar usuário supervisionado"</string>
<string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Digitar nome do idioma"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index ac5eca7..035d1eb 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -2021,6 +2021,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificare de aplicație personalizată"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Permiteți ca <xliff:g id="APP">%1$s</xliff:g> să creeze un nou utilizator folosind <xliff:g id="ACCOUNT">%2$s</xliff:g>? (există deja un utilizator cu acest cont)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Permiteți ca <xliff:g id="APP">%1$s</xliff:g> să creeze un nou utilizator folosind <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Adăugați un utilizator monitorizat"</string>
<string name="language_selection_title" msgid="52674936078683285">"Adăugați o limbă"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Regiunea preferată"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Numele limbii"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 6182832..1b64a3b 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -2053,6 +2053,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Уведомление пользовательского приложения"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" создать нового пользователя с аккаунтом <xliff:g id="ACCOUNT">%2$s</xliff:g> (пользователь с этим аккаунтом уже существует)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" создать нового пользователя с аккаунтом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Добавить язык"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Региональные настройки"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Введите название языка"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index c5e76c8..cf7fc87 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"අභිරුචි යෙදුම් දැනුම් දීම"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> හට <xliff:g id="ACCOUNT">%2$s</xliff:g> සමගින් නව පරිශීලකයෙකු සෑදීමට ඉඩ දෙන්නද (මෙම ගිණුම සහිත පරිශීලකයෙකු දැනටමත් සිටී) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> හට <xliff:g id="ACCOUNT">%2$s</xliff:g> සමගින් නව පරිශීලකයෙකු සෑදීමට ඉඩ දෙන්නද ?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"භාෂාවක් එක් කරන්න"</string>
<string name="country_selection_title" msgid="5221495687299014379">"ප්රදේශ මනාපය"</string>
<string name="search_language_hint" msgid="7004225294308793583">"භාෂා නම ටයිප් කරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index dfd34e7..c6423dc 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -2053,6 +2053,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Vlastné upozornenie na aplikáciu"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Chcete povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> vytvoriť nového používateľa pomocou účtu <xliff:g id="ACCOUNT">%2$s</xliff:g> (používateľ s týmto účtom už existuje)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Chcete povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> vytvoriť nového používateľa pomocou účtu <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Pridať jazyk"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferovaný región"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Zadajte názov jazyka"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 931fc5b..1e8f264 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -2053,6 +2053,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Obvestilo po meri iz aplikacije"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Ali aplikaciji <xliff:g id="APP">%1$s</xliff:g> dovolite, da ustvari novega uporabnika za račun <xliff:g id="ACCOUNT">%2$s</xliff:g> (uporabnik s tem računom že obstaja)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Ali aplikaciji <xliff:g id="APP">%1$s</xliff:g> dovolite, da ustvari novega uporabnika za račun <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Dodaj nadzorovanega uporabnika"</string>
<string name="language_selection_title" msgid="52674936078683285">"Dodajanje jezika"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Nastavitev območja"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Vnesite ime jezika"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 937332b..705e309 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Njoftim i personalizuar për aplikacionin"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Të lejohet <xliff:g id="APP">%1$s</xliff:g> që të krijojë një përdorues të ri me <xliff:g id="ACCOUNT">%2$s</xliff:g> (një përdorues me këtë llogari ekziston tashmë) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Të lejohet <xliff:g id="APP">%1$s</xliff:g> që të krijojë një përdorues të ri me <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Shto një gjuhë"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Preferenca e rajonit"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Shkruaj emrin e gjuhës"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 72fd908..dde0e33 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -2021,6 +2021,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Прилагођено обавештење о апликацији"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Желите ли да дозволите да <xliff:g id="APP">%1$s</xliff:g> направи новог корисника са налогом <xliff:g id="ACCOUNT">%2$s</xliff:g> (корисник са тим налогом већ постоји)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Желите ли да дозволите да <xliff:g id="APP">%1$s</xliff:g> направи новог корисника са налогом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Додајте корисника под надзором"</string>
<string name="language_selection_title" msgid="52674936078683285">"Додајте језик"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Подешавање региона"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Унесите назив језика"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index e078da0..2003e64 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Anpassad appavisering"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Tillåter du att <xliff:g id="APP">%1$s</xliff:g> skapar en ny användare för <xliff:g id="ACCOUNT">%2$s</xliff:g> (det finns redan en användare med det här kontot)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Tillåter du att <xliff:g id="APP">%1$s</xliff:g> skapar en ny användare för <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Lägg till en kontrollerad användare"</string>
<string name="language_selection_title" msgid="52674936078683285">"Lägg till ett språk"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Regionsinställningar"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Ange språk"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 99fd107..f955203 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Arifa ya programu maalum"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Ruhusu <xliff:g id="APP">%1$s</xliff:g> iweke Mtumiaji mpya ikitumia <xliff:g id="ACCOUNT">%2$s</xliff:g> (Je, tayari kuna mtumiaji anayetumia akaunti hii)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Ungependa kuruhusu <xliff:g id="APP">%1$s</xliff:g> iweke Mtumiaji mpya ikitumia <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Weka mtumiaji anayesimamiwa"</string>
<string name="language_selection_title" msgid="52674936078683285">"Ongeza lugha"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Mapendeleo ya eneo"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Weka jina la lugha"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 0be25cd..a7296dc 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -170,7 +170,7 @@
<string name="httpErrorFailedSslHandshake" msgid="546319061228876290">"பாதுகாப்பான இணைப்பை நிறுவ முடியவில்லை."</string>
<string name="httpErrorBadUrl" msgid="754447723314832538">"URL தவறாக உள்ளதால் பக்கத்தைத் திறக்க முடியவில்லை."</string>
<string name="httpErrorFile" msgid="3400658466057744084">"ஃபைலை அணுக முடியவில்லை."</string>
- <string name="httpErrorFileNotFound" msgid="5191433324871147386">"கோரப்பட்ட கோப்பைக் கண்டறிய முடியவில்லை."</string>
+ <string name="httpErrorFileNotFound" msgid="5191433324871147386">"கோரப்பட்ட ஃபைலைக் கண்டறிய முடியவில்லை."</string>
<string name="httpErrorTooManyRequests" msgid="2149677715552037198">"மிக அதிகமான கோரிக்கைகள் செயல்படுத்தப்படுகின்றன. பிறகு முயற்சிக்கவும்."</string>
<string name="notification_title" msgid="5783748077084481121">"<xliff:g id="ACCOUNT">%1$s</xliff:g> க்கான உள்நுழைவு பிழை"</string>
<string name="contentServiceSync" msgid="2341041749565687871">"ஒத்திசை"</string>
@@ -1526,8 +1526,8 @@
<string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"எப்போதும் இயக்கத்தில் இருக்கும்படி அமைத்த VPN இலிருந்து துண்டிக்கப்பட்டது"</string>
<string name="vpn_lockdown_error" msgid="4453048646854247947">"எப்போதும் ஆனில் இருக்கும்படி அமைத்த VPN உடன் இணைக்க முடியவில்லை"</string>
<string name="vpn_lockdown_config" msgid="8331697329868252169">"நெட்வொர்க் அல்லது VPN அமைப்புகளை மாற்றவும்"</string>
- <string name="upload_file" msgid="8651942222301634271">"கோப்பைத் தேர்வுசெய்"</string>
- <string name="no_file_chosen" msgid="4146295695162318057">"எந்தக் கோப்பும் தேர்வுசெய்யப்படவில்லை"</string>
+ <string name="upload_file" msgid="8651942222301634271">"ஃபலைத் தேர்வுசெய்"</string>
+ <string name="no_file_chosen" msgid="4146295695162318057">"எந்த ஃபைலும் தேர்வுசெய்யப்படவில்லை"</string>
<string name="reset" msgid="3865826612628171429">"மீட்டமை"</string>
<string name="submit" msgid="862795280643405865">"சமர்ப்பி"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"\'வாகனம் ஓட்டும் பயன்முறை’ ஆனில் உள்ளது"</string>
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"பிரத்தியேக ஆப்ஸ் அறிவிப்பு"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> மூலம் புதிய பயனரை உருவாக்க <xliff:g id="APP">%1$s</xliff:g> ஆப்ஸை அனுமதிக்கவா (இந்தக் கணக்கில் ஏற்கெனவே ஒரு பயனர் உள்ளார்) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> மூலம் புதிய பயனரை உருவாக்க <xliff:g id="APP">%1$s</xliff:g> ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"மேற்பார்வையிடப்படும் பயனரைச் சேர்"</string>
<string name="language_selection_title" msgid="52674936078683285">"மொழியைச் சேர்"</string>
<string name="country_selection_title" msgid="5221495687299014379">"மண்டல விருப்பம்"</string>
<string name="search_language_hint" msgid="7004225294308793583">"மொழி பெயரை உள்ளிடுக"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 3aa7b04..dc21719 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"అనుకూల యాప్ నోటిఫికేషన్"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g>తో కొత్త వినియోగదారుని సృష్టించడానికి <xliff:g id="APP">%1$s</xliff:g>ను అనుమతించాలా (ఈ ఖాతాతో ఇప్పటికే ఒక వినియోగదారు ఉన్నారు) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g>తో కొత్త వినియోగదారుని సృష్టించడానికి <xliff:g id="APP">%1$s</xliff:g>ను అనుమతించాలా?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"పర్యవేక్షించబడే యూజర్ను జోడించండి"</string>
<string name="language_selection_title" msgid="52674936078683285">"భాషను జోడించండి"</string>
<string name="country_selection_title" msgid="5221495687299014379">"ప్రాంతం ప్రాధాన్యత"</string>
<string name="search_language_hint" msgid="7004225294308793583">"భాష పేరును టైప్ చేయండి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 41adb26..15d7f30 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"การแจ้งเตือนที่กำหนดเองของแอป"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> สร้างผู้ใช้ใหม่ด้วย <xliff:g id="ACCOUNT">%2$s</xliff:g> ไหม (มีผู้ใช้ที่มีบัญชีนี้อยู่แล้ว)"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> สร้างผู้ใช้ใหม่ด้วย <xliff:g id="ACCOUNT">%2$s</xliff:g> ไหม"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"เพิ่มผู้ใช้ภายใต้การควบคุมดูแล"</string>
<string name="language_selection_title" msgid="52674936078683285">"เพิ่มภาษา"</string>
<string name="country_selection_title" msgid="5221495687299014379">"ค่ากำหนดภูมิภาค"</string>
<string name="search_language_hint" msgid="7004225294308793583">"พิมพ์ชื่อภาษา"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 7f39769..cb6c485 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Custom na notification ng app"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na gumawa ng bagong User sa <xliff:g id="ACCOUNT">%2$s</xliff:g> (mayroon nang User sa account na ito) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na gumawa ng bagong User sa <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Magdagdag ng wika"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Kagustuhan sa rehiyon"</string>
<string name="search_language_hint" msgid="7004225294308793583">"I-type ang wika"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index bc26fed..df4a960 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Özel uygulama bildirimi"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabına sahip yeni bir Kullanıcı eklemesine izin verilsin mi (bu hesaba sahip bir kullanıcı zaten var)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabına sahip yeni bir Kullanıcı eklemesine izin verilsin mi?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Dil ekleyin"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Bölge tercihi"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Dil adını yazın"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 5ce1407..0539beba 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -2053,6 +2053,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Користувацьке сповіщення додатка"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> створити нового користувача з обліковим записом <xliff:g id="ACCOUNT">%2$s</xliff:g> (користувач із таким обліковим записом уже існує)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> створити нового користувача з обліковим записом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Додати мову"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Вибір регіону"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Введіть назву мови"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 7ceaa99..9d3c357 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"حسب ضرورت ایپ کی اطلاع"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> کو <xliff:g id="ACCOUNT">%2$s</xliff:g> کے ساتھ ایک نیا صارف بنانے کی اجازت دیں (اس اکاؤنٹ کے ساتھ ایک صارف پہلے سے موجود ہے) ؟"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> کے ساتھ نئے صارف کو تخلیق کرنے کے لیے <xliff:g id="APP">%1$s</xliff:g> کو اجازت دیں ؟"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"ایک زبان شامل کریں"</string>
<string name="country_selection_title" msgid="5221495687299014379">"علاقہ کی ترجیح"</string>
<string name="search_language_hint" msgid="7004225294308793583">"زبان کا نام ٹائپ کریں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index a40b67f..ab03056 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Maxsus ilova bildirishnomasi"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="ACCOUNT">%2$s</xliff:g> hisobi bilan yangi foydalanuvchi yaratishiga ruxsat berilsinmi (bunday hisobdagi foydalanuvchi allaqachon mavjud) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="ACCOUNT">%2$s</xliff:g> hisobi bilan yangi foydalanuvchi yaratishiga ruxsat berilsinmi ?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Kuzatuvdagi foydalanuvchi qoʻshish"</string>
<string name="language_selection_title" msgid="52674936078683285">"Til qoʻshish"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Hudud sozlamalari"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Til nomini kiriting"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 1731b3b..9225c16 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Thông báo tùy chỉnh cho ứng dụng"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Cho phép <xliff:g id="APP">%1$s</xliff:g> tạo người dùng mới bằng <xliff:g id="ACCOUNT">%2$s</xliff:g> (đã tồn tại người dùng có tài khoản này)?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Cho phép <xliff:g id="APP">%1$s</xliff:g> tạo người dùng mới bằng <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"Thêm người dùng được giám sát"</string>
<string name="language_selection_title" msgid="52674936078683285">"Thêm ngôn ngữ"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Tùy chọn khu vực"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Nhập tên ngôn ngữ"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 8ce9ab2..6793baa 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"自定义应用通知"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g>(目前已有用户使用此帐号)创建新用户吗?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 创建新用户吗?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"添加语言"</string>
<string name="country_selection_title" msgid="5221495687299014379">"区域偏好设置"</string>
<string name="search_language_hint" msgid="7004225294308793583">"输入语言名称"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 49850e14..d63bf16 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1989,6 +1989,7 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"自訂應用程式通知"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"要允許 <xliff:g id="APP">%1$s</xliff:g> 使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者 (此帳戶目前已有此使用者) 嗎?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"要允許 <xliff:g id="APP">%1$s</xliff:g> 使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎?"</string>
+ <string name="supervised_user_creation_label" msgid="6884904353827427515">"新增受管使用者"</string>
<string name="language_selection_title" msgid="52674936078683285">"新增語言"</string>
<string name="country_selection_title" msgid="5221495687299014379">"地區偏好設定"</string>
<string name="search_language_hint" msgid="7004225294308793583">"輸入語言名稱"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 329b5dc..8890f66 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"自訂應用程式通知"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"要允許「<xliff:g id="APP">%1$s</xliff:g>」替 <xliff:g id="ACCOUNT">%2$s</xliff:g> (這個帳戶目前已有使用者) 建立新使用者嗎?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"要允許「<xliff:g id="APP">%1$s</xliff:g>」替 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"新增語言"</string>
<string name="country_selection_title" msgid="5221495687299014379">"地區偏好設定"</string>
<string name="search_language_hint" msgid="7004225294308793583">"請輸入語言名稱"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 8c7d5ea..bfc0f1b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1989,6 +1989,8 @@
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"Isaziso sohlelo lokusebenza olungokwezifiso"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukuthi idale umsebenzisi omusha nge-<xliff:g id="ACCOUNT">%2$s</xliff:g> (Umsebenzisi onale akhawunti usevele ukhona) ?"</string>
<string name="user_creation_adding" msgid="7305185499667958364">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukuthi idale umsebenzisi omusha nge-<xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
+ <!-- no translation found for supervised_user_creation_label (6884904353827427515) -->
+ <skip />
<string name="language_selection_title" msgid="52674936078683285">"Engeza ulimi"</string>
<string name="country_selection_title" msgid="5221495687299014379">"Okuncamelayo kwesifunda"</string>
<string name="search_language_hint" msgid="7004225294308793583">"Thayipha igama lolimi"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8aa9201..bfc1c83 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8778,6 +8778,14 @@
<attr name="hotwordDetectionService" format="string" />
</declare-styleable>
+ <!-- Use <code>game-service</code> as the root tag of the XML resource that
+ describes a GameService.
+ Described here are the attributes that can be included in that tag. -->
+ <declare-styleable name="GameService">
+ <!-- The service that hosts active game sessions. This is required. -->
+ <attr name="gameSessionService" format="string" />
+ </declare-styleable>
+
<!-- Use <code>voice-enrollment-application</code>
as the root tag of the XML resource that escribes the supported keyphrases (hotwords)
by the enrollment application.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index be32c42..7d8bcea 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2897,6 +2897,10 @@
<!-- Make the IME killable by the lowmemorykiller by raising its oom_score_adj. -->
<bool name="config_killableInputMethods">false</bool>
+ <!-- Prevent the InputMethodManagerService from starting up the IME unless
+ the currently focused view is a text editor. -->
+ <bool name="config_preventImeStartupUnlessTextEditor">false</bool>
+
<!-- The list of classes that should be added to the notification ranking pipeline.
See {@link com.android.server.notification.NotificationSignalExtractor}
If you add a new extractor to this list make sure to update
@@ -5550,4 +5554,7 @@
That button will fire an intent targeted for this package with the mentioned action.
When this resource is empty, that button will not be shown. -->
<string name="config_supervisedUserCreationPackage" translatable="false"></string>
+
+ <!-- Determines whether SafetyCenter feature is enabled. -->
+ <bool name="config_enableSafetyCenter">true</bool>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 3d3c860..1f560f4 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3250,6 +3250,8 @@
<public name="supportedTypes" />
<public name="resetEnabledSettingsOnAppDataCleared" />
<public name="supportsStylusHandwriting" />
+ <!-- @hide @SystemApi -->
+ <public name="gameSessionService" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01de0000">
@@ -3311,6 +3313,8 @@
<staging-public-group type="bool" first-id="0x01cf0000">
<!-- @hide @SystemApi -->
<public name="config_systemCaptionsServiceCallsEnabled" />
+ <!-- @hide @TestApi -->
+ <public name="config_preventImeStartupUnlessTextEditor" />
</staging-public-group>
<staging-public-group type="fraction" first-id="0x01ce0000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b16e462..1f5f189 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1237,8 +1237,11 @@
<string name="permlab_bodySensors">access body sensors (like heart rate monitors)
</string>
<!-- Description of the body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] -->
- <string name="permdesc_bodySensors" product="default">Allows the app to access data from sensors
- that monitor your physical condition, such as your heart rate.</string>
+ <string name="permdesc_bodySensors" product="default">Access to data from body sensors such as heart rate, temperature, blood oxygen percentage, etc.</string>
+ <!-- Title of the background body sensors permission, listed so the user can decide whether to allow the application to access body sensor data in the background. [CHAR LIMIT=80] -->
+ <string name="permlab_bodySensors_background">access body sensors (like heart rate monitors) while in the background</string>
+ <!-- Description of the background body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors in the background. [CHAR LIMIT=NONE] -->
+ <string name="permdesc_bodySensors_background" product="default">Access to data from body sensors such as heart rate, temperature, blood oxygen percentage, etc. while in the background.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readCalendar">Read calendar events and details</string>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index ad0d0e0..d8111ea 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -42,6 +42,7 @@
<item name="outlineSpotShadowColor">@color/btn_colored_background_material</item>
<item name="textAppearance">?attr/textAppearanceButton</item>
<item name="textColor">@color/btn_colored_text_material</item>
+ <item name="drawableTint">@color/btn_colored_text_material</item>
</style>
<style name="Widget.DeviceDefault.TextView" parent="Widget.Material.TextView" />
<style name="Widget.DeviceDefault.CheckedTextView" parent="Widget.Material.CheckedTextView"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 527865f..ba4aa81 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2250,6 +2250,7 @@
<java-symbol type="bool" name="config_autoResetAirplaneMode" />
<java-symbol type="string" name="config_notificationAccessConfirmationActivity" />
<java-symbol type="bool" name="config_killableInputMethods" />
+ <java-symbol type="bool" name="config_preventImeStartupUnlessTextEditor" />
<java-symbol type="layout" name="resolver_list" />
<java-symbol type="id" name="resolver_list" />
@@ -4634,4 +4635,6 @@
<java-symbol type="string" name="config_systemGameService" />
<java-symbol type="string" name="config_supervisedUserCreationPackage"/>
+
+ <java-symbol type="bool" name="config_enableSafetyCenter" />
</resources>
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 5db6a3e..bfb2fd5 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -273,13 +273,14 @@
newerConfig.orientation = orientation == ORIENTATION_LANDSCAPE
? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
newerConfig.seq = seq + 2;
- final ActivityClientRecord r = getActivityClientRecord(activity);
- activityThread.updatePendingActivityConfiguration(r, newerConfig);
+ activityThread.updatePendingActivityConfiguration(activity.getActivityToken(),
+ newerConfig);
final Configuration olderConfig = new Configuration();
olderConfig.orientation = orientation;
olderConfig.seq = seq + 1;
+ final ActivityClientRecord r = getActivityClientRecord(activity);
activityThread.handleActivityConfigurationChanged(r, olderConfig, INVALID_DISPLAY);
assertEquals(numOfConfig, activity.mNumOfConfigChanges);
assertEquals(olderConfig.orientation, activity.mConfig.orientation);
@@ -504,7 +505,8 @@
? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
final ActivityClientRecord r = getActivityClientRecord(activity);
- activityThread.updatePendingActivityConfiguration(r, newActivityConfig);
+ activityThread.updatePendingActivityConfiguration(activity.getActivityToken(),
+ newActivityConfig);
activityThread.handleActivityConfigurationChanged(r, newActivityConfig,
INVALID_DISPLAY);
diff --git a/core/tests/coretests/src/android/net/NetworkPolicyTest.kt b/core/tests/coretests/src/android/net/NetworkPolicyTest.kt
index d936cad..3c8f90c 100644
--- a/core/tests/coretests/src/android/net/NetworkPolicyTest.kt
+++ b/core/tests/coretests/src/android/net/NetworkPolicyTest.kt
@@ -16,6 +16,10 @@
package android.net
+import android.net.NetworkTemplate.MATCH_BLUETOOTH
+import android.net.NetworkTemplate.MATCH_ETHERNET
+import android.net.NetworkTemplate.MATCH_MOBILE
+import android.net.NetworkTemplate.MATCH_WIFI
import android.text.format.Time.TIMEZONE_UTC
import androidx.test.runner.AndroidJUnit4
import org.junit.Test
@@ -24,16 +28,18 @@
import java.io.DataInputStream
import java.time.ZoneId
import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
private const val TEST_IMSI1 = "TESTIMSI1"
-private const val TEST_SSID1 = "TESTISSID1"
+private const val TEST_WIFI_NETWORK_KEY1 = "TESTKEY1"
@RunWith(AndroidJUnit4::class)
class NetworkPolicyTest {
@Test
fun testTemplateBackupRestore() {
assertPolicyBackupRestore(createTestPolicyForTemplate(
- NetworkTemplate.buildTemplateWifi(TEST_SSID1)))
+ NetworkTemplate.buildTemplateWifi(TEST_WIFI_NETWORK_KEY1)))
assertPolicyBackupRestore(createTestPolicyForTemplate(
NetworkTemplate.buildTemplateMobileAll(TEST_IMSI1)))
assertPolicyBackupRestore(createTestPolicyForTemplate(
@@ -53,4 +59,26 @@
val restored = NetworkPolicy.getNetworkPolicyFromBackup(stream)
assertEquals(policy, restored)
}
-}
\ No newline at end of file
+
+ @Test
+ fun testIsTemplatePersistable() {
+ listOf(MATCH_MOBILE, MATCH_WIFI).forEach {
+ // Verify wildcard templates cannot be persistable.
+ assertFalse(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(it).build()))
+
+ // Verify mobile/wifi templates can be persistable if the Subscriber Id is supplied.
+ assertTrue(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(it)
+ .setSubscriberIds(setOf(TEST_IMSI1)).build()))
+ }
+
+ // Verify bluetooth and ethernet templates can be persistable without any other
+ // field is supplied.
+ listOf(MATCH_BLUETOOTH, MATCH_ETHERNET).forEach {
+ assertTrue(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(it).build()))
+ }
+
+ // Verify wifi template can be persistable if the Wifi Network Key is supplied.
+ assertTrue(NetworkPolicy.isTemplatePersistable(NetworkTemplate.Builder(MATCH_WIFI)
+ .setWifiNetworkKeys(setOf(TEST_WIFI_NETWORK_KEY1)).build()))
+ }
+}
diff --git a/core/tests/coretests/src/android/os/BundleTest.java b/core/tests/coretests/src/android/os/BundleTest.java
index 09f4840..a3bda8b 100644
--- a/core/tests/coretests/src/android/os/BundleTest.java
+++ b/core/tests/coretests/src/android/os/BundleTest.java
@@ -23,6 +23,7 @@
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import android.platform.test.annotations.Presubmit;
import android.util.Log;
import androidx.test.filters.SmallTest;
@@ -41,6 +42,7 @@
* Run with: atest FrameworksCoreTests:android.os.BundleTest
*/
@SmallTest
+@Presubmit
@RunWith(AndroidJUnit4.class)
public class BundleTest {
private Log.TerribleFailureHandler mWtfHandler;
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
index 2c8c385..6df9002 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
@@ -42,14 +42,14 @@
// and assertAccessibilityEventCleared
/** The number of properties of the {@link AccessibilityEvent} class. */
- private static final int A11Y_EVENT_NON_STATIC_FIELD_COUNT = 34;
+ private static final int A11Y_EVENT_NON_STATIC_FIELD_COUNT = 32;
// The number of fields tested in the corresponding CTS AccessibilityRecordTest:
// assertAccessibilityRecordCleared, fullyPopulateAccessibilityRecord,
// and assertEqualAccessibilityRecord
/** The number of properties of the {@link AccessibilityRecord} class. */
- private static final int A11Y_RECORD_NON_STATIC_FIELD_COUNT = 25;
+ private static final int A11Y_RECORD_NON_STATIC_FIELD_COUNT = 23;
@Test
public void testImportantForAccessibiity_getSetWorkAcrossParceling() {
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
index 212fdca..bb1a3b18 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
@@ -17,7 +17,6 @@
package android.view.accessibility;
import static junit.framework.TestCase.assertFalse;
-import static junit.framework.TestCase.assertSame;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -188,17 +187,6 @@
}
@Test
- public void testSendAccessibilityEvent_AccessibilityEnabled() throws Exception {
- AccessibilityEvent sentEvent = AccessibilityEvent.obtain(
- AccessibilityEvent.TYPE_ANNOUNCEMENT);
-
- AccessibilityManager manager = createManager(WITH_A11Y_ENABLED);
- manager.sendAccessibilityEvent(sentEvent);
-
- assertSame("The event should be recycled.", sentEvent, AccessibilityEvent.obtain());
- }
-
- @Test
public void testSendAccessibilityEvent_AccessibilityDisabled() throws Exception {
AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
diff --git a/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java
deleted file mode 100644
index 11f4e3c..0000000
--- a/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java
+++ /dev/null
@@ -1,80 +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 android.view.accessibility;
-
-import androidx.test.filters.SmallTest;
-
-import junit.framework.TestCase;
-
-/**
- * This class exercises the caching and recycling of {@link AccessibilityEvent}s.
- */
-public class RecycleAccessibilityEventTest extends TestCase {
-
- private static final String CLASS_NAME = "foo.bar.baz.Test";
- private static final String PACKAGE_NAME = "foo.bar.baz";
- private static final String TEXT = "Some stuff";
-
- private static final String CONTENT_DESCRIPTION = "Content description";
- private static final int ITEM_COUNT = 10;
- private static final int CURRENT_ITEM_INDEX = 1;
-
- private static final int FROM_INDEX = 1;
- private static final int ADDED_COUNT = 2;
- private static final int REMOVED_COUNT = 1;
-
- /**
- * If an {@link AccessibilityEvent} is marshaled/unmarshaled correctly
- */
- @SmallTest
- public void testAccessibilityEventViewTextChangedType() {
- AccessibilityEvent first =
- AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
- assertNotNull(first);
-
- first.setClassName(CLASS_NAME);
- first.setPackageName(PACKAGE_NAME);
- first.getText().add(TEXT);
- first.setFromIndex(FROM_INDEX);
- first.setAddedCount(ADDED_COUNT);
- first.setRemovedCount(REMOVED_COUNT);
- first.setChecked(true);
- first.setContentDescription(CONTENT_DESCRIPTION);
- first.setItemCount(ITEM_COUNT);
- first.setCurrentItemIndex(CURRENT_ITEM_INDEX);
- first.setEnabled(true);
- first.setPassword(true);
-
- first.recycle();
-
- assertNotNull(first);
- assertNull(first.getClassName());
- assertNull(first.getPackageName());
- assertEquals(0, first.getText().size());
- assertFalse(first.isChecked());
- assertNull(first.getContentDescription());
- assertEquals(-1, first.getItemCount());
- assertEquals(AccessibilityEvent.INVALID_POSITION, first.getCurrentItemIndex());
- assertFalse(first.isEnabled());
- assertFalse(first.isPassword());
- assertEquals(-1, first.getFromIndex());
- assertEquals(-1, first.getAddedCount());
- assertEquals(-1, first.getRemovedCount());
-
- // get another event from the pool (this must be the recycled first)
- AccessibilityEvent second = AccessibilityEvent.obtain();
- assertEquals(first, second);
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityLoggerFake.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityLoggerFake.java
index 374edb8..2ecc261 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityLoggerFake.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityLoggerFake.java
@@ -95,6 +95,13 @@
return mCalls.get(index).event;
}
+ public void removeCallsForUiEventsOfType(int uiEventType) {
+ mCalls.removeIf(
+ call ->
+ (call.atomId == FrameworkStatsLog.UI_EVENT_REPORTED)
+ && (call.event.getId() == uiEventType));
+ }
+
@Override
public void logShareStarted(int eventId, String packageName, String mimeType,
int appProvidedDirect, int appProvidedApp, boolean isWorkprofile, int previewType,
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index c69cb4b..69ff7c6 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -45,6 +45,7 @@
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThan;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -80,12 +81,12 @@
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.service.chooser.ChooserTarget;
+import android.view.View;
import androidx.annotation.CallSuper;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
-import com.android.internal.R;
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
import com.android.internal.app.chooser.DisplayResolveInfo;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -93,6 +94,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.FrameworkStatsLog;
+import org.hamcrest.Matcher;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
@@ -178,6 +180,16 @@
return clientIntent;
}
+ /**
+ * Whether {@code #testIsAppPredictionServiceAvailable} should verify the behavior after
+ * changing the availability conditions at runtime. In the unbundled chooser, the availability
+ * is cached at start and will never be re-evaluated.
+ * TODO: remove when we no longer want to test the system's on-the-fly evaluation.
+ */
+ protected boolean shouldTestTogglingAppPredictionServiceAvailabilityAtRuntime() {
+ return true;
+ }
+
/* --------
* The code in this section is unorthodox and can be simplified/reverted when we no longer need
* to support the parallel chooser implementations.
@@ -256,7 +268,7 @@
waitForIdle();
assertThat(activity.getAdapter().getCount(), is(2));
assertThat(activity.getAdapter().getServiceTargetCount(), is(0));
- onView(withId(R.id.title)).check(matches(withText("chooser test")));
+ onView(withIdFromRuntimeResource("title")).check(matches(withText("chooser test")));
}
@Test
@@ -275,7 +287,8 @@
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "chooser test"));
waitForIdle();
- onView(withId(R.id.title)).check(matches(withText(R.string.whichSendApplication)));
+ onView(withIdFromRuntimeResource("title"))
+ .check(matches(withTextFromRuntimeResource("whichSendApplication")));
}
@Test
@@ -294,8 +307,8 @@
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.title))
- .check(matches(withText(R.string.whichSendApplication)));
+ onView(withIdFromRuntimeResource("title"))
+ .check(matches(withTextFromRuntimeResource("whichSendApplication")));
}
@Test
@@ -314,8 +327,10 @@
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.content_preview_title)).check(matches(not(isDisplayed())));
- onView(withId(R.id.content_preview_thumbnail)).check(matches(not(isDisplayed())));
+ onView(withIdFromRuntimeResource("content_preview_title"))
+ .check(matches(not(isDisplayed())));
+ onView(withIdFromRuntimeResource("content_preview_thumbnail"))
+ .check(matches(not(isDisplayed())));
}
@Test
@@ -335,9 +350,12 @@
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.content_preview_title)).check(matches(isDisplayed()));
- onView(withId(R.id.content_preview_title)).check(matches(withText(previewTitle)));
- onView(withId(R.id.content_preview_thumbnail)).check(matches(not(isDisplayed())));
+ onView(withIdFromRuntimeResource("content_preview_title"))
+ .check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_title"))
+ .check(matches(withText(previewTitle)));
+ onView(withIdFromRuntimeResource("content_preview_thumbnail"))
+ .check(matches(not(isDisplayed())));
}
@Test
@@ -358,8 +376,9 @@
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.content_preview_title)).check(matches(isDisplayed()));
- onView(withId(R.id.content_preview_thumbnail)).check(matches(not(isDisplayed())));
+ onView(withIdFromRuntimeResource("content_preview_title")).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_thumbnail"))
+ .check(matches(not(isDisplayed())));
}
@Test
@@ -382,8 +401,9 @@
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.content_preview_title)).check(matches(isDisplayed()));
- onView(withId(R.id.content_preview_thumbnail)).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_title")).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_thumbnail"))
+ .check(matches(isDisplayed()));
}
@Test @Ignore
@@ -406,7 +426,7 @@
waitForIdle();
assertThat(activity.getAdapter().getCount(), is(2));
- onView(withId(R.id.profile_button)).check(doesNotExist());
+ onView(withIdFromRuntimeResource("profile_button")).check(doesNotExist());
ResolveInfo[] chosen = new ResolveInfo[1];
ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
@@ -536,8 +556,8 @@
waitForIdle();
assertThat(activity.isFinishing(), is(false));
- onView(withId(R.id.empty)).check(matches(isDisplayed()));
- onView(withId(R.id.profile_pager)).check(matches(not(isDisplayed())));
+ onView(withIdFromRuntimeResource("empty")).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("profile_pager")).check(matches(not(isDisplayed())));
InstrumentationRegistry.getInstrumentation().runOnMainSync(
() -> wrapper.getAdapter().handlePackagesChanged()
);
@@ -700,8 +720,8 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.chooser_copy_button)).check(matches(isDisplayed()));
- onView(withId(R.id.chooser_copy_button)).perform(click());
+ onView(withIdFromRuntimeResource("chooser_copy_button")).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("chooser_copy_button")).perform(click());
ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(
Context.CLIPBOARD_SERVICE);
ClipData clipData = clipboard.getPrimaryClip();
@@ -729,8 +749,8 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.chooser_copy_button)).check(matches(isDisplayed()));
- onView(withId(R.id.chooser_copy_button)).perform(click());
+ onView(withIdFromRuntimeResource("chooser_copy_button")).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("chooser_copy_button")).perform(click());
verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture());
@@ -755,12 +775,17 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.chooser_nearby_button)).check(matches(isDisplayed()));
- onView(withId(R.id.chooser_nearby_button)).perform(click());
+ onView(withIdFromRuntimeResource("chooser_nearby_button")).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("chooser_nearby_button")).perform(click());
ChooserActivityLoggerFake logger =
(ChooserActivityLoggerFake) activity.getChooserActivityLogger();
+ // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
+ logger.removeCallsForUiEventsOfType(
+ ChooserActivityLogger.SharesheetStandardEvent
+ .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
+
// SHARESHEET_TRIGGERED:
assertThat(logger.event(0).getId(),
is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
@@ -769,7 +794,8 @@
assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
assertThat(logger.get(1).mimeType, is("text/plain"));
- assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests"));
+ assertThat(logger.get(1).packageName, is(
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
assertThat(logger.get(1).appProvidedApp, is(0));
assertThat(logger.get(1).appProvidedDirect, is(0));
assertThat(logger.get(1).isWorkprofile, is(false));
@@ -780,31 +806,26 @@
is(ChooserActivityLogger
.SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
- // SHARESHEET_DIRECT_LOAD_COMPLETE:
+ // Next are just artifacts of test set-up:
assertThat(logger.event(3).getId(),
is(ChooserActivityLogger
- .SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE.getId()));
-
- // Fifth and sixth are just artifacts of test set-up:
- assertThat(logger.event(4).getId(),
- is(ChooserActivityLogger
.SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
- assertThat(logger.event(5).getId(),
+ assertThat(logger.event(4).getId(),
is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId()));
- // SHARESHEET_EDIT_TARGET_SELECTED:
- assertThat(logger.get(6).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
- assertThat(logger.get(6).targetType,
+ // SHARESHEET_NEARBY_TARGET_SELECTED:
+ assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
+ assertThat(logger.get(5).targetType,
is(ChooserActivityLogger
.SharesheetTargetSelectedEvent.SHARESHEET_NEARBY_TARGET_SELECTED.getId()));
// No more events.
- assertThat(logger.numCalls(), is(7));
+ assertThat(logger.numCalls(), is(6));
}
- @Test
+ @Test @Ignore
public void testEditImageLogs() throws Exception {
Intent sendIntent = createSendImageIntent(
Uri.parse("android.resource://com.android.frameworks.coretests/"
@@ -824,12 +845,17 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.chooser_edit_button)).check(matches(isDisplayed()));
- onView(withId(R.id.chooser_edit_button)).perform(click());
+ onView(withIdFromRuntimeResource("chooser_edit_button")).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("chooser_edit_button")).perform(click());
ChooserActivityLoggerFake logger =
(ChooserActivityLoggerFake) activity.getChooserActivityLogger();
+ // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
+ logger.removeCallsForUiEventsOfType(
+ ChooserActivityLogger.SharesheetStandardEvent
+ .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
+
// SHARESHEET_TRIGGERED:
assertThat(logger.event(0).getId(),
is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
@@ -838,7 +864,8 @@
assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
assertThat(logger.get(1).mimeType, is("image/png"));
- assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests"));
+ assertThat(logger.get(1).packageName, is(
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
assertThat(logger.get(1).appProvidedApp, is(0));
assertThat(logger.get(1).appProvidedDirect, is(0));
assertThat(logger.get(1).isWorkprofile, is(false));
@@ -849,26 +876,21 @@
is(ChooserActivityLogger
.SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
- // SHARESHEET_DIRECT_LOAD_COMPLETE:
+ // Next are just artifacts of test set-up:
assertThat(logger.event(3).getId(),
is(ChooserActivityLogger
- .SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE.getId()));
-
- // Fifth and sixth are just artifacts of test set-up:
- assertThat(logger.event(4).getId(),
- is(ChooserActivityLogger
.SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
- assertThat(logger.event(5).getId(),
+ assertThat(logger.event(4).getId(),
is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId()));
// SHARESHEET_EDIT_TARGET_SELECTED:
- assertThat(logger.get(6).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
- assertThat(logger.get(6).targetType,
+ assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
+ assertThat(logger.get(5).targetType,
is(ChooserActivityLogger
.SharesheetTargetSelectedEvent.SHARESHEET_EDIT_TARGET_SELECTED.getId()));
// No more events.
- assertThat(logger.numCalls(), is(7));
+ assertThat(logger.numCalls(), is(6));
}
@@ -897,10 +919,14 @@
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.content_preview_image_1_large)).check(matches(isDisplayed()));
- onView(withId(R.id.content_preview_image_2_large)).check(matches(not(isDisplayed())));
- onView(withId(R.id.content_preview_image_2_small)).check(matches(not(isDisplayed())));
- onView(withId(R.id.content_preview_image_3_small)).check(matches(not(isDisplayed())));
+ onView(withIdFromRuntimeResource("content_preview_image_1_large"))
+ .check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_image_2_large"))
+ .check(matches(not(isDisplayed())));
+ onView(withIdFromRuntimeResource("content_preview_image_2_small"))
+ .check(matches(not(isDisplayed())));
+ onView(withIdFromRuntimeResource("content_preview_image_3_small"))
+ .check(matches(not(isDisplayed())));
}
@Test
@@ -929,10 +955,14 @@
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.content_preview_image_1_large)).check(matches(isDisplayed()));
- onView(withId(R.id.content_preview_image_2_large)).check(matches(isDisplayed()));
- onView(withId(R.id.content_preview_image_2_small)).check(matches(not(isDisplayed())));
- onView(withId(R.id.content_preview_image_3_small)).check(matches(not(isDisplayed())));
+ onView(withIdFromRuntimeResource("content_preview_image_1_large"))
+ .check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_image_2_large"))
+ .check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_image_2_small"))
+ .check(matches(not(isDisplayed())));
+ onView(withIdFromRuntimeResource("content_preview_image_3_small"))
+ .check(matches(not(isDisplayed())));
}
@Test
@@ -964,10 +994,14 @@
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.content_preview_image_1_large)).check(matches(isDisplayed()));
- onView(withId(R.id.content_preview_image_2_large)).check(matches(not(isDisplayed())));
- onView(withId(R.id.content_preview_image_2_small)).check(matches(isDisplayed()));
- onView(withId(R.id.content_preview_image_3_small)).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_image_1_large"))
+ .check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_image_2_large"))
+ .check(matches(not(isDisplayed())));
+ onView(withIdFromRuntimeResource("content_preview_image_2_small"))
+ .check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_image_3_small"))
+ .check(matches(isDisplayed()));
}
@Test
@@ -1120,9 +1154,11 @@
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.content_preview_filename)).check(matches(isDisplayed()));
- onView(withId(R.id.content_preview_filename)).check(matches(withText("app.pdf")));
- onView(withId(R.id.content_preview_file_icon)).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_filename")).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_filename"))
+ .check(matches(withText("app.pdf")));
+ onView(withIdFromRuntimeResource("content_preview_file_icon"))
+ .check(matches(isDisplayed()));
}
@@ -1150,9 +1186,12 @@
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.content_preview_filename)).check(matches(isDisplayed()));
- onView(withId(R.id.content_preview_filename)).check(matches(withText("app.pdf + 2 files")));
- onView(withId(R.id.content_preview_file_icon)).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_filename"))
+ .check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_filename"))
+ .check(matches(withText("app.pdf + 2 files")));
+ onView(withIdFromRuntimeResource("content_preview_file_icon"))
+ .check(matches(isDisplayed()));
}
@Test
@@ -1179,9 +1218,11 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.content_preview_filename)).check(matches(isDisplayed()));
- onView(withId(R.id.content_preview_filename)).check(matches(withText("app.pdf")));
- onView(withId(R.id.content_preview_file_icon)).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_filename")).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_filename"))
+ .check(matches(withText("app.pdf")));
+ onView(withIdFromRuntimeResource("content_preview_file_icon"))
+ .check(matches(isDisplayed()));
}
@Test
@@ -1215,9 +1256,11 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.content_preview_filename)).check(matches(isDisplayed()));
- onView(withId(R.id.content_preview_filename)).check(matches(withText("app.pdf + 1 file")));
- onView(withId(R.id.content_preview_file_icon)).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_filename")).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("content_preview_filename"))
+ .check(matches(withText("app.pdf + 1 file")));
+ onView(withIdFromRuntimeResource("content_preview_file_icon"))
+ .check(matches(isDisplayed()));
}
@Test
@@ -1290,13 +1333,20 @@
} else {
assertThat(activity.isAppPredictionServiceAvailable(), is(true));
+ if (!shouldTestTogglingAppPredictionServiceAvailabilityAtRuntime()) {
+ return;
+ }
+
ChooserActivityOverrideData.getInstance().resources =
Mockito.spy(activity.getResources());
when(
ChooserActivityOverrideData
.getInstance()
.resources
- .getString(R.string.config_defaultAppPredictionService))
+ .getString(
+ getRuntimeResourceId(
+ "config_defaultAppPredictionService",
+ "string")))
.thenReturn("ComponentNameThatDoesNotExist");
assertThat(activity.isAppPredictionServiceAvailable(), is(false));
@@ -1544,7 +1594,8 @@
ChooserActivityOverrideData
.getInstance()
.resources
- .getInteger(R.integer.config_maxShortcutTargetsPerApp))
+ .getInteger(
+ getRuntimeResourceId("config_maxShortcutTargetsPerApp", "integer")))
.thenReturn(1);
Intent sendIntent = createSendTextIntent();
// We need app targets for direct targets to get displayed
@@ -1615,7 +1666,8 @@
ChooserActivityOverrideData
.getInstance()
.resources
- .getInteger(R.integer.config_maxShortcutTargetsPerApp))
+ .getInteger(
+ getRuntimeResourceId("config_maxShortcutTargetsPerApp", "integer")))
.thenReturn(1);
Intent sendIntent = createSendTextIntent();
// We need app targets for direct targets to get displayed
@@ -1787,7 +1839,7 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
waitForIdle();
- onView(withId(R.id.tabs)).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("tabs")).check(matches(isDisplayed()));
}
@Test
@@ -1800,7 +1852,7 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
waitForIdle();
- onView(withId(R.id.tabs)).check(matches(not(isDisplayed())));
+ onView(withIdFromRuntimeResource("tabs")).check(matches(not(isDisplayed())));
}
@Test
@@ -1825,7 +1877,7 @@
waitForIdle();
assertThat(activity.getCurrentUserHandle().getIdentifier(), is(0));
- onView(withText(R.string.resolver_work_tab)).perform(click());
+ onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
assertThat(activity.getCurrentUserHandle().getIdentifier(), is(10));
assertThat(activity.getPersonalListAdapter().getCount(), is(personalProfileTargets));
assertThat(activity.getWorkListAdapter().getCount(), is(workProfileTargets));
@@ -1848,7 +1900,7 @@
final IChooserWrapper activity = (IChooserWrapper)
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
waitForIdle();
- onView(withText(R.string.resolver_work_tab)).perform(click());
+ onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
waitForIdle();
assertThat(activity.getWorkListAdapter().getCount(), is(workProfileTargets));
@@ -1875,7 +1927,7 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
waitForIdle();
- onView(withText(R.string.resolver_work_tab)).perform(click());
+ onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
waitForIdle();
// wait for the share sheet to expand
Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
@@ -1906,12 +1958,12 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
waitForIdle();
- onView(withText(R.string.resolver_work_tab)).perform(click());
+ onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
waitForIdle();
- onView(withId(R.id.contentPanel))
+ onView(withIdFromRuntimeResource("contentPanel"))
.perform(swipeUp());
- onView(withText(R.string.resolver_cross_profile_blocked))
+ onView(withTextFromRuntimeResource("resolver_cross_profile_blocked"))
.check(matches(isDisplayed()));
}
@@ -1932,12 +1984,12 @@
ResolverActivity.ENABLE_TABBED_VIEW = true;
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
waitForIdle();
- onView(withId(R.id.contentPanel))
+ onView(withIdFromRuntimeResource("contentPanel"))
.perform(swipeUp());
- onView(withText(R.string.resolver_work_tab)).perform(click());
+ onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
waitForIdle();
- onView(withText(R.string.resolver_turn_on_work_apps))
+ onView(withTextFromRuntimeResource("resolver_turn_on_work_apps"))
.check(matches(isDisplayed()));
}
@@ -1956,12 +2008,12 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
waitForIdle();
- onView(withId(R.id.contentPanel))
+ onView(withIdFromRuntimeResource("contentPanel"))
.perform(swipeUp());
- onView(withText(R.string.resolver_work_tab)).perform(click());
+ onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
waitForIdle();
- onView(withText(R.string.resolver_no_work_apps_available))
+ onView(withTextFromRuntimeResource("resolver_no_work_apps_available"))
.check(matches(isDisplayed()));
}
@@ -1982,12 +2034,12 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
waitForIdle();
- onView(withId(R.id.contentPanel))
+ onView(withIdFromRuntimeResource("contentPanel"))
.perform(swipeUp());
- onView(withText(R.string.resolver_work_tab)).perform(click());
+ onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
waitForIdle();
- onView(withText(R.string.resolver_cross_profile_blocked))
+ onView(withTextFromRuntimeResource("resolver_cross_profile_blocked"))
.check(matches(isDisplayed()));
}
@@ -2007,12 +2059,12 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
waitForIdle();
- onView(withId(R.id.contentPanel))
+ onView(withIdFromRuntimeResource("contentPanel"))
.perform(swipeUp());
- onView(withText(R.string.resolver_work_tab)).perform(click());
+ onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
waitForIdle();
- onView(withText(R.string.resolver_no_work_apps_available))
+ onView(withTextFromRuntimeResource("resolver_no_work_apps_available"))
.check(matches(isDisplayed()));
}
@@ -2036,7 +2088,7 @@
waitForIdle();
assertThat(activity.getAdapter().getCount(), is(2));
- onView(withId(R.id.profile_button)).check(doesNotExist());
+ onView(withIdFromRuntimeResource("profile_button")).check(doesNotExist());
ResolveInfo[] chosen = new ResolveInfo[1];
ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> {
@@ -2052,6 +2104,11 @@
ChooserActivityLoggerFake logger =
(ChooserActivityLoggerFake) activity.getChooserActivityLogger();
+ // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
+ logger.removeCallsForUiEventsOfType(
+ ChooserActivityLogger.SharesheetStandardEvent
+ .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
+
// SHARESHEET_TRIGGERED:
assertThat(logger.event(0).getId(),
is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
@@ -2060,7 +2117,8 @@
assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
assertThat(logger.get(1).mimeType, is("text/plain"));
- assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests"));
+ assertThat(logger.get(1).packageName, is(
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
assertThat(logger.get(1).appProvidedApp, is(0));
assertThat(logger.get(1).appProvidedDirect, is(0));
assertThat(logger.get(1).isWorkprofile, is(false));
@@ -2071,26 +2129,21 @@
is(ChooserActivityLogger
.SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
- // SHARESHEET_DIRECT_LOAD_COMPLETE:
+ // Next are just artifacts of test set-up:
assertThat(logger.event(3).getId(),
is(ChooserActivityLogger
- .SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE.getId()));
-
- // Fifth and sixth are just artifacts of test set-up:
- assertThat(logger.event(4).getId(),
- is(ChooserActivityLogger
.SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
- assertThat(logger.event(5).getId(),
+ assertThat(logger.event(4).getId(),
is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId()));
- // SHARESHEET_EDIT_TARGET_SELECTED:
- assertThat(logger.get(6).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
- assertThat(logger.get(6).targetType,
+ // SHARESHEET_APP_TARGET_SELECTED:
+ assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
+ assertThat(logger.get(5).targetType,
is(ChooserActivityLogger
.SharesheetTargetSelectedEvent.SHARESHEET_APP_TARGET_SELECTED.getId()));
// No more events.
- assertThat(logger.numCalls(), is(7));
+ assertThat(logger.numCalls(), is(6));
}
@Test @Ignore
@@ -2161,7 +2214,8 @@
assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
assertThat(logger.get(1).mimeType, is("text/plain"));
- assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests"));
+ assertThat(logger.get(1).packageName, is(
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
assertThat(logger.get(1).appProvidedApp, is(0));
assertThat(logger.get(1).appProvidedDirect, is(0));
assertThat(logger.get(1).isWorkprofile, is(false));
@@ -2179,7 +2233,7 @@
.SharesheetTargetSelectedEvent.SHARESHEET_SERVICE_TARGET_SELECTED.getId()));
}
- @Test
+ @Test @Ignore
public void testEmptyDirectRowLogging() throws InterruptedException {
Intent sendIntent = createSendTextIntent();
// We need app targets for direct targets to get displayed
@@ -2210,6 +2264,11 @@
ChooserActivityLoggerFake logger =
(ChooserActivityLoggerFake) activity.getChooserActivityLogger();
+ // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
+ logger.removeCallsForUiEventsOfType(
+ ChooserActivityLogger.SharesheetStandardEvent
+ .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
+
// SHARESHEET_TRIGGERED:
assertThat(logger.event(0).getId(),
is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
@@ -2218,7 +2277,8 @@
assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
assertThat(logger.get(1).mimeType, is("text/plain"));
- assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests"));
+ assertThat(logger.get(1).packageName, is(
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
assertThat(logger.get(1).appProvidedApp, is(0));
assertThat(logger.get(1).appProvidedDirect, is(0));
assertThat(logger.get(1).isWorkprofile, is(false));
@@ -2229,21 +2289,16 @@
is(ChooserActivityLogger
.SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
- // SHARESHEET_DIRECT_LOAD_COMPLETE:
- assertThat(logger.event(3).getId(),
- is(ChooserActivityLogger
- .SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE.getId()));
-
// SHARESHEET_EMPTY_DIRECT_SHARE_ROW:
- assertThat(logger.event(4).getId(),
+ assertThat(logger.event(3).getId(),
is(ChooserActivityLogger
.SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
- // Sixth is just an artifact of test set-up:
- assertThat(logger.event(5).getId(),
+ // Next is just an artifact of test set-up:
+ assertThat(logger.event(4).getId(),
is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId()));
- assertThat(logger.numCalls(), is(6));
+ assertThat(logger.numCalls(), is(5));
}
@Test
@@ -2265,12 +2320,17 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
- onView(withId(R.id.chooser_copy_button)).check(matches(isDisplayed()));
- onView(withId(R.id.chooser_copy_button)).perform(click());
+ onView(withIdFromRuntimeResource("chooser_copy_button")).check(matches(isDisplayed()));
+ onView(withIdFromRuntimeResource("chooser_copy_button")).perform(click());
ChooserActivityLoggerFake logger =
(ChooserActivityLoggerFake) activity.getChooserActivityLogger();
+ // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
+ logger.removeCallsForUiEventsOfType(
+ ChooserActivityLogger.SharesheetStandardEvent
+ .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
+
// SHARESHEET_TRIGGERED:
assertThat(logger.event(0).getId(),
is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
@@ -2279,7 +2339,8 @@
assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
assertThat(logger.get(1).mimeType, is("text/plain"));
- assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests"));
+ assertThat(logger.get(1).packageName, is(
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
assertThat(logger.get(1).appProvidedApp, is(0));
assertThat(logger.get(1).appProvidedDirect, is(0));
assertThat(logger.get(1).isWorkprofile, is(false));
@@ -2290,26 +2351,21 @@
is(ChooserActivityLogger
.SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
- // SHARESHEET_DIRECT_LOAD_COMPLETE:
+ // Next are just artifacts of test set-up:
assertThat(logger.event(3).getId(),
is(ChooserActivityLogger
- .SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE.getId()));
-
- // Fifth and sixth are just artifacts of test set-up:
- assertThat(logger.event(4).getId(),
- is(ChooserActivityLogger
.SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
- assertThat(logger.event(5).getId(),
+ assertThat(logger.event(4).getId(),
is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId()));
- // SHARESHEET_EDIT_TARGET_SELECTED:
- assertThat(logger.get(6).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
- assertThat(logger.get(6).targetType,
+ // SHARESHEET_COPY_TARGET_SELECTED:
+ assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED));
+ assertThat(logger.get(5).targetType,
is(ChooserActivityLogger
.SharesheetTargetSelectedEvent.SHARESHEET_COPY_TARGET_SELECTED.getId()));
// No more events.
- assertThat(logger.numCalls(), is(7));
+ assertThat(logger.numCalls(), is(6));
}
@Test
@@ -2329,14 +2385,19 @@
final IChooserWrapper activity = (IChooserWrapper)
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
waitForIdle();
- onView(withText(R.string.resolver_work_tab)).perform(click());
+ onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
waitForIdle();
- onView(withText(R.string.resolver_personal_tab)).perform(click());
+ onView(withTextFromRuntimeResource("resolver_personal_tab")).perform(click());
waitForIdle();
ChooserActivityLoggerFake logger =
(ChooserActivityLoggerFake) activity.getChooserActivityLogger();
+ // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events.
+ logger.removeCallsForUiEventsOfType(
+ ChooserActivityLogger.SharesheetStandardEvent
+ .SHARESHEET_DIRECT_LOAD_COMPLETE.getId());
+
// SHARESHEET_TRIGGERED:
assertThat(logger.event(0).getId(),
is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId()));
@@ -2345,7 +2406,8 @@
assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED));
assertThat(logger.get(1).intent, is(Intent.ACTION_SEND));
assertThat(logger.get(1).mimeType, is(TEST_MIME_TYPE));
- assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests"));
+ assertThat(logger.get(1).packageName, is(
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName()));
assertThat(logger.get(1).appProvidedApp, is(0));
assertThat(logger.get(1).appProvidedDirect, is(0));
assertThat(logger.get(1).isWorkprofile, is(false));
@@ -2356,45 +2418,35 @@
is(ChooserActivityLogger
.SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
- // SHARESHEET_DIRECT_LOAD_COMPLETE:
+ // Next is just an artifact of test set-up:
assertThat(logger.event(3).getId(),
is(ChooserActivityLogger
- .SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE.getId()));
-
- // Fifth is just an artifact of test set-up:
- assertThat(logger.event(4).getId(),
- is(ChooserActivityLogger
.SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
// SHARESHEET_PROFILE_CHANGED:
- assertThat(logger.event(5).getId(),
+ assertThat(logger.event(4).getId(),
is(ChooserActivityLogger.SharesheetStandardEvent
.SHARESHEET_PROFILE_CHANGED.getId()));
// Repeat the loading steps in the new profile:
// SHARESHEET_APP_LOAD_COMPLETE:
- assertThat(logger.event(6).getId(),
+ assertThat(logger.event(5).getId(),
is(ChooserActivityLogger
.SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId()));
- // SHARESHEET_DIRECT_LOAD_COMPLETE:
- assertThat(logger.event(7).getId(),
- is(ChooserActivityLogger
- .SharesheetStandardEvent.SHARESHEET_DIRECT_LOAD_COMPLETE.getId()));
-
- // Ninth is again an artifact of test set-up:
- assertThat(logger.event(8).getId(),
+ // Next is again an artifact of test set-up:
+ assertThat(logger.event(6).getId(),
is(ChooserActivityLogger
.SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
// SHARESHEET_PROFILE_CHANGED:
- assertThat(logger.event(9).getId(),
+ assertThat(logger.event(7).getId(),
is(ChooserActivityLogger.SharesheetStandardEvent
.SHARESHEET_PROFILE_CHANGED.getId()));
// No more events (this profile was already loaded).
- assertThat(logger.numCalls(), is(10));
+ assertThat(logger.numCalls(), is(8));
}
@Test
@@ -2576,12 +2628,12 @@
mActivityRule.launchActivity(chooserIntent);
waitForIdle();
- onView(withText(R.string.resolver_work_tab)).perform(click());
+ onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
waitForIdle();
- onView(withId(R.id.contentPanel))
+ onView(withIdFromRuntimeResource("contentPanel"))
.perform(swipeUp());
- onView(withText(R.string.resolver_cross_profile_blocked))
+ onView(withTextFromRuntimeResource("resolver_cross_profile_blocked"))
.check(matches(isDisplayed()));
}
@@ -2610,12 +2662,12 @@
mActivityRule.launchActivity(chooserIntent);
waitForIdle();
- onView(withId(R.id.contentPanel))
+ onView(withIdFromRuntimeResource("contentPanel"))
.perform(swipeUp());
- onView(withText(R.string.resolver_work_tab)).perform(click());
+ onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
waitForIdle();
- onView(withText(R.string.resolver_no_work_apps_available))
+ onView(withTextFromRuntimeResource("resolver_no_work_apps_available"))
.check(matches(isDisplayed()));
}
@@ -2675,9 +2727,9 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
waitForIdle();
- onView(withId(R.id.contentPanel))
+ onView(withIdFromRuntimeResource("contentPanel"))
.perform(swipeUp());
- onView(withText(R.string.resolver_work_tab)).perform(click());
+ onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
waitForIdle();
assertFalse("Direct share targets were queried on a paused work profile",
@@ -2707,9 +2759,9 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
waitForIdle();
- onView(withId(R.id.contentPanel))
+ onView(withIdFromRuntimeResource("contentPanel"))
.perform(swipeUp());
- onView(withText(R.string.resolver_work_tab)).perform(click());
+ onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
waitForIdle();
assertFalse("Direct share targets were queried on a locked work profile user",
@@ -2734,9 +2786,8 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
final IChooserWrapper wrapper = (IChooserWrapper) activity;
waitForIdle();
- onView(withId(R.id.contentPanel))
- .perform(swipeUp());
- onView(withText(R.string.resolver_work_tab)).perform(click());
+ onView(withIdFromRuntimeResource("contentPanel")).perform(swipeUp());
+ onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
waitForIdle();
assertEquals(3, wrapper.getWorkListAdapter().getCount());
@@ -2765,9 +2816,9 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
waitForIdle();
- onView(withId(R.id.contentPanel))
+ onView(withIdFromRuntimeResource("contentPanel"))
.perform(swipeUp());
- onView(withText(R.string.resolver_work_tab)).perform(click());
+ onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
waitForIdle();
assertFalse("Direct share targets were queried on a locked work profile user",
@@ -2792,9 +2843,9 @@
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
final IChooserWrapper wrapper = (IChooserWrapper) activity;
waitForIdle();
- onView(withId(R.id.contentPanel))
+ onView(withIdFromRuntimeResource("contentPanel"))
.perform(swipeUp());
- onView(withText(R.string.resolver_work_tab)).perform(click());
+ onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click());
waitForIdle();
assertEquals(3, wrapper.getWorkListAdapter().getCount());
@@ -3043,4 +3094,27 @@
eq(UserHandle.SYSTEM)))
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
}
+
+ private Matcher<View> withIdFromRuntimeResource(String id) {
+ return withId(getRuntimeResourceId(id, "id"));
+ }
+
+ private Matcher<View> withTextFromRuntimeResource(String id) {
+ return withText(getRuntimeResourceId(id, "string"));
+ }
+
+ // ChooserWrapperActivity inherits from the framework ChooserActivity, so if the framework
+ // resources have been updated since the framework was last built/pushed, the inherited behavior
+ // (which is the focus of our testing) will still be implemented in terms of the old resource
+ // IDs; then when we try to assert those IDs in tests (e.g. `onView(withText(R.string.foo))`),
+ // the expected values won't match. The tests can instead call this method (with the same
+ // general semantics as Resources#getIdentifier() e.g. `getRuntimeResourceId("foo", "string")`)
+ // to refer to the resource by that name in the runtime chooser, regardless of whether the
+ // framework code on the device is up-to-date.
+ // TODO: is there a better way to do this? (Other than abandoning inheritance-based DI wrapper?)
+ private int getRuntimeResourceId(String name, String defType) {
+ int id = mActivityRule.getActivity().getResources().getIdentifier(name, defType, "android");
+ assertThat(id, greaterThan(0));
+ return id;
+ }
}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 0b8dc3f..92fca36 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -223,6 +223,10 @@
targetSdk="29">
<new-permission name="android.permission.ACCESS_BACKGROUND_LOCATION" />
</split-permission>
+ <split-permission name="android.permission.BODY_SENSORS"
+ targetSdk="33">
+ <new-permission name="android.permission.BODY_SENSORS_BACKGROUND" />
+ </split-permission>
<split-permission name="android.permission.READ_EXTERNAL_STORAGE"
targetSdk="29">
<new-permission name="android.permission.ACCESS_MEDIA_LOCATION" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index e61a665..f17fa3b 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -520,6 +520,8 @@
<permission name="android.permission.LOCK_DEVICE" />
<!-- Permission required for CTS test - CtsSafetyCenterTestCases -->
<permission name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
+ <!-- Permission required for CTS test - CtsSafetyCenterTestCases -->
+ <permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
<!-- Permission required for CTS test - CommunalManagerTest -->
<permission name="android.permission.WRITE_COMMUNAL_STATE" />
<permission name="android.permission.READ_COMMUNAL_STATE" />
diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index 8d3eadb..a9e730d 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -27,8 +27,6 @@
// Note: This field is accessed by native code.
public long mNativeObject; // BLASTBufferQueue*
- private static native long nativeCreateAndUpdate(String name, long surfaceControl, long width,
- long height, int format);
private static native long nativeCreate(String name);
private static native void nativeDestroy(long ptr);
private static native Surface nativeGetSurface(long ptr, boolean includeSurfaceControlHandle);
@@ -40,11 +38,13 @@
long frameNumber);
private static native long nativeGetLastAcquiredFrameNum(long ptr);
private static native void nativeApplyPendingTransactions(long ptr, long frameNumber);
+ private static native boolean nativeIsSameSurfaceControl(long ptr, long surfaceControlPtr);
/** Create a new connection with the surface flinger. */
public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height,
@PixelFormat.Format int format) {
- mNativeObject = nativeCreateAndUpdate(name, sc.mNativeObject, width, height, format);
+ this(name);
+ update(sc, width, height, format);
}
public BLASTBufferQueue(String name) {
@@ -152,4 +152,11 @@
public long getLastAcquiredFrameNum() {
return nativeGetLastAcquiredFrameNum(mNativeObject);
}
+
+ /**
+ * @return True if the associated SurfaceControl has the same handle as {@param sc}.
+ */
+ public boolean isSameSurfaceControl(SurfaceControl sc) {
+ return nativeIsSameSurfaceControl(mNativeObject, sc.mNativeObject);
+ }
}
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index 2b18350..fd4bed1 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -902,6 +902,20 @@
* @param frame The id of the frame being drawn.
*/
void onFrameDraw(long frame);
+
+ /**
+ * Invoked during a frame drawing.
+ *
+ * @param syncResult The result of the draw. Should be a value or a combination of values
+ * from {@link SyncAndDrawResult}
+ * @param frame The id of the frame being drawn.
+ *
+ * @return A {@link FrameCommitCallback} that will report back if the current vsync draws.
+ */
+ default FrameCommitCallback onFrameDraw(@SyncAndDrawResult int syncResult, long frame) {
+ onFrameDraw(frame);
+ return null;
+ }
}
/**
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index b77865f..fc7f84c 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -118,13 +118,13 @@
/**
* Returns whether the outline can be used to clip a View.
* <p>
- * Currently, only Outlines that can be represented as a rectangle, circle,
- * or round rect support clipping.
+ * As of API 33, all Outline shapes support clipping. Prior to API 33, only Outlines that
+ * could be represented as a rectangle, circle, or round rect supported clipping.
*
* @see android.view.View#setClipToOutline(boolean)
*/
public boolean canClip() {
- return mMode != MODE_PATH;
+ return true;
}
/**
diff --git a/graphics/java/android/graphics/RenderEffect.java b/graphics/java/android/graphics/RenderEffect.java
index ad4c3fe..b8a4685 100644
--- a/graphics/java/android/graphics/RenderEffect.java
+++ b/graphics/java/android/graphics/RenderEffect.java
@@ -290,6 +290,22 @@
return new RenderEffect(nativeCreateShaderEffect(shader.getNativeInstance()));
}
+ /**
+ * Create a {@link RenderEffect} that executes the provided {@link RuntimeShader} and passes
+ * the contents of the {@link android.graphics.RenderNode} that this RenderEffect is installed
+ * on as an input to the shader.
+ * @param shader the runtime shader that will bind the inputShaderName to the RenderEffect input
+ * @param uniformShaderName the uniform name defined in the RuntimeShader's program to which
+ * the contents of the RenderNode will be bound
+ */
+ @NonNull
+ public static RenderEffect createRuntimeShaderEffect(
+ @NonNull RuntimeShader shader, @NonNull String uniformShaderName) {
+ return new RenderEffect(
+ nativeCreateRuntimeShaderEffect(shader.getNativeShaderBuilder(),
+ uniformShaderName));
+ }
+
private final long mNativeRenderEffect;
/* only constructed from static factory methods */
@@ -318,5 +334,7 @@
private static native long nativeCreateBlendModeEffect(long dst, long src, int blendmode);
private static native long nativeCreateChainEffect(long outer, long inner);
private static native long nativeCreateShaderEffect(long shader);
+ private static native long nativeCreateRuntimeShaderEffect(
+ long shaderBuilder, String inputShaderName);
private static native long nativeGetFinalizer();
}
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index 107da81..8b32b38 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Bestuur"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Borrel is toegemaak."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Tik om hierdie program te herbegin en maak volskerm oop."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index d724372..8b898c0 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"ያቀናብሩ"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"አረፋ ተሰናብቷል።"</string>
<string name="restart_button_description" msgid="5887656107651190519">"ይህን መተግበሪያ ዳግም ለማስነሳት መታ ያድርጉ እና ወደ ሙሉ ማያ ገጽ ይሂዱ።"</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 7dd1f81..a9eafdd 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"إدارة"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"تم إغلاق الفقاعة."</string>
<string name="restart_button_description" msgid="5887656107651190519">"انقر لإعادة تشغيل هذا التطبيق والانتقال إلى وضع ملء الشاشة."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index 190f7ca..a81d4e3 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"পৰিচালনা কৰক"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"বাবল অগ্ৰাহ্য কৰা হৈছে"</string>
<string name="restart_button_description" msgid="5887656107651190519">"এপ্টো ৰিষ্টাৰ্ট কৰিবলৈ আৰু পূৰ্ণ স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ টিপক।"</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index e33a35f..45e3fdb 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"İdarə edin"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Qabarcıqdan imtina edilib."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Bu tətbiqi sıfırlayaraq tam ekrana keçmək üçün toxunun."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index f59e932..c17b3c4 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljajte"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblačić je odbačen."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Dodirnite da biste restartovali aplikaciju i prešli u režim celog ekrana."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index 3b478f2..bcf7186 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Кіраваць"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Усплывальнае апавяшчэнне адхілена."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Націсніце, каб перазапусціць гэту праграму і перайсці ў поўнаэкранны рэжым."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index 3a77a1c..5f48744 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Управление"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Балончето е отхвърлено."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Докоснете, за да рестартирате това приложение в режим на цял екран."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index 8bfd775..f96d65f 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"ম্যানেজ করুন"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"বাবল বাতিল করা হয়েছে।"</string>
<string name="restart_button_description" msgid="5887656107651190519">"এই অ্যাপ রিস্টার্ট করতে ট্যাপ করুন ও \'ফুল-স্ক্রিন\' মোড ব্যবহার করুন।"</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index d23cc61..1e068c6 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljaj"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblačić je odbačen."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Dodirnite da ponovo pokrenete ovu aplikaciju i aktivirate prikaz preko cijelog ekrana."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 6434e31..97585ef 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gestiona"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"La bombolla s\'ha ignorat."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Toca per reiniciar aquesta aplicació i passar a pantalla completa."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index 3530a7c..7a3a890 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Spravovat"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bublina byla zavřena."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Klepnutím aplikaci restartujete a přejdete na režim celé obrazovky"</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index 89b66e5..4a025ba 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Administrer"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Boblen blev lukket."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Tryk for at genstarte denne app, og gå til fuld skærm."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index b49b446..bacd512 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Verwalten"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble verworfen."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Tippe, um die App im Vollbildmodus neu zu starten."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index ed1d913..f306ba3 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Διαχείριση"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Το συννεφάκι παραβλέφθηκε."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Πατήστε για επανεκκίνηση αυτής της εφαρμογής και ενεργοποίηση πλήρους οθόνης."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index 067e998..1ffbd039 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Tap to restart this app and go full screen."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index 067e998..1ffbd039 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Tap to restart this app and go full screen."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index 067e998..1ffbd039 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Tap to restart this app and go full screen."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index 067e998..1ffbd039 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Tap to restart this app and go full screen."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
index 95c0d01..ffa3a65 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -73,4 +73,7 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Tap to restart this app and go full screen."</string>
+ <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
+ <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
+ <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index 6e5347d..1ca7bfc 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Administrar"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Se descartó el cuadro."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Presiona para reiniciar esta app y acceder al modo de pantalla completa."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index 4820a0f..3d46421 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gestionar"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Burbuja cerrada."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Toca para reiniciar esta aplicación e ir a la pantalla completa."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index 4c94694..4f5d563 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Halda"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Mullist loobuti."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Puudutage rakenduse taaskäivitamiseks ja täisekraanrežiimi aktiveerimiseks."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index afc4292..b76ccc8 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Kudeatu"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Baztertu da globoa."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Saka ezazu aplikazioa berrabiarazteko, eta ezarri pantaila osoko modua."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index e8a0682..aef3c62 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"مدیریت"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"حبابک رد شد."</string>
<string name="restart_button_description" msgid="5887656107651190519">"برای بازراهاندازی این برنامه و تغییر به حالت تمامصفحه، ضربه بزنید."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index f671105..5f76ba4 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Ylläpidä"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Kupla ohitettu."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Napauta, niin sovellus käynnistyy uudelleen ja siirtyy koko näytön tilaan."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 0d0b718..e1843e7 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gérer"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulle ignorée."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Touchez pour redémarrer cette application et passer en plein écran."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index 5652d7e..b3f3349 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gérer"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulle fermée."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Appuyez pour redémarrer cette application et activer le mode plein écran."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index 81bd916..3cdddf3 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Xestionar"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ignorouse a burbulla."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Toca o botón para reiniciar esta aplicación e abrila en pantalla completa."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index 3d408cf2..09d206e 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"મેનેજ કરો"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"બબલ છોડી દેવાયો."</string>
<string name="restart_button_description" msgid="5887656107651190519">"આ ઍપ ફરીથી ચાલુ કરવા માટે ટૅપ કરીને પૂર્ણ સ્ક્રીન કરો."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index 8c93e0a..0ce5114 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"मैनेज करें"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल खारिज किया गया."</string>
<string name="restart_button_description" msgid="5887656107651190519">"इस ऐप्लिकेशन को रीस्टार्ट करने और फ़ुल स्क्रीन पर देखने के लिए टैप करें."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 1f8f982..e8c83f1 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljanje"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblačić odbačen."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Dodirnite da biste ponovo pokrenuli tu aplikaciju i prikazali je na cijelom zaslonu."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index ebd02e5..6d60513 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Kezelés"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Buborék elvetve."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Koppintson az alkalmazás újraindításához és a teljes képernyős mód elindításához."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 29b2052..f1ec076 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Կառավարել"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ամպիկը փակվեց։"</string>
<string name="restart_button_description" msgid="5887656107651190519">"Հպեք՝ հավելվածը վերագործարկելու և լիաէկրան ռեժիմին անցնելու համար։"</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index 6432aef..62dfcb7 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Kelola"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balon ditutup."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Ketuk untuk memulai ulang aplikasi ini dan membuka layar penuh."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 126d1f1..feab362 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Stjórna"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Blöðru lokað."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Ýttu til að endurræsa forritið og sýna það á öllum skjánum."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index ec221b1..bfcd385 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gestisci"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Fumetto ignorato."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Tocca per riavviare l\'app e passare alla modalità a schermo intero."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index b87d10c..7ef5035 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"ניהול"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"הבועה נסגרה."</string>
<string name="restart_button_description" msgid="5887656107651190519">"צריך להקיש כדי להפעיל מחדש את האפליקציה הזו ולעבור למסך מלא."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 51ffca6..fb58abb 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ふきだしが非表示になっています。"</string>
<string name="restart_button_description" msgid="5887656107651190519">"タップしてこのアプリを再起動すると、全画面表示になります。"</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index fc91d72..297d9af 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"მართვა"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ბუშტი დაიხურა."</string>
<string name="restart_button_description" msgid="5887656107651190519">"შეეხეთ ამ აპის გადასატვირთად და გადადით სრულ ეკრანზე."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index 05a905d..7ca2f23 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Басқару"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Қалқыма хабар жабылды."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Бұл қолданбаны қайта қосып, толық экранға өту үшін түртіңіз."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 6a1cb2b..dae2293 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"គ្រប់គ្រង"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"បានច្រានចោលសារលេចឡើង។"</string>
<string name="restart_button_description" msgid="5887656107651190519">"ចុចដើម្បីចាប់ផ្ដើមកម្មវិធីនេះឡើងវិញ រួចចូលប្រើពេញអេក្រង់។"</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index aecb54b..72ba8ea 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"ನಿರ್ವಹಿಸಿ"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ಬಬಲ್ ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
<string name="restart_button_description" msgid="5887656107651190519">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಲು ಮತ್ತು ಪೂರ್ಣ ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ನೋಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index 5af9ca2a..d99abc4 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"관리"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"대화창을 닫았습니다."</string>
<string name="restart_button_description" msgid="5887656107651190519">"탭하여 이 앱을 다시 시작하고 전체 화면으로 이동합니다."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 76f192e..fe25161 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Башкаруу"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Калкып чыкма билдирме жабылды."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Бул колдонмону өчүрүп күйгүзүп, толук экранга өтүү үчүн таптап коюңуз."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index 4ec6313..786d837 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"ຈັດການ"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ປິດ Bubble ໄສ້ແລ້ວ."</string>
<string name="restart_button_description" msgid="5887656107651190519">"ແຕະເພື່ອຣີສະຕາດແອັບນີ້ ແລະ ໃຊ້ແບບເຕັມຈໍ."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index 8630e91..32bdfc4 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Tvarkyti"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Debesėlio atsisakyta."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Palieskite, kad paleistumėte iš naujo šią programą ir įjungtumėte viso ekrano režimą."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index b095b88..5d0f318 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Pārvaldīt"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Burbulis ir noraidīts."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Pieskarieties, lai restartētu šo lietotni un pārietu pilnekrāna režīmā."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index 184fe9d..8c2e44c 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Управувајте"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Балончето е отфрлено."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Допрете за да ја рестартирате апликацијава и да ја отворите на цел екран."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index f1bfe9a..6c8883a 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"മാനേജ് ചെയ്യുക"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ബബിൾ ഡിസ്മിസ് ചെയ്തു."</string>
<string name="restart_button_description" msgid="5887656107651190519">"ഈ ആപ്പ് റീസ്റ്റാർട്ട് ചെയ്ത് പൂർണ്ണ സ്ക്രീനിലേക്ക് മാറാൻ ടാപ്പ് ചെയ്യുക."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index 8b8cb95..d297923 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Удирдах"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Бөмбөлгийг үл хэрэгссэн."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Энэ аппыг дахин эхлүүлж, бүтэн дэлгэцэд орохын тулд товшино уу."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index c11af7b..3d9b53c 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"व्यवस्थापित करा"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल डिसमिस केला."</string>
<string name="restart_button_description" msgid="5887656107651190519">"हे अॅप रीस्टार्ट करण्यासाठी आणि फुल स्क्रीन करण्यासाठी टॅप करा."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index 5493ce5..0aafb59 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Urus"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Gelembung diketepikan."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Ketik untuk memulakan semula apl ini dan menggunakan skrin penuh."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index e1d17f8..899c607 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"စီမံရန်"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ပူဖောင်းကွက် ဖယ်လိုက်သည်။"</string>
<string name="restart_button_description" msgid="5887656107651190519">"ဤအက်ပ်ကို ပြန်စပြီး ဖန်သားပြင်အပြည့်လုပ်ရန် တို့ပါ။"</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 87bc7da..60891d3 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Administrer"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Boblen er avvist."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Trykk for å starte denne appen på nytt og vise den i fullskjerm."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index 12df158..8bd6907 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"व्यवस्थापन गर्नुहोस्"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल हटाइयो।"</string>
<string name="restart_button_description" msgid="5887656107651190519">"यो एप रिस्टार्ट गर्न ट्याप गर्नुहोस् र फुल स्क्रिन मोडमा जानुहोस्।"</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index f83ad22..3fddf34 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Beheren"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubbel gesloten."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Tik om deze app opnieuw te starten en te openen op het volledige scherm."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index 14f92c8..217556e 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ବବଲ୍ ଖାରଜ କରାଯାଇଛି।"</string>
<string name="restart_button_description" msgid="5887656107651190519">"ଏହି ଆପକୁ ରିଷ୍ଟାର୍ଟ କରି ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index e09f53adb..dc4dae1 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ਬਬਲ ਨੂੰ ਖਾਰਜ ਕੀਤਾ ਗਿਆ।"</string>
<string name="restart_button_description" msgid="5887656107651190519">"ਇਸ ਐਪ ਨੂੰ ਮੁੜ-ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ ਅਤੇ ਪੂਰੀ ਸਕ੍ਰੀਨ ਮੋਡ \'ਤੇ ਜਾਓ।"</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index a2ef997..fccd138 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Zarządzaj"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Zamknięto dymek"</string>
<string name="restart_button_description" msgid="5887656107651190519">"Kliknij, by uruchomić tę aplikację ponownie i przejść w tryb pełnoekranowy."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 1300e53..5664030 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gerenciar"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão dispensado."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Toque para reiniciar o app e usar tela cheia."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index f3314f8..abe6a01 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gerir"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão ignorado."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Toque para reiniciar esta app e ficar em ecrã inteiro."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 1300e53..5664030 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gerenciar"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão dispensado."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Toque para reiniciar o app e usar tela cheia."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 01f96c8..39dec90 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gestionați"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balonul a fost respins."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Atingeți ca să reporniți aplicația și să treceți în modul ecran complet."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index 6a0e9c1..e3c2215 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Настроить"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Всплывающий чат закрыт."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Нажмите, чтобы перезапустить приложение и перейти в полноэкранный режим."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index d7ed246..efaf1f3 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"කළමනා කරන්න"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"බුබුල ඉවත දමා ඇත."</string>
<string name="restart_button_description" msgid="5887656107651190519">"මෙම යෙදුම යළි ඇරඹීමට සහ පූර්ණ තිරයට යාමට තට්ටු කරන්න."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index 13fd58f..a827153 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Spravovať"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bublina bola zavretá."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Klepnutím reštartujete túto aplikáciu a prejdete do režimu celej obrazovky."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index 6a68069..7437654 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljanje"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblaček je bil opuščen."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Dotaknite se za vnovični zagon te aplikacije in preklop v celozaslonski način."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index 7382a48..bda10c8 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Menaxho"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Flluska u hoq."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Trokit për ta rinisur këtë aplikacion dhe për të kaluar në ekranin e plotë."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index c0c1e3f..98e13be 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Управљајте"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Облачић је одбачен."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Додирните да бисте рестартовали апликацију и прешли у режим целог екрана."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 34254d9..3080088 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Hantera"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubblan ignorerades."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Tryck för att starta om appen i helskärmsläge."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 82a9f14..9fb7460 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Dhibiti"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Umeondoa kiputo."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Gusa ili uzime na uwashe programu hii, kisha nenda kwenye skrini nzima."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 0ed778a..d7f17aa 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"நிர்வகி"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"குமிழ் நிராகரிக்கப்பட்டது."</string>
<string name="restart_button_description" msgid="5887656107651190519">"தட்டுவதன் மூலம் இந்த ஆப்ஸை மீண்டும் தொடங்கலாம், முழுத்திரையில் பார்க்கலாம்."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 8fef67b..4e421b5 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"మేనేజ్ చేయండి"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"బబుల్ విస్మరించబడింది."</string>
<string name="restart_button_description" msgid="5887656107651190519">"ఈ యాప్ను రీస్టార్ట్ చేయడానికి ట్యాప్ చేసి, ఆపై పూర్తి స్క్రీన్లోకి వెళ్లండి."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 06b04f1..52f94e6 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"จัดการ"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ปิดบับเบิลแล้ว"</string>
<string name="restart_button_description" msgid="5887656107651190519">"แตะเพื่อรีสตาร์ทแอปนี้และแสดงแบบเต็มหน้าจอ"</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 62642c1..d7b671d 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Pamahalaan"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Na-dismiss na ang bubble."</string>
<string name="restart_button_description" msgid="5887656107651190519">"I-tap para i-restart ang app na ito at mag-full screen."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index 971520a..c618f6c 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Yönet"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balon kapatıldı."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Bu uygulamayı yeniden başlatmak ve tam ekrana geçmek için dokunun."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index 3014735..ec2e550 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Налаштувати"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Спливаюче сповіщення закрито."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Натисніть, щоб перезапустити додаток і перейти в повноекранний режим."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 07319ef..18e1e51 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"نظم کریں"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"بلبلہ برخاست کر دیا گیا۔"</string>
<string name="restart_button_description" msgid="5887656107651190519">"یہ ایپ دوبارہ شروع کرنے کے لیے تھپتھپائیں اور پوری اسکرین پر جائیں۔"</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 4c79d64..f6c7ed2 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Boshqarish"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulutcha yopildi."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Bu ilovani qaytadan ishga tushirish va butun ekranda ochish uchun bosing."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index b9f23cd..1cab8e7 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Quản lý"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Đã đóng bong bóng."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Nhấn để khởi động lại ứng dụng này và xem ở chế độ toàn màn hình."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index c007258..dc12c4f 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"已关闭对话泡。"</string>
<string name="restart_button_description" msgid="5887656107651190519">"点按即可重启此应用并进入全屏模式。"</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index 5e33677..fe114ac 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"對話氣泡已關閉。"</string>
<string name="restart_button_description" msgid="5887656107651190519">"輕按即可重新開啟此應用程式並放大至全螢幕。"</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index 2439a97..0e4fc30 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"已關閉泡泡。"</string>
<string name="restart_button_description" msgid="5887656107651190519">"輕觸即可重新啟動這個應用程式並進入全螢幕模式。"</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index 20128f6..f563f1f 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -73,4 +73,10 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Phatha"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ibhamuza licashisiwe."</string>
<string name="restart_button_description" msgid="5887656107651190519">"Thepha ukuze uqale kabusha lolu hlelo lokusebenza uphinde uye kusikrini esigcwele."</string>
+ <!-- no translation found for camera_compat_treatment_suggested_button_description (8103916969024076767) -->
+ <skip />
+ <!-- no translation found for camera_compat_treatment_applied_button_description (2944157113330703897) -->
+ <skip />
+ <!-- no translation found for camera_compat_dismiss_button_description (2795364433503817511) -->
+ <skip />
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index a9e0c48..f7c92fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -123,7 +123,7 @@
mDividerWindowWidth = mDividerSize + 2 * mDividerInsets;
mRootBounds.set(configuration.windowConfiguration.getBounds());
- mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds);
+ mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null);
resetDividerPosition();
}
@@ -201,7 +201,7 @@
mTempRect.set(mRootBounds);
mRootBounds.set(rootBounds);
mRotation = rotation;
- mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds);
+ mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null);
initDividerPosition(mTempRect);
if (mInitialized) {
@@ -212,8 +212,9 @@
return true;
}
- /** Rotate the layout to specific rotation and assume its new bounds. */
- public void rotateTo(int newRotation) {
+ /** Rotate the layout to specific rotation and calculate new bounds. The stable insets value
+ * should be calculated by display layout. */
+ public void rotateTo(int newRotation, Rect stableInsets) {
final int rotationDelta = (newRotation - mRotation + 4) % 4;
final boolean changeOrient = (rotationDelta % 2) != 0;
@@ -223,11 +224,11 @@
tmpRect.set(mRootBounds.top, mRootBounds.left, mRootBounds.bottom, mRootBounds.right);
}
- final Configuration config = new Configuration();
- config.setTo(mContext.getResources().getConfiguration());
- config.orientation = mOrientation;
- config.windowConfiguration.setBounds(tmpRect);
- updateConfiguration(config);
+ // We only need new bounds here, other configuration should be update later.
+ mTempRect.set(mRootBounds);
+ mRootBounds.set(tmpRect);
+ mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, stableInsets);
+ initDividerPosition(mTempRect);
}
private void initDividerPosition(Rect oldBounds) {
@@ -372,7 +373,8 @@
return mDividerSnapAlgorithm.calculateSnapTarget(position, velocity, hardDismiss);
}
- private DividerSnapAlgorithm getSnapAlgorithm(Context context, Rect rootBounds) {
+ private DividerSnapAlgorithm getSnapAlgorithm(Context context, Rect rootBounds,
+ @Nullable Rect stableInsets) {
final boolean isLandscape = isLandscape(rootBounds);
return new DividerSnapAlgorithm(
context.getResources(),
@@ -380,7 +382,7 @@
rootBounds.height(),
mDividerSize,
!isLandscape,
- getDisplayInsets(context),
+ stableInsets != null ? stableInsets : getDisplayInsets(context),
isLandscape ? DOCKED_LEFT : DOCKED_TOP /* dockSide */);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index d70857a4..4f01dc6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -309,10 +309,11 @@
PipAnimationController pipAnimationController, PipBoundsAlgorithm pipBoundsAlgorithm,
PipBoundsState pipBoundsState, PipTransitionState pipTransitionState,
PhonePipMenuController pipMenuController,
- PipSurfaceTransactionHelper pipSurfaceTransactionHelper) {
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ Optional<SplitScreenController> splitScreenOptional) {
return new PipTransition(context, pipBoundsState, pipTransitionState, pipMenuController,
pipBoundsAlgorithm, pipAnimationController, transitions, shellTaskOrganizer,
- pipSurfaceTransactionHelper);
+ pipSurfaceTransactionHelper, splitScreenOptional);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index f0b2716..a8d4d1c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -25,6 +25,8 @@
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP;
import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
import static com.android.wm.shell.pip.PipAnimationController.FRACTION_START;
@@ -40,6 +42,10 @@
import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection;
import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
import static com.android.wm.shell.pip.PipAnimationController.isRemovePipDirection;
+import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP_TO_SPLIT;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -394,6 +400,18 @@
mPipUiEventLoggerLogger.log(
PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN);
final WindowContainerTransaction wct = new WindowContainerTransaction();
+
+ if (ENABLE_SHELL_TRANSITIONS) {
+ if (requestEnterSplit && mSplitScreenOptional.isPresent()) {
+ mSplitScreenOptional.get().prepareEnterSplitScreen(wct, mTaskInfo,
+ isPipTopLeft()
+ ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT);
+ mPipTransitionController.startExitTransition(
+ TRANSIT_EXIT_PIP_TO_SPLIT, wct, null /* destinationBounds */);
+ return;
+ }
+ }
+
final Rect destinationBounds = mPipBoundsState.getDisplayBounds();
final int direction = syncWithSplitScreenBounds(destinationBounds, requestEnterSplit)
? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
@@ -414,7 +432,7 @@
mPipTransitionState.setTransitionState(PipTransitionState.EXITING_PIP);
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- mPipTransitionController.startTransition(destinationBounds, wct);
+ mPipTransitionController.startExitTransition(TRANSIT_EXIT_PIP, wct, destinationBounds);
return;
}
mSyncTransactionQueue.queue(wct);
@@ -479,7 +497,8 @@
wct.setBounds(mToken, null);
wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
wct.reorder(mToken, false);
- mPipTransitionController.startTransition(null, wct);
+ mPipTransitionController.startExitTransition(TRANSIT_REMOVE_PIP, wct,
+ null /* destinationBounds */);
return;
}
@@ -882,7 +901,10 @@
if (animator == null || !animator.isRunning()
|| animator.getTransitionDirection() != TRANSITION_DIRECTION_TO_PIP) {
final boolean rotatingPip = mPipTransitionState.isInPip() && fromRotation;
- if (rotatingPip && mWaitForFixedRotation && mHasFadeOut) {
+ if (rotatingPip && Transitions.ENABLE_SHELL_TRANSITIONS) {
+ // The animation and surface update will be handled by the shell transition handler.
+ mPipBoundsState.setBounds(destinationBoundsOut);
+ } else if (rotatingPip && mWaitForFixedRotation && mHasFadeOut) {
// The position will be used by fade-in animation when the fixed rotation is done.
mPipBoundsState.setBounds(destinationBoundsOut);
} else if (rotatingPip) {
@@ -1277,7 +1299,8 @@
public void applyFinishBoundsResize(@NonNull WindowContainerTransaction wct,
@PipAnimationController.TransitionDirection int direction, boolean wasPipTopLeft) {
if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
- mSplitScreenOptional.get().enterSplitScreen(mTaskInfo.taskId, wasPipTopLeft, wct);
+ mSplitScreenOptional.ifPresent(splitScreenController ->
+ splitScreenController.enterSplitScreen(mTaskInfo.taskId, wasPipTopLeft, wct));
} else {
mTaskOrganizer.applyTransaction(wct);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 0c443ce..e440feb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -19,6 +19,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.util.RotationUtils.deltaRotation;
+import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_PIP;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
@@ -29,8 +30,9 @@
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection;
import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
-import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP_TO_SPLIT;
import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
+import static com.android.wm.shell.transition.Transitions.isOpeningType;
import android.app.ActivityManager;
import android.app.TaskInfo;
@@ -50,8 +52,11 @@
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions;
+import java.util.Optional;
+
/**
* Implementation of transitions for PiP on phone. Responsible for enter (alpha, bounds) and
* exit animation.
@@ -63,6 +68,7 @@
private final PipTransitionState mPipTransitionState;
private final int mEnterExitAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
+ private final Optional<SplitScreenController> mSplitScreenOptional;
private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
private Transitions.TransitionFinishCallback mFinishCallback;
private Rect mExitDestinationBounds = new Rect();
@@ -76,13 +82,15 @@
PipAnimationController pipAnimationController,
Transitions transitions,
@NonNull ShellTaskOrganizer shellTaskOrganizer,
- PipSurfaceTransactionHelper pipSurfaceTransactionHelper) {
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ Optional<SplitScreenController> splitScreenOptional) {
super(pipBoundsState, pipMenuController, pipBoundsAlgorithm,
pipAnimationController, transitions, shellTaskOrganizer);
mPipTransitionState = pipTransitionState;
mEnterExitAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipResizeAnimationDuration);
mSurfaceTransactionHelper = pipSurfaceTransactionHelper;
+ mSplitScreenOptional = splitScreenOptional;
}
@Override
@@ -100,13 +108,12 @@
}
@Override
- public void startTransition(Rect destinationBounds, WindowContainerTransaction out) {
+ public void startExitTransition(int type, WindowContainerTransaction out,
+ @Nullable Rect destinationBounds) {
if (destinationBounds != null) {
mExitDestinationBounds.set(destinationBounds);
- mExitTransition = mTransitions.startTransition(TRANSIT_EXIT_PIP, out, this);
- } else {
- mTransitions.startTransition(TRANSIT_REMOVE_PIP, out, this);
}
+ mExitTransition = mTransitions.startTransition(type, out, this);
}
@Override
@@ -115,9 +122,15 @@
@android.annotation.NonNull SurfaceControl.Transaction startTransaction,
@android.annotation.NonNull SurfaceControl.Transaction finishTransaction,
@android.annotation.NonNull Transitions.TransitionFinishCallback finishCallback) {
-
- if (mExitTransition == transition || info.getType() == TRANSIT_EXIT_PIP) {
+ final int type = info.getType();
+ if (mExitTransition == transition) {
mExitTransition = null;
+
+ if (type == TRANSIT_EXIT_PIP_TO_SPLIT) {
+ return startExitToSplitAnimation(
+ info, startTransaction, finishTransaction, finishCallback);
+ }
+
if (info.getChanges().size() == 1) {
if (mFinishCallback != null) {
mFinishCallback.onTransitionFinished(null, null);
@@ -137,7 +150,7 @@
}
}
- if (info.getType() == TRANSIT_REMOVE_PIP) {
+ if (type == TRANSIT_REMOVE_PIP) {
if (mFinishCallback != null) {
mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
mFinishCallback = null;
@@ -153,7 +166,26 @@
// We only support TRANSIT_PIP type (from RootWindowContainer) or TRANSIT_OPEN (from apps
// that enter PiP instantly on opening, mostly from CTS/Flicker tests)
- if (info.getType() != TRANSIT_PIP && info.getType() != TRANSIT_OPEN) {
+ if (type != TRANSIT_PIP && type != TRANSIT_OPEN) {
+ // In case the PIP window is part of rotation transition, reset the bounds and rounded
+ // corner.
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change.getMode() == TRANSIT_CHANGE && change.getTaskInfo() != null
+ && change.getTaskInfo().configuration.windowConfiguration.getWindowingMode()
+ == WINDOWING_MODE_PINNED) {
+ final SurfaceControl leash = change.getLeash();
+ final Rect destBounds = mPipBoundsState.getBounds();
+ final boolean isInPip = mPipTransitionState.isInPip();
+ mSurfaceTransactionHelper
+ .crop(startTransaction, leash, destBounds)
+ .round(startTransaction, leash, isInPip);
+ mSurfaceTransactionHelper
+ .crop(finishTransaction, leash, destBounds)
+ .round(finishTransaction, leash, isInPip);
+ break;
+ }
+ }
return false;
}
@@ -199,7 +231,6 @@
@NonNull TransitionRequestInfo request) {
if (request.getType() == TRANSIT_PIP) {
WindowContainerTransaction wct = new WindowContainerTransaction();
- mPipTransitionState.setTransitionState(PipTransitionState.ENTRY_SCHEDULED);
if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
wct.setActivityWindowingMode(request.getTriggerTask().token,
WINDOWING_MODE_UNDEFINED);
@@ -349,6 +380,40 @@
return true;
}
+ private boolean startExitToSplitAnimation(TransitionInfo info,
+ SurfaceControl.Transaction startTransaction,
+ SurfaceControl.Transaction finishTransaction,
+ Transitions.TransitionFinishCallback finishCallback) {
+ final int changeSize = info.getChanges().size();
+ if (changeSize < 4) {
+ throw new RuntimeException(
+ "Got an exit-pip-to-split transition with unexpected change-list");
+ }
+ for (int i = changeSize - 1; i >= 0; i--) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ final int mode = change.getMode();
+
+ if (mode == TRANSIT_CHANGE && change.getParent() != null) {
+ // TODO: perform resize/expand animation for reparented child task.
+ continue;
+ }
+
+ if (isOpeningType(mode) && change.getParent() == null) {
+ final SurfaceControl leash = change.getLeash();
+ final Rect endBounds = change.getEndAbsBounds();
+ startTransaction
+ .show(leash)
+ .setAlpha(leash, 1f)
+ .setPosition(leash, endBounds.left, endBounds.top)
+ .setWindowCrop(leash, endBounds.width(), endBounds.height());
+ }
+ }
+ mSplitScreenOptional.get().finishEnterSplitScreen(startTransaction);
+ startTransaction.apply();
+ finishCallback.onTransitionFinished(null, null);
+ return true;
+ }
+
private void finishResizeForMenu(Rect destinationBounds) {
mPipMenuController.movePipMenu(null, null, destinationBounds);
mPipMenuController.updateMenuBounds(destinationBounds);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 376f329..1c8b9bc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -20,6 +20,7 @@
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
+import android.annotation.Nullable;
import android.app.PictureInPictureParams;
import android.app.TaskInfo;
import android.content.ComponentName;
@@ -98,9 +99,10 @@
}
/**
- * Called when the Shell wants to starts a transition/animation.
+ * Called when the Shell wants to start an exit Pip transition/animation.
*/
- public void startTransition(Rect destinationBounds, WindowContainerTransaction out) {
+ public void startExitTransition(int type, WindowContainerTransaction out,
+ @Nullable Rect destinationBounds) {
// Default implementation does nothing.
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index a006f30..7decb54 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -25,6 +25,7 @@
import android.app.TaskInfo;
import android.content.Context;
import android.os.RemoteException;
+import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -291,6 +292,7 @@
* Invalidates this instance, preventing future calls from updating the controller.
*/
void invalidate() {
+ Slog.d("b/206648922", "invalidating controller: " + mController);
mController = null;
}
@@ -316,6 +318,8 @@
(controller) -> out[0] = controller.getRecentTasks(maxNum, flags, userId)
.toArray(new GroupedRecentTaskInfo[0]),
true /* blocking */);
+ Slog.d("b/206648922", "getRecentTasks(" + maxNum + "): " + out[0]
+ + " mController=" + mController);
return out[0];
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
index 1ba1d22..122fc9f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
@@ -19,7 +19,6 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
-import android.graphics.Rect;
import android.view.SurfaceSession;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -45,11 +44,6 @@
stageTaskUnfoldController);
}
- void moveToTop(Rect rootBounds, WindowContainerTransaction wct) {
- final WindowContainerToken rootToken = mRootTaskInfo.token;
- wct.setBounds(rootToken, rootBounds).reorder(rootToken, true /* onTop */);
- }
-
boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) {
// No matter if the root task is empty or not, moving the root to bottom because it no
// longer preserves visible child task.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index a91dfe1..448773a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -76,12 +76,6 @@
}
/**
- * Called when the keyguard occluded state changes.
- * @param occluded Indicates if the keyguard is now occluded.
- */
- void onKeyguardOccludedChanged(boolean occluded);
-
- /**
* Called when the visibility of the keyguard changes.
* @param showing Indicates if the keyguard is now visible.
*/
@@ -90,9 +84,6 @@
/** Called when device waking up finished. */
void onFinishedWakingUp();
- /** Called when device going to sleep finished. */
- void onFinishedGoingToSleep();
-
/** Get a string representation of a stage type */
static String stageTypeToString(@StageType int stage) {
switch (stage) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 39ad536..6921448 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -26,6 +26,7 @@
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
+import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
@@ -238,6 +239,15 @@
enterSplitScreen(taskId, leftOrTop, new WindowContainerTransaction());
}
+ public void prepareEnterSplitScreen(WindowContainerTransaction wct,
+ ActivityManager.RunningTaskInfo taskInfo, int startPosition) {
+ mStageCoordinator.prepareEnterSplitScreen(wct, taskInfo, startPosition);
+ }
+
+ public void finishEnterSplitScreen(SurfaceControl.Transaction t) {
+ mStageCoordinator.finishEnterSplitScreen(t);
+ }
+
public void enterSplitScreen(int taskId, boolean leftOrTop, WindowContainerTransaction wct) {
final int stageType = isSplitScreenVisible() ? STAGE_TYPE_UNDEFINED : STAGE_TYPE_SIDE;
final int stagePosition =
@@ -249,10 +259,6 @@
mStageCoordinator.exitSplitScreen(toTopTaskId, exitReason);
}
- public void onKeyguardOccludedChanged(boolean occluded) {
- mStageCoordinator.onKeyguardOccludedChanged(occluded);
- }
-
public void onKeyguardVisibilityChanged(boolean showing) {
mStageCoordinator.onKeyguardVisibilityChanged(showing);
}
@@ -261,10 +267,6 @@
mStageCoordinator.onFinishedWakingUp();
}
- public void onFinishedGoingToSleep() {
- mStageCoordinator.onFinishedGoingToSleep();
- }
-
public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
mStageCoordinator.exitSplitScreenOnHide(exitSplitScreenOnHide);
}
@@ -318,7 +320,7 @@
public void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
@Nullable Bundle options) {
- if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
+ if (!ENABLE_SHELL_TRANSITIONS) {
startIntentLegacy(intent, fillInIntent, position, options);
return;
}
@@ -374,7 +376,8 @@
}
RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel, RemoteAnimationTarget[] apps) {
- if (apps.length < 2) return null;
+ if (ENABLE_SHELL_TRANSITIONS || apps.length < 2) return null;
+ // TODO(b/206487881): Integrate this with shell transition.
final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
.setContainerLayer()
.setName("RecentsAnimationSplitTasks")
@@ -491,13 +494,6 @@
}
@Override
- public void onKeyguardOccludedChanged(boolean occluded) {
- mMainExecutor.execute(() -> {
- SplitScreenController.this.onKeyguardOccludedChanged(occluded);
- });
- }
-
- @Override
public void registerSplitScreenListener(SplitScreenListener listener, Executor executor) {
if (mExecutors.containsKey(listener)) return;
@@ -538,13 +534,6 @@
SplitScreenController.this.onFinishedWakingUp();
});
}
-
- @Override
- public void onFinishedGoingToSleep() {
- mMainExecutor.execute(() -> {
- SplitScreenController.this.onFinishedGoingToSleep();
- });
- }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index 54d8ece..0aa8d7e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -28,7 +28,8 @@
import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS_SNAP;
-import static com.android.wm.shell.transition.Transitions.isOpeningType;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -148,7 +149,7 @@
t.setWindowCrop(leash, change.getEndAbsBounds().width(),
change.getEndAbsBounds().height());
}
- boolean isOpening = isOpeningType(info.getType());
+ boolean isOpening = isOpeningTransition(info);
if (isOpening && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
// fade in
startExampleAnimation(leash, true /* show */);
@@ -305,6 +306,12 @@
mTransitions.getAnimExecutor().execute(va::start);
}
+ private boolean isOpeningTransition(TransitionInfo info) {
+ return Transitions.isOpeningType(info.getType())
+ || info.getType() == TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE
+ || info.getType() == TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
+ }
+
/** Bundled information of dismiss transition. */
static class DismissTransition {
IBinder mTransition;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 28f838b..4c28be0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -46,7 +46,7 @@
import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
import static com.android.wm.shell.splitscreen.SplitScreenTransitions.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
-import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS_SNAP;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
import static com.android.wm.shell.transition.Transitions.isClosingType;
import static com.android.wm.shell.transition.Transitions.isOpeningType;
@@ -58,6 +58,7 @@
import android.app.ActivityTaskManager;
import android.app.WindowConfiguration;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.devicestate.DeviceStateManager;
import android.os.Bundle;
@@ -88,6 +89,7 @@
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitLayout;
@@ -134,6 +136,7 @@
private final SideStage mSideStage;
private final StageListenerImpl mSideStageListener = new StageListenerImpl();
private final StageTaskUnfoldController mSideUnfoldController;
+ private final DisplayLayout mDisplayLayout;
@SplitPosition
private int mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT;
@@ -157,8 +160,6 @@
// and exit, since exit itself can trigger a number of changes that update the stages.
private boolean mShouldUpdateRecents;
private boolean mExitSplitScreenOnHide;
- private boolean mKeyguardOccluded;
- private boolean mDeviceSleep;
/** The target stage to dismiss to when unlock after folded. */
@StageType
@@ -171,6 +172,7 @@
// properly for the animation itself.
mSplitLayout.release();
mSplitLayout.resetDividerPosition();
+ mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
}
};
@@ -236,6 +238,7 @@
mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
mOnTransitionAnimationComplete);
mDisplayController.addDisplayWindowListener(this);
+ mDisplayLayout = new DisplayLayout(displayController.getDisplayLayout(displayId));
transitions.addHandler(this);
}
@@ -269,6 +272,7 @@
mLogger = logger;
mRecentTasks = recentTasks;
mDisplayController.addDisplayWindowListener(this);
+ mDisplayLayout = new DisplayLayout();
transitions.addHandler(this);
}
@@ -320,7 +324,14 @@
if (!evictWct.isEmpty()) {
wct.merge(evictWct, true /* transfer */);
}
- mTaskOrganizer.applyTransaction(wct);
+
+ if (ENABLE_SHELL_TRANSITIONS) {
+ prepareEnterSplitScreen(wct);
+ mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE,
+ wct, null, this);
+ } else {
+ mTaskOrganizer.applyTransaction(wct);
+ }
return true;
}
@@ -372,6 +383,9 @@
// Init divider first to make divider leash for remote animation target.
mSplitLayout.init();
final WindowContainerTransaction wct = new WindowContainerTransaction();
+ final WindowContainerTransaction evictWct = new WindowContainerTransaction();
+ prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
+ prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct);
// Need to add another wrapper here in shell so that we can inject the divider bar
// and also manage the process elevation via setRunningRemote
IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
@@ -392,6 +406,7 @@
new IRemoteAnimationFinishedCallback.Stub() {
@Override
public void onAnimationFinished() throws RemoteException {
+ mSyncQueue.queue(evictWct);
mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
finishedCallback.onAnimationFinished();
}
@@ -413,6 +428,7 @@
@Override
public void onAnimationCancelled() {
+ mSyncQueue.queue(evictWct);
mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
try {
adapter.getRunner().onAnimationCancelled();
@@ -436,10 +452,14 @@
setSideStagePosition(sidePosition, wct);
mSplitLayout.setDivideRatio(splitRatio);
- // Build a request WCT that will launch both apps such that task 0 is on the main stage
- // while task 1 is on the side stage.
- mMainStage.activate(getMainStageBounds(), wct, false /* reparent */);
- mSideStage.setBounds(getSideStageBounds(), wct);
+ if (mMainStage.isActive()) {
+ mMainStage.moveToTop(getMainStageBounds(), wct);
+ } else {
+ // Build a request WCT that will launch both apps such that task 0 is on the main stage
+ // while task 1 is on the side stage.
+ mMainStage.activate(getMainStageBounds(), wct, false /* reparent */);
+ }
+ mSideStage.moveToTop(getSideStageBounds(), wct);
// Make sure the launch options will put tasks in the corresponding split roots
addActivityOptions(mainOptions, mMainStage);
@@ -566,29 +586,54 @@
mTaskOrganizer.applyTransaction(wct);
}
- void onKeyguardOccludedChanged(boolean occluded) {
- // Do not exit split directly, because it needs to wait for task info update to determine
- // which task should remain on top after split dismissed.
- mKeyguardOccluded = occluded;
- }
-
void onKeyguardVisibilityChanged(boolean showing) {
- if (!showing && mMainStage.isActive()
- && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
- exitSplitScreen(mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
- EXIT_REASON_DEVICE_FOLDED);
+ if (!mMainStage.isActive()) {
+ return;
+ }
+
+ if (ENABLE_SHELL_TRANSITIONS) {
+ // Update divider visibility so it won't float on top of keyguard.
+ setDividerVisibility(!showing, null /* transaction */);
+ }
+
+ if (!showing && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
+ if (ENABLE_SHELL_TRANSITIONS) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ prepareExitSplitScreen(mTopStageAfterFoldDismiss, wct);
+ mSplitTransitions.startDismissTransition(null /* transition */, wct, this,
+ mTopStageAfterFoldDismiss, EXIT_REASON_DEVICE_FOLDED);
+ } else {
+ exitSplitScreen(
+ mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
+ EXIT_REASON_DEVICE_FOLDED);
+ }
}
}
void onFinishedWakingUp() {
- if (mMainStage.isActive()) {
- exitSplitScreenIfKeyguardOccluded();
+ if (!mMainStage.isActive()) {
+ return;
}
- mDeviceSleep = false;
- }
- void onFinishedGoingToSleep() {
- mDeviceSleep = true;
+ // Check if there's only one stage visible while keyguard occluded.
+ final boolean mainStageVisible = mMainStage.mRootTaskInfo.isVisible;
+ final boolean oneStageVisible =
+ mMainStage.mRootTaskInfo.isVisible != mSideStage.mRootTaskInfo.isVisible;
+ if (oneStageVisible) {
+ // Dismiss split because there's show-when-locked activity showing on top of keyguard.
+ // Also make sure the task contains show-when-locked activity remains on top after split
+ // dismissed.
+ if (!ENABLE_SHELL_TRANSITIONS) {
+ final StageTaskListener toTop = mainStageVisible ? mMainStage : mSideStage;
+ exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
+ } else {
+ final int dismissTop = mainStageVisible ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ prepareExitSplitScreen(dismissTop, wct);
+ mSplitTransitions.startDismissTransition(null /* transition */, wct, this,
+ dismissTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
+ }
+ }
}
void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
@@ -619,19 +664,6 @@
applyExitSplitScreen(childrenToTop, wct, exitReason);
}
- private void exitSplitScreenIfKeyguardOccluded() {
- final boolean mainStageVisible = mMainStageListener.mVisible;
- final boolean oneStageVisible = mainStageVisible ^ mSideStageListener.mVisible;
- if (mDeviceSleep && mKeyguardOccluded && oneStageVisible) {
- // Only the stages include show-when-locked activity is visible while keyguard occluded.
- // Dismiss split because there's show-when-locked activity showing on top of keyguard.
- // Also make sure the task contains show-when-locked activity remains on top after split
- // dismissed.
- final StageTaskListener toTop = mainStageVisible ? mMainStage : mSideStage;
- exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
- }
- }
-
private void applyExitSplitScreen(StageTaskListener childrenToTop,
WindowContainerTransaction wct, @ExitReason int exitReason) {
mRecentTasks.ifPresent(recentTasks -> {
@@ -681,6 +713,10 @@
case EXIT_REASON_APP_FINISHED:
// One of the children enters PiP
case EXIT_REASON_CHILD_TASK_ENTER_PIP:
+ // One of the apps occludes lock screen.
+ case EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP:
+ // User has unlocked the device after folded
+ case EXIT_REASON_DEVICE_FOLDED:
return true;
default:
return false;
@@ -692,12 +728,47 @@
* an existing WindowContainerTransaction (rather than applying immediately). This is intended
* to be used when exiting split might be bundled with other window operations.
*/
- void prepareExitSplitScreen(@StageType int stageToTop,
+ private void prepareExitSplitScreen(@StageType int stageToTop,
@NonNull WindowContainerTransaction wct) {
+ if (!mMainStage.isActive()) return;
mSideStage.removeAllTasks(wct, stageToTop == STAGE_TYPE_SIDE);
mMainStage.deactivate(wct, stageToTop == STAGE_TYPE_MAIN);
}
+ private void prepareEnterSplitScreen(WindowContainerTransaction wct) {
+ prepareEnterSplitScreen(wct, null /* taskInfo */, SPLIT_POSITION_UNDEFINED);
+ }
+
+ /**
+ * Prepare transaction to active split screen. If there's a task indicated, the task will be put
+ * into side stage.
+ */
+ void prepareEnterSplitScreen(WindowContainerTransaction wct,
+ @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
+ if (mMainStage.isActive()) return;
+
+ if (taskInfo != null) {
+ setSideStagePosition(startPosition, wct);
+ mSideStage.addTask(taskInfo, wct);
+ }
+ mMainStage.activate(getMainStageBounds(), wct, true /* includingTopTask */);
+ mSideStage.moveToTop(getSideStageBounds(), wct);
+ }
+
+ void finishEnterSplitScreen(SurfaceControl.Transaction t) {
+ mSplitLayout.init();
+ setDividerVisibility(true, t);
+ setSplitsVisible(true);
+ mShouldUpdateRecents = true;
+ updateRecentTasksSplitPair();
+ if (!mLogger.hasStartedSession()) {
+ mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
+ getMainStagePosition(), mMainStage.getTopChildTaskUid(),
+ getSideStagePosition(), mSideStage.getTopChildTaskUid(),
+ mSplitLayout.isLandscape());
+ }
+ }
+
void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
outTopOrLeftBounds.set(mSplitLayout.getBounds1());
outBottomOrRightBounds.set(mSplitLayout.getBounds2());
@@ -840,31 +911,27 @@
private void onStageVisibilityChanged(StageListenerImpl stageListener) {
final boolean sideStageVisible = mSideStageListener.mVisible;
final boolean mainStageVisible = mMainStageListener.mVisible;
- final boolean bothStageVisible = sideStageVisible && mainStageVisible;
- final boolean bothStageInvisible = !sideStageVisible && !mainStageVisible;
- final boolean sameVisibility = sideStageVisible == mainStageVisible;
- if (bothStageInvisible) {
+ // Wait for both stages having the same visibility to prevent causing flicker.
+ if (mainStageVisible != sideStageVisible) {
+ return;
+ }
+
+ if (!mainStageVisible) {
+ // Both stages are not visible, check if it needs to dismiss split screen.
if (mExitSplitScreenOnHide
- // Don't dismiss staged split when both stages are not visible due to sleeping
- // display, like the cases keyguard showing or screen off.
+ // Don't dismiss split screen when both stages are not visible due to sleeping
+ // display.
|| (!mMainStage.mRootTaskInfo.isSleeping
&& !mSideStage.mRootTaskInfo.isSleeping)) {
- // Don't dismiss staged split when both stages are not visible due to sleeping display,
- // like the cases keyguard showing or screen off.
exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RETURN_HOME);
}
}
- exitSplitScreenIfKeyguardOccluded();
mSyncQueue.runInSync(t -> {
- // Same above, we only set root tasks and divider leash visibility when both stage
- // change to visible or invisible to avoid flicker.
- if (sameVisibility) {
- t.setVisibility(mSideStage.mRootLeash, bothStageVisible)
- .setVisibility(mMainStage.mRootLeash, bothStageVisible);
- setDividerVisibility(bothStageVisible, t);
- }
+ t.setVisibility(mSideStage.mRootLeash, sideStageVisible)
+ .setVisibility(mMainStage.mRootLeash, mainStageVisible);
+ setDividerVisibility(mainStageVisible, t);
});
}
@@ -884,6 +951,7 @@
if (mDividerVisible) {
t.show(dividerLeash);
+ t.setAlpha(dividerLeash, 1);
t.setLayer(dividerLeash, SPLIT_DIVIDER_LAYER);
t.setPosition(dividerLeash,
mSplitLayout.getDividerBounds().left, mSplitLayout.getDividerBounds().top);
@@ -907,8 +975,7 @@
final WindowContainerTransaction wct = new WindowContainerTransaction();
mSplitLayout.init();
// Make sure the main stage is active.
- mMainStage.activate(getMainStageBounds(), wct, true /* reparent */);
- mSideStage.moveToTop(getSideStageBounds(), wct);
+ prepareEnterSplitScreen(wct);
mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
updateSurfaceBounds(mSplitLayout, t);
@@ -1088,6 +1155,14 @@
mDisplayController.addDisplayChangingController(this::onRotateDisplay);
}
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ if (displayId != DEFAULT_DISPLAY) {
+ return;
+ }
+ mDisplayLayout.set(mDisplayController.getDisplayLayout(displayId));
+ }
+
private void onRotateDisplay(int displayId, int fromRotation, int toRotation,
WindowContainerTransaction wct) {
if (!mMainStage.isActive()) return;
@@ -1096,7 +1171,8 @@
final SurfaceControl.Transaction t = mTransactionPool.acquire();
setDividerVisibility(false, t);
- mSplitLayout.rotateTo(toRotation);
+ mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
+ mSplitLayout.rotateTo(toRotation, mDisplayLayout.stableInsets());
updateWindowBounds(mSplitLayout, wct);
updateUnfoldBounds();
t.apply();
@@ -1203,8 +1279,7 @@
if (isOpening && getStageOfTask(triggerTask) != null) {
// One task is appearing into split, prepare to enter split screen.
out = new WindowContainerTransaction();
- mMainStage.activate(getMainStageBounds(), out, true /* includingTopTask */);
- mSideStage.moveToTop(getSideStageBounds(), out);
+ prepareEnterSplitScreen(out);
mSplitTransitions.mPendingEnter = transition;
}
}
@@ -1212,6 +1287,16 @@
}
@Override
+ public void onTransitionMerged(@NonNull IBinder transition) {
+ // Once the pending enter transition got merged, make sure to bring divider bar visible and
+ // clear the pending transition from cache to prevent mess-up the following state.
+ if (transition == mSplitTransitions.mPendingEnter) {
+ finishEnterSplitScreen(null);
+ mSplitTransitions.mPendingEnter = null;
+ }
+ }
+
+ @Override
public boolean startAnimation(@NonNull IBinder transition,
@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@@ -1294,47 +1379,40 @@
sideChild = change;
}
}
- if (mainChild == null || sideChild == null) {
- throw new IllegalStateException("Launched 2 tasks in split, but didn't receive"
- + " 2 tasks in transition. Possibly one of them failed to launch");
- // TODO: fallback logic. Probably start a new transition to exit split before
- // applying anything here. Ideally consolidate with transition-merging.
+
+ // TODO: fallback logic. Probably start a new transition to exit split before applying
+ // anything here. Ideally consolidate with transition-merging.
+ if (info.getType() == TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE) {
+ if (mainChild == null && sideChild == null) {
+ throw new IllegalStateException("Launched a task in split, but didn't receive any"
+ + " task in transition.");
+ }
+ } else {
+ if (mainChild == null || sideChild == null) {
+ throw new IllegalStateException("Launched 2 tasks in split, but didn't receive"
+ + " 2 tasks in transition. Possibly one of them failed to launch");
+ }
}
- // Update local states (before animating).
- mSplitLayout.init();
- setDividerVisibility(true, t);
- setSplitsVisible(true);
-
- addDividerBarToTransition(info, t, true /* show */);
-
// Make some noise if things aren't totally expected. These states shouldn't effect
// transitions locally, but remotes (like Launcher) may get confused if they were
// depending on listener callbacks. This can happen because task-organizer callbacks
// aren't serialized with transition callbacks.
// TODO(b/184679596): Find a way to either include task-org information in
// the transition, or synchronize task-org callbacks.
- if (!mMainStage.containsTask(mainChild.getTaskInfo().taskId)) {
+ if (mainChild != null && !mMainStage.containsTask(mainChild.getTaskInfo().taskId)) {
Log.w(TAG, "Expected onTaskAppeared on " + mMainStage
+ " to have been called with " + mainChild.getTaskInfo().taskId
+ " before startAnimation().");
}
- if (!mSideStage.containsTask(sideChild.getTaskInfo().taskId)) {
+ if (sideChild != null && !mSideStage.containsTask(sideChild.getTaskInfo().taskId)) {
Log.w(TAG, "Expected onTaskAppeared on " + mSideStage
+ " to have been called with " + sideChild.getTaskInfo().taskId
+ " before startAnimation().");
}
- mShouldUpdateRecents = true;
- updateRecentTasksSplitPair();
-
- if (!mLogger.hasStartedSession()) {
- mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
- getMainStagePosition(), mMainStage.getTopChildTaskUid(),
- getSideStagePosition(), mSideStage.getTopChildTaskUid(),
- mSplitLayout.isLandscape());
- }
-
+ finishEnterSplitScreen(t);
+ addDividerBarToTransition(info, t, true /* show */);
return true;
}
@@ -1388,11 +1466,9 @@
setSplitsVisible(false);
// Wait until after animation to update divider
- if (info.getType() == TRANSIT_SPLIT_DISMISS_SNAP) {
- // Reset crops so they don't interfere with subsequent launches
- t.setWindowCrop(mMainStage.mRootLeash, null);
- t.setWindowCrop(mSideStage.mRootLeash, null);
- }
+ // Reset crops so they don't interfere with subsequent launches
+ t.setWindowCrop(mMainStage.mRootLeash, null);
+ t.setWindowCrop(mSideStage.mRootLeash, null);
if (dismissTransition.mDismissTop == STAGE_TYPE_UNDEFINED) {
logExit(dismissTransition.mReason);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 2c853c1..83534c1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -34,6 +34,7 @@
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
+import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
@@ -301,9 +302,19 @@
}
void addTask(ActivityManager.RunningTaskInfo task, WindowContainerTransaction wct) {
+ // Clear overridden bounds and windowing mode to make sure the child task can inherit
+ // windowing mode and bounds from split root.
+ wct.setWindowingMode(task.token, WINDOWING_MODE_UNDEFINED)
+ .setBounds(task.token, null);
+
wct.reparent(task.token, mRootTaskInfo.token, true /* onTop*/);
}
+ void moveToTop(Rect rootBounds, WindowContainerTransaction wct) {
+ final WindowContainerToken rootToken = mRootTaskInfo.token;
+ wct.setBounds(rootToken, rootBounds).reorder(rootToken, true /* onTop */);
+ }
+
void setBounds(Rect bounds, WindowContainerTransaction wct) {
wct.setBounds(mRootTaskInfo.token, bounds);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 324b8b5..072b925 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -18,11 +18,13 @@
import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
import static android.app.ActivityOptions.ANIM_CUSTOM;
+import static android.app.ActivityOptions.ANIM_FROM_STYLE;
import static android.app.ActivityOptions.ANIM_NONE;
import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
import static android.app.ActivityOptions.ANIM_SCALE_UP;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
@@ -356,6 +358,12 @@
continue;
}
+ // There is no default animation for Pip window in rotation transition, and the
+ // PipTransition will update the surface of its own window at start/finish.
+ if (isTask && change.getTaskInfo().configuration.windowConfiguration
+ .getWindowingMode() == WINDOWING_MODE_PINNED) {
+ continue;
+ }
// No default animation for this, so just update bounds/position.
startTransaction.setPosition(change.getLeash(),
change.getEndAbsBounds().left - info.getRootOffset().x,
@@ -509,60 +517,70 @@
} else if ((changeFlags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0 && isOpeningType) {
// This received a transferred starting window, so don't animate
return null;
- } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) {
- a = mTransitionAnimation.loadDefaultAnimationAttr(enter
- ? R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
- : R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation);
- } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_CLOSE) {
- a = mTransitionAnimation.loadDefaultAnimationAttr(enter
- ? R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation
- : R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation);
- } else if (wallpaperTransit == WALLPAPER_TRANSITION_OPEN) {
- a = mTransitionAnimation.loadDefaultAnimationAttr(enter
- ? R.styleable.WindowAnimation_wallpaperOpenEnterAnimation
- : R.styleable.WindowAnimation_wallpaperOpenExitAnimation);
- } else if (wallpaperTransit == WALLPAPER_TRANSITION_CLOSE) {
- a = mTransitionAnimation.loadDefaultAnimationAttr(enter
- ? R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
- : R.styleable.WindowAnimation_wallpaperCloseExitAnimation);
- } else if (type == TRANSIT_OPEN) {
- if (isTask) {
- a = mTransitionAnimation.loadDefaultAnimationAttr(enter
- ? R.styleable.WindowAnimation_taskOpenEnterAnimation
- : R.styleable.WindowAnimation_taskOpenExitAnimation);
- } else {
- if ((changeFlags & FLAG_TRANSLUCENT) != 0 && enter) {
- a = mTransitionAnimation.loadDefaultAnimationRes(
- R.anim.activity_translucent_open_enter);
+ } else {
+ int animAttr = 0;
+ boolean translucent = false;
+ if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) {
+ animAttr = enter
+ ? R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
+ : R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
+ } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_CLOSE) {
+ animAttr = enter
+ ? R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation
+ : R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
+ } else if (wallpaperTransit == WALLPAPER_TRANSITION_OPEN) {
+ animAttr = enter
+ ? R.styleable.WindowAnimation_wallpaperOpenEnterAnimation
+ : R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
+ } else if (wallpaperTransit == WALLPAPER_TRANSITION_CLOSE) {
+ animAttr = enter
+ ? R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
+ : R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
+ } else if (type == TRANSIT_OPEN) {
+ if (isTask) {
+ animAttr = enter
+ ? R.styleable.WindowAnimation_taskOpenEnterAnimation
+ : R.styleable.WindowAnimation_taskOpenExitAnimation;
} else {
- a = mTransitionAnimation.loadDefaultAnimationAttr(enter
+ if ((changeFlags & FLAG_TRANSLUCENT) != 0 && enter) {
+ translucent = true;
+ }
+ animAttr = enter
? R.styleable.WindowAnimation_activityOpenEnterAnimation
- : R.styleable.WindowAnimation_activityOpenExitAnimation);
+ : R.styleable.WindowAnimation_activityOpenExitAnimation;
}
- }
- } else if (type == TRANSIT_TO_FRONT) {
- a = mTransitionAnimation.loadDefaultAnimationAttr(enter
- ? R.styleable.WindowAnimation_taskToFrontEnterAnimation
- : R.styleable.WindowAnimation_taskToFrontExitAnimation);
- } else if (type == TRANSIT_CLOSE) {
- if (isTask) {
- a = mTransitionAnimation.loadDefaultAnimationAttr(enter
- ? R.styleable.WindowAnimation_taskCloseEnterAnimation
- : R.styleable.WindowAnimation_taskCloseExitAnimation);
- } else {
- if ((changeFlags & FLAG_TRANSLUCENT) != 0 && !enter) {
- a = mTransitionAnimation.loadDefaultAnimationRes(
- R.anim.activity_translucent_close_exit);
+ } else if (type == TRANSIT_TO_FRONT) {
+ animAttr = enter
+ ? R.styleable.WindowAnimation_taskToFrontEnterAnimation
+ : R.styleable.WindowAnimation_taskToFrontExitAnimation;
+ } else if (type == TRANSIT_CLOSE) {
+ if (isTask) {
+ animAttr = enter
+ ? R.styleable.WindowAnimation_taskCloseEnterAnimation
+ : R.styleable.WindowAnimation_taskCloseExitAnimation;
} else {
- a = mTransitionAnimation.loadDefaultAnimationAttr(enter
+ if ((changeFlags & FLAG_TRANSLUCENT) != 0 && !enter) {
+ translucent = true;
+ }
+ animAttr = enter
? R.styleable.WindowAnimation_activityCloseEnterAnimation
- : R.styleable.WindowAnimation_activityCloseExitAnimation);
+ : R.styleable.WindowAnimation_activityCloseExitAnimation;
+ }
+ } else if (type == TRANSIT_TO_BACK) {
+ animAttr = enter
+ ? R.styleable.WindowAnimation_taskToBackEnterAnimation
+ : R.styleable.WindowAnimation_taskToBackExitAnimation;
+ }
+
+ if (animAttr != 0) {
+ if (overrideType == ANIM_FROM_STYLE && canCustomContainer) {
+ a = mTransitionAnimation
+ .loadAnimationAttr(options.getPackageName(), options.getAnimations(),
+ animAttr, translucent);
+ } else {
+ a = mTransitionAnimation.loadDefaultAnimationAttr(animAttr);
}
}
- } else if (type == TRANSIT_TO_BACK) {
- a = mTransitionAnimation.loadDefaultAnimationAttr(enter
- ? R.styleable.WindowAnimation_taskToBackEnterAnimation
- : R.styleable.WindowAnimation_taskToBackExitAnimation);
}
if (a != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index b8cbfd9..711510d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -74,23 +74,25 @@
public static final boolean ENABLE_SHELL_TRANSITIONS =
SystemProperties.getBoolean("persist.debug.shell_transit", false);
- /** Transition type for dismissing split-screen via dragging the divider off the screen. */
- public static final int TRANSIT_SPLIT_DISMISS_SNAP = TRANSIT_FIRST_CUSTOM + 1;
-
- /** Transition type for launching 2 tasks simultaneously. */
- public static final int TRANSIT_SPLIT_SCREEN_PAIR_OPEN = TRANSIT_FIRST_CUSTOM + 2;
-
/** Transition type for exiting PIP via the Shell, via pressing the expand button. */
- public static final int TRANSIT_EXIT_PIP = TRANSIT_FIRST_CUSTOM + 3;
+ public static final int TRANSIT_EXIT_PIP = TRANSIT_FIRST_CUSTOM + 1;
+
+ public static final int TRANSIT_EXIT_PIP_TO_SPLIT = TRANSIT_FIRST_CUSTOM + 2;
/** Transition type for removing PIP via the Shell, either via Dismiss bubble or Close. */
- public static final int TRANSIT_REMOVE_PIP = TRANSIT_FIRST_CUSTOM + 4;
+ public static final int TRANSIT_REMOVE_PIP = TRANSIT_FIRST_CUSTOM + 3;
+
+ /** Transition type for launching 2 tasks simultaneously. */
+ public static final int TRANSIT_SPLIT_SCREEN_PAIR_OPEN = TRANSIT_FIRST_CUSTOM + 4;
/** Transition type for entering split by opening an app into side-stage. */
public static final int TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE = TRANSIT_FIRST_CUSTOM + 5;
+ /** Transition type for dismissing split-screen via dragging the divider off the screen. */
+ public static final int TRANSIT_SPLIT_DISMISS_SNAP = TRANSIT_FIRST_CUSTOM + 6;
+
/** Transition type for dismissing split-screen. */
- public static final int TRANSIT_SPLIT_DISMISS = TRANSIT_FIRST_CUSTOM + 6;
+ public static final int TRANSIT_SPLIT_DISMISS = TRANSIT_FIRST_CUSTOM + 7;
private final WindowOrganizer mOrganizer;
private final Context mContext;
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index c4be785..68b0b4e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -17,11 +17,11 @@
@file:JvmName("CommonAssertions")
package com.android.wm.shell.flicker
-import android.graphics.Region
import android.view.Surface
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.common.region.Region
fun FlickerTestParameter.appPairsDividerIsVisibleAtEnd() {
assertLayersEnd {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
index d9b7277..ae92366 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
@@ -82,7 +82,7 @@
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
index 20a9475..f1b0135 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
@@ -67,7 +67,7 @@
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
index 2d47027..6998cd2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
@@ -86,7 +86,7 @@
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
index 9b4506c..7a53224 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
@@ -71,7 +71,7 @@
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
index 10ccd6a..f2f4877 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
@@ -18,6 +18,7 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -92,6 +93,10 @@
testSpec.appPairsSecondaryBoundsIsVisibleAtEnd(testSpec.endRotation,
secondaryApp.component)
+ @FlakyTest(bugId = 206753786)
+ @Test
+ override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
index cf7343b..2a173d1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
@@ -18,6 +18,7 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -79,6 +80,10 @@
@Test
override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible()
+ @FlakyTest(bugId = 206753786)
+ @Test
+ override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
@Presubmit
@Test
fun bothAppWindowsVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
index 623055f6..efae207 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
@@ -17,23 +17,23 @@
package com.android.wm.shell.flicker.helpers
import android.app.Instrumentation
-import android.graphics.Region
import com.android.server.wm.flicker.Flicker
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.common.region.Region
class AppPairsHelper(
instrumentation: Instrumentation,
activityLabel: String,
component: FlickerComponentName
) : BaseAppHelper(instrumentation, activityLabel, component) {
- fun getPrimaryBounds(dividerBounds: Region): android.graphics.Region {
+ fun getPrimaryBounds(dividerBounds: Region): Region {
val primaryAppBounds = Region(0, 0, dividerBounds.bounds.right,
dividerBounds.bounds.bottom + WindowUtils.dockedStackDividerInset)
return primaryAppBounds
}
- fun getSecondaryBounds(dividerBounds: Region): android.graphics.Region {
+ fun getSecondaryBounds(dividerBounds: Region): Region {
val displayBounds = WindowUtils.displayBounds
val secondaryAppBounds = Region(0,
dividerBounds.bounds.bottom - WindowUtils.dockedStackDividerInset,
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
index 2357b0d..8e6fa5f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.helpers
import android.app.Instrumentation
-import android.graphics.Rect
import android.media.session.MediaController
import android.media.session.MediaSessionManager
import android.os.SystemClock
@@ -26,6 +25,7 @@
import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.helpers.FIND_TIMEOUT
import com.android.server.wm.flicker.helpers.SYSTEMUI_PACKAGE
+import com.android.server.wm.traces.common.Rect
import com.android.server.wm.traces.parser.toFlickerComponent
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import com.android.wm.shell.flicker.pip.tv.closeTvPipWindow
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
index 77fb101..2c02d2c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
@@ -110,7 +110,7 @@
@Test
fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
index 6041e23..7d7add4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.legacysplitscreen
-import android.graphics.Region
import android.util.Rational
import android.view.Surface
import androidx.test.filters.FlakyTest
@@ -41,6 +40,7 @@
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.server.wm.traces.common.region.Region
import com.android.server.wm.traces.parser.toFlickerComponent
import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.helpers.SimpleAppHelper
@@ -135,6 +135,7 @@
@Test
fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
+ @FlakyTest(bugId = 206753786)
@Test
fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
index e44d7d6..5678899 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
@@ -77,7 +77,7 @@
@Test
fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
index d33d92b..c2edf9d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
@@ -76,7 +76,7 @@
@Test
fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
index ece68df..777998c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
@@ -18,6 +18,7 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -85,7 +86,7 @@
@Test
fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
index 127301f..914b11d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
@@ -91,7 +91,7 @@
@Test
fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index f3a3db1..d3bb008 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -91,7 +91,7 @@
}
/** {@inheritDoc} */
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
@@ -128,8 +128,8 @@
@Presubmit
@Test
fun pipWindowRemainInsideVisibleBounds() {
- testSpec.assertWm {
- coversAtMost(displayBounds, pipApp.component)
+ testSpec.assertWmVisibleRegion(pipApp.component) {
+ coversAtMost(displayBounds)
}
}
@@ -140,8 +140,8 @@
@Presubmit
@Test
fun pipLayerRemainInsideVisibleBounds() {
- testSpec.assertLayers {
- coversAtMost(displayBounds, pipApp.component)
+ testSpec.assertLayersVisibleRegion(pipApp.component) {
+ coversAtMost(displayBounds)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index f923a23..fa9fbcd 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -119,7 +119,7 @@
* Checks that the [FlickerComponentName.STATUS_BAR] has the correct position at
* the start and end of the transition
*/
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
index 3e7e2f5..f8a3aff 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
@@ -45,8 +45,8 @@
@Presubmit
@Test
open fun pipAppWindowRemainInsideVisibleBounds() {
- testSpec.assertWm {
- coversAtMost(displayBounds, pipApp.component)
+ testSpec.assertWmVisibleRegion(pipApp.component) {
+ coversAtMost(displayBounds)
}
}
@@ -57,8 +57,8 @@
@Presubmit
@Test
open fun pipAppLayerRemainInsideVisibleBounds() {
- testSpec.assertLayers {
- coversAtMost(displayBounds, pipApp.component)
+ testSpec.assertLayersVisibleRegion(pipApp.component) {
+ coversAtMost(displayBounds)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
index 4d63d14..2231d88 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
@@ -16,8 +16,8 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -80,7 +80,7 @@
}
/** {@inheritDoc} */
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
index 19d8671..fcac2c7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -100,7 +99,7 @@
}
/** {@inheritDoc} */
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
index 338687f..c75076d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -96,7 +95,7 @@
}
/** {@inheritDoc} */
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
index 40be21a..8e6603b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -80,7 +79,7 @@
@Test
override fun pipLayerBecomesInvisible() = super.pipLayerBecomesInvisible()
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index 3511cc2..52177c2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -78,8 +78,8 @@
@Presubmit
@Test
fun pipWindowRemainInsideVisibleBounds() {
- testSpec.assertWm {
- coversAtMost(displayBounds, pipApp.component)
+ testSpec.assertWmVisibleRegion(pipApp.component) {
+ coversAtMost(displayBounds)
}
}
@@ -90,8 +90,8 @@
@Presubmit
@Test
fun pipLayerRemainInsideVisibleBounds() {
- testSpec.assertLayers {
- coversAtMost(displayBounds, pipApp.component)
+ testSpec.assertLayersVisibleRegion(pipApp.component) {
+ coversAtMost(displayBounds)
}
}
@@ -165,6 +165,10 @@
}
}
+ @FlakyTest(bugId = 206753786)
+ @Test
+ override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
companion object {
/**
* Creates the test configurations.
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
index 10a542f..f9e180e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
@@ -16,8 +16,8 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -25,8 +25,8 @@
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import com.android.server.wm.flicker.traces.RegionSubject
import org.junit.Assume.assumeFalse
+import com.android.server.wm.flicker.traces.region.RegionSubject
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -83,7 +83,7 @@
}
/** {@inheritDoc} */
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
index 6e0324c..0499e7d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
@@ -19,7 +19,7 @@
import android.platform.test.annotations.Presubmit
import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.traces.RegionSubject
+import com.android.server.wm.flicker.traces.region.RegionSubject
import com.android.wm.shell.flicker.helpers.FixedAppHelper
import org.junit.Test
@@ -66,8 +66,8 @@
@Presubmit
@Test
open fun pipWindowRemainInsideVisibleBounds() {
- testSpec.assertWm {
- coversAtMost(displayBounds, pipApp.component)
+ testSpec.assertWmVisibleRegion(pipApp.component) {
+ coversAtMost(displayBounds)
}
}
@@ -78,8 +78,8 @@
@Presubmit
@Test
open fun pipLayerRemainInsideVisibleBounds() {
- testSpec.assertLayers {
- coversAtMost(displayBounds, pipApp.component)
+ testSpec.assertLayersVisibleRegion(pipApp.component) {
+ coversAtMost(displayBounds)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
index cb6ba0e6..b7bfa1b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
@@ -16,16 +16,16 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.traces.region.RegionSubject
import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
-import com.android.server.wm.flicker.traces.RegionSubject
import org.junit.Assume.assumeFalse
import org.junit.FixMethodOrder
import org.junit.Test
@@ -83,7 +83,7 @@
}
/** {@inheritDoc} */
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index 81ac10f..c36dfda 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -18,6 +18,7 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -73,7 +74,7 @@
}
/** {@inheritDoc} */
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
@@ -87,9 +88,9 @@
@Presubmit
@Test
fun pipInVisibleBounds() {
- testSpec.assertWm {
+ testSpec.assertWmVisibleRegion(pipApp.component) {
val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
- coversAtMost(displayBounds, pipApp.component)
+ coversAtMost(displayBounds)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
index 70075dd..df58194 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
@@ -90,7 +90,7 @@
}
/** {@inheritDoc} */
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
@@ -101,8 +101,8 @@
@FlakyTest(bugId = 161435597)
@Test
fun pipWindowInsideDisplayBounds() {
- testSpec.assertWm {
- coversAtMost(displayBounds, pipApp.component)
+ testSpec.assertWmVisibleRegion(pipApp.component) {
+ coversAtMost(displayBounds)
}
}
@@ -119,8 +119,8 @@
@FlakyTest(bugId = 161435597)
@Test
fun pipLayerInsideDisplayBounds() {
- testSpec.assertLayers {
- coversAtMost(displayBounds, pipApp.component)
+ testSpec.assertLayersVisibleRegion(pipApp.component) {
+ coversAtMost(displayBounds)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index 59bbdfe..b2b50ad 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -27,12 +27,10 @@
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.wm.shell.flicker.helpers.FixedAppHelper
-import org.junit.Assume.assumeFalse
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -100,7 +98,7 @@
/**
* Checks the position of the status bar at the start and end of the transition
*/
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
@@ -121,8 +119,6 @@
@Presubmit
@Test
fun appLayerRotates_EndingBounds() {
- // This CUJ don't work in shell transitions because of b/204570898 b/204562589 b/206753786
- assumeFalse(isShellTransitionsEnabled)
testSpec.assertLayersEnd {
visibleRegion(fixedApp.component).coversExactly(screenBoundsEnd)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index 3121218..dbd3d8c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -115,7 +115,7 @@
super.navBarLayerRotatesAndScales()
}
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h
index 2eb2c7c..e16fd8c 100644
--- a/libs/hwui/Outline.h
+++ b/libs/hwui/Outline.h
@@ -88,14 +88,10 @@
bool getShouldClip() const { return mShouldClip; }
- bool willClip() const {
- // only round rect outlines can be used for clipping
- return mShouldClip && (mType == Type::RoundRect);
- }
+ bool willClip() const { return mShouldClip; }
- bool willRoundRectClip() const {
- // only round rect outlines can be used for clipping
- return willClip() && MathUtils::isPositive(mRadius);
+ bool willComplexClip() const {
+ return mShouldClip && (mType != Type::RoundRect || MathUtils::isPositive(mRadius));
}
bool getAsRoundRect(Rect* outRect, float* outRadius) const {
diff --git a/libs/hwui/ProfileData.cpp b/libs/hwui/ProfileData.cpp
index dd84396..3d0ca0a 100644
--- a/libs/hwui/ProfileData.cpp
+++ b/libs/hwui/ProfileData.cpp
@@ -137,6 +137,7 @@
histogramGPUForEach([fd](HistogramEntry entry) {
dprintf(fd, " %ums=%u", entry.renderTimeMs, entry.frameCount);
});
+ dprintf(fd, "\n");
}
uint32_t ProfileData::findPercentile(int percentile) const {
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index cd622eb..064ba7a 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -165,11 +165,11 @@
bool prepareForFunctorPresence(bool willHaveFunctor, bool ancestorDictatesFunctorsNeedLayer) {
// parent may have already dictated that a descendant layer is needed
bool functorsNeedLayer =
- ancestorDictatesFunctorsNeedLayer
- || CC_UNLIKELY(isClipMayBeComplex())
+ ancestorDictatesFunctorsNeedLayer ||
+ CC_UNLIKELY(isClipMayBeComplex())
// Round rect clipping forces layer for functors
- || CC_UNLIKELY(getOutline().willRoundRectClip()) ||
+ || CC_UNLIKELY(getOutline().willComplexClip()) ||
CC_UNLIKELY(getRevealClip().willClip())
// Complex matrices forces layer, due to stencil clipping
diff --git a/libs/hwui/jni/RenderEffect.cpp b/libs/hwui/jni/RenderEffect.cpp
index a48d7f7..213f35a 100644
--- a/libs/hwui/jni/RenderEffect.cpp
+++ b/libs/hwui/jni/RenderEffect.cpp
@@ -127,6 +127,32 @@
return reinterpret_cast<jlong>(shaderFilter.release());
}
+static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int ret = jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", fmt, args);
+ va_end(args);
+ return ret;
+}
+
+static jlong createRuntimeShaderEffect(JNIEnv* env, jobject, jlong shaderBuilderHandle,
+ jstring inputShaderName) {
+ SkRuntimeShaderBuilder* builder =
+ reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilderHandle);
+ ScopedUtfChars name(env, inputShaderName);
+
+ if (builder->child(name.c_str()).fChild == nullptr) {
+ ThrowIAEFmt(env,
+ "unable to find a uniform with the name '%s' of the correct "
+ "type defined by the provided RuntimeShader",
+ name.c_str());
+ return 0;
+ }
+
+ sk_sp<SkImageFilter> filter = SkImageFilters::RuntimeShader(*builder, name.c_str(), nullptr);
+ return reinterpret_cast<jlong>(filter.release());
+}
+
static void RenderEffect_safeUnref(SkImageFilter* filter) {
SkSafeUnref(filter);
}
@@ -136,15 +162,16 @@
}
static const JNINativeMethod gRenderEffectMethods[] = {
- {"nativeGetFinalizer", "()J", (void*)getRenderEffectFinalizer},
- {"nativeCreateOffsetEffect", "(FFJ)J", (void*)createOffsetEffect},
- {"nativeCreateBlurEffect", "(FFJI)J", (void*)createBlurEffect},
- {"nativeCreateBitmapEffect", "(JFFFFFFFF)J", (void*)createBitmapEffect},
- {"nativeCreateColorFilterEffect", "(JJ)J", (void*)createColorFilterEffect},
- {"nativeCreateBlendModeEffect", "(JJI)J", (void*)createBlendModeEffect},
- {"nativeCreateChainEffect", "(JJ)J", (void*)createChainEffect},
- {"nativeCreateShaderEffect", "(J)J", (void*)createShaderEffect}
-};
+ {"nativeGetFinalizer", "()J", (void*)getRenderEffectFinalizer},
+ {"nativeCreateOffsetEffect", "(FFJ)J", (void*)createOffsetEffect},
+ {"nativeCreateBlurEffect", "(FFJI)J", (void*)createBlurEffect},
+ {"nativeCreateBitmapEffect", "(JFFFFFFFF)J", (void*)createBitmapEffect},
+ {"nativeCreateColorFilterEffect", "(JJ)J", (void*)createColorFilterEffect},
+ {"nativeCreateBlendModeEffect", "(JJI)J", (void*)createBlendModeEffect},
+ {"nativeCreateChainEffect", "(JJ)J", (void*)createChainEffect},
+ {"nativeCreateShaderEffect", "(J)J", (void*)createShaderEffect},
+ {"nativeCreateRuntimeShaderEffect", "(JLjava/lang/String;)J",
+ (void*)createRuntimeShaderEffect}};
int register_android_graphics_RenderEffect(JNIEnv* env) {
android::RegisterMethodsOrDie(env, "android/graphics/RenderEffect",
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index bd93a4f..27865b3 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -609,10 +609,19 @@
LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
auto globalCallbackRef = std::make_shared<JGlobalRefHolder>(vm,
env->NewGlobalRef(frameCallback));
- proxy->setFrameCallback([globalCallbackRef](int64_t frameNr) {
+ proxy->setFrameCallback([globalCallbackRef](int32_t syncResult,
+ int64_t frameNr) -> std::function<void(bool)> {
JNIEnv* env = getenv(globalCallbackRef->vm());
- env->CallVoidMethod(globalCallbackRef->object(), gFrameDrawingCallback.onFrameDraw,
- static_cast<jlong>(frameNr));
+ ScopedLocalRef<jobject> frameCommitCallback(
+ env, env->CallObjectMethod(
+ globalCallbackRef->object(), gFrameDrawingCallback.onFrameDraw,
+ static_cast<jint>(syncResult), static_cast<jlong>(frameNr)));
+ if (frameCommitCallback == nullptr) {
+ return nullptr;
+ }
+ sp<FrameCommitWrapper> wrapper =
+ sp<FrameCommitWrapper>::make(env, frameCommitCallback.get());
+ return [wrapper](bool didProduceBuffer) { wrapper->onFrameCommit(didProduceBuffer); };
});
}
}
@@ -623,7 +632,7 @@
if (!callback) {
proxy->setFrameCommitCallback(nullptr);
} else {
- sp<FrameCommitWrapper> wrapper = new FrameCommitWrapper{env, callback};
+ sp<FrameCommitWrapper> wrapper = sp<FrameCommitWrapper>::make(env, callback);
proxy->setFrameCommitCallback(
[wrapper](bool didProduceBuffer) { wrapper->onFrameCommit(didProduceBuffer); });
}
@@ -1003,8 +1012,9 @@
jclass frameCallbackClass = FindClassOrDie(env,
"android/graphics/HardwareRenderer$FrameDrawingCallback");
- gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass,
- "onFrameDraw", "(J)V");
+ gFrameDrawingCallback.onFrameDraw =
+ GetMethodIDOrDie(env, frameCallbackClass, "onFrameDraw",
+ "(IJ)Landroid/graphics/HardwareRenderer$FrameCommitCallback;");
jclass frameCommitClass =
FindClassOrDie(env, "android/graphics/HardwareRenderer$FrameCommitCallback");
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 48145d2..507d3dc 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -88,6 +88,10 @@
if (pendingClip) {
canvas->clipRect(*pendingClip);
}
+ const SkPath* path = outline.getPath();
+ if (path) {
+ canvas->clipPath(*path, SkClipOp::kIntersect, true);
+ }
return;
}
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 94aedd0..8c98c72 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -158,7 +158,8 @@
// Grab a copy of everything we need
CanvasContext* context = mContext;
- std::function<void(int64_t)> frameCallback = std::move(mFrameCallback);
+ std::function<std::function<void(bool)>(int32_t, int64_t)> frameCallback =
+ std::move(mFrameCallback);
std::function<void()> frameCompleteCallback = std::move(mFrameCompleteCallback);
mFrameCallback = nullptr;
mFrameCompleteCallback = nullptr;
@@ -173,8 +174,13 @@
// Even if we aren't drawing this vsync pulse the next frame number will still be accurate
if (CC_UNLIKELY(frameCallback)) {
- context->enqueueFrameWork(
- [frameCallback, frameNr = context->getFrameNumber()]() { frameCallback(frameNr); });
+ context->enqueueFrameWork([frameCallback, context, syncResult = mSyncResult,
+ frameNr = context->getFrameNumber()]() {
+ auto frameCommitCallback = std::move(frameCallback(syncResult, frameNr));
+ if (frameCommitCallback) {
+ context->addFrameCommitListener(std::move(frameCommitCallback));
+ }
+ });
}
nsecs_t dequeueBufferDuration = 0;
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index e3ea802..8ad8abc 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -77,7 +77,7 @@
void run();
- void setFrameCallback(std::function<void(int64_t)>&& callback) {
+ void setFrameCallback(std::function<std::function<void(bool)>(int32_t, int64_t)>&& callback) {
mFrameCallback = std::move(callback);
}
@@ -126,7 +126,7 @@
int64_t mFrameInfo[UI_THREAD_FRAME_INFO_SIZE];
- std::function<void(int64_t)> mFrameCallback;
+ std::function<std::function<void(bool)>(int32_t, int64_t)> mFrameCallback;
std::function<void(bool)> mFrameCommitCallback;
std::function<void()> mFrameCompleteCallback;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 430c4d3..026699c 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -327,7 +327,8 @@
[this, cb = callback]() { mContext->setPrepareSurfaceControlForWebviewCallback(cb); });
}
-void RenderProxy::setFrameCallback(std::function<void(int64_t)>&& callback) {
+void RenderProxy::setFrameCallback(
+ std::function<std::function<void(bool)>(int32_t, int64_t)>&& callback) {
mDrawFrameTask.setFrameCallback(std::move(callback));
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 6d46be4..491dbd7 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -124,7 +124,7 @@
void setASurfaceTransactionCallback(
const std::function<bool(int64_t, int64_t, int64_t)>& callback);
void setPrepareSurfaceControlForWebviewCallback(const std::function<void()>& callback);
- void setFrameCallback(std::function<void(int64_t)>&& callback);
+ void setFrameCallback(std::function<std::function<void(bool)>(int32_t, int64_t)>&& callback);
void setFrameCommitCallback(std::function<void(bool)>&& callback);
void setFrameCompleteCallback(std::function<void()>&& callback);
diff --git a/libs/hwui/tests/common/scenes/PathClippingAnimation.cpp b/libs/hwui/tests/common/scenes/PathClippingAnimation.cpp
new file mode 100644
index 0000000..1e343c1
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/PathClippingAnimation.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <vector>
+
+#include "TestSceneBase.h"
+
+class PathClippingAnimation : public TestScene {
+public:
+ int mSpacing, mSize;
+ bool mClip, mAnimateClip;
+ int mMaxCards;
+ std::vector<sp<RenderNode> > cards;
+
+ PathClippingAnimation(int spacing, int size, bool clip, bool animateClip, int maxCards)
+ : mSpacing(spacing)
+ , mSize(size)
+ , mClip(clip)
+ , mAnimateClip(animateClip)
+ , mMaxCards(maxCards) {}
+
+ PathClippingAnimation(int spacing, int size, bool clip, bool animateClip)
+ : PathClippingAnimation(spacing, size, clip, animateClip, INT_MAX) {}
+
+ void createContent(int width, int height, Canvas& canvas) override {
+ canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
+ canvas.enableZ(true);
+ int ci = 0;
+ int numCards = 0;
+
+ for (int x = 0; x < width; x += mSpacing) {
+ for (int y = 0; y < height; y += mSpacing) {
+ auto color = BrightColors[ci++ % BrightColorsCount];
+ auto card = TestUtils::createNode(
+ x, y, x + mSize, y + mSize, [&](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(color, SkBlendMode::kSrcOver);
+ if (mClip) {
+ // Create circular path that rounds around the inside of all
+ // four corners of the given square defined by mSize*mSize
+ SkPath path = setPath(mSize);
+ props.mutableOutline().setPath(&path, 1);
+ props.mutableOutline().setShouldClip(true);
+ }
+ });
+ canvas.drawRenderNode(card.get());
+ cards.push_back(card);
+ ++numCards;
+ if (numCards >= mMaxCards) {
+ break;
+ }
+ }
+ if (numCards >= mMaxCards) {
+ break;
+ }
+ }
+
+ canvas.enableZ(false);
+ }
+
+ SkPath setPath(int size) {
+ SkPath path;
+ path.moveTo(0, size / 2);
+ path.cubicTo(0, size * .75, size * .25, size, size / 2, size);
+ path.cubicTo(size * .75, size, size, size * .75, size, size / 2);
+ path.cubicTo(size, size * .25, size * .75, 0, size / 2, 0);
+ path.cubicTo(size / 4, 0, 0, size / 4, 0, size / 2);
+ return path;
+ }
+
+ void doFrame(int frameNr) override {
+ int curFrame = frameNr % 50;
+ if (curFrame > 25) curFrame = 50 - curFrame;
+ for (auto& card : cards) {
+ if (mAnimateClip) {
+ SkPath path = setPath(mSize - curFrame);
+ card->mutateStagingProperties().mutableOutline().setPath(&path, 1);
+ }
+ card->mutateStagingProperties().setTranslationX(curFrame);
+ card->mutateStagingProperties().setTranslationY(curFrame);
+ card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::DISPLAY_LIST);
+ }
+ }
+};
+
+static TestScene::Registrar _PathClippingUnclipped(TestScene::Info{
+ "pathClipping-unclipped", "Multiple RenderNodes, unclipped.",
+ [](const TestScene::Options&) -> test::TestScene* {
+ return new PathClippingAnimation(dp(100), dp(80), false, false);
+ }});
+
+static TestScene::Registrar _PathClippingUnclippedSingle(TestScene::Info{
+ "pathClipping-unclippedsingle", "A single RenderNode, unclipped.",
+ [](const TestScene::Options&) -> test::TestScene* {
+ return new PathClippingAnimation(dp(100), dp(80), false, false, 1);
+ }});
+
+static TestScene::Registrar _PathClippingUnclippedSingleLarge(TestScene::Info{
+ "pathClipping-unclippedsinglelarge", "A single large RenderNode, unclipped.",
+ [](const TestScene::Options&) -> test::TestScene* {
+ return new PathClippingAnimation(dp(100), dp(350), false, false, 1);
+ }});
+
+static TestScene::Registrar _PathClippingClipped80(TestScene::Info{
+ "pathClipping-clipped80", "Multiple RenderNodes, clipped by paths.",
+ [](const TestScene::Options&) -> test::TestScene* {
+ return new PathClippingAnimation(dp(100), dp(80), true, false);
+ }});
+
+static TestScene::Registrar _PathClippingClippedSingle(TestScene::Info{
+ "pathClipping-clippedsingle", "A single RenderNode, clipped by a path.",
+ [](const TestScene::Options&) -> test::TestScene* {
+ return new PathClippingAnimation(dp(100), dp(80), true, false, 1);
+ }});
+
+static TestScene::Registrar _PathClippingClippedSingleLarge(TestScene::Info{
+ "pathClipping-clippedsinglelarge", "A single large RenderNode, clipped by a path.",
+ [](const TestScene::Options&) -> test::TestScene* {
+ return new PathClippingAnimation(dp(100), dp(350), true, false, 1);
+ }});
+
+static TestScene::Registrar _PathClippingAnimated(TestScene::Info{
+ "pathClipping-animated",
+ "Multiple RenderNodes, clipped by paths which are being altered every frame.",
+ [](const TestScene::Options&) -> test::TestScene* {
+ return new PathClippingAnimation(dp(100), dp(80), true, true);
+ }});
+
+static TestScene::Registrar _PathClippingAnimatedSingle(TestScene::Info{
+ "pathClipping-animatedsingle",
+ "A single RenderNode, clipped by a path which is being altered every frame.",
+ [](const TestScene::Options&) -> test::TestScene* {
+ return new PathClippingAnimation(dp(100), dp(80), true, true, 1);
+ }});
+
+static TestScene::Registrar _PathClippingAnimatedSingleLarge(TestScene::Info{
+ "pathClipping-animatedsinglelarge",
+ "A single large RenderNode, clipped by a path which is being altered every frame.",
+ [](const TestScene::Options&) -> test::TestScene* {
+ return new PathClippingAnimation(dp(100), dp(350), true, true, 1);
+ }});
diff --git a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
index 163745b..e9f353d 100644
--- a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
@@ -21,14 +21,17 @@
class RoundRectClippingAnimation : public TestScene {
public:
int mSpacing, mSize;
+ int mMaxCards;
- RoundRectClippingAnimation(int spacing, int size) : mSpacing(spacing), mSize(size) {}
+ RoundRectClippingAnimation(int spacing, int size, int maxCards = INT_MAX)
+ : mSpacing(spacing), mSize(size), mMaxCards(maxCards) {}
std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
canvas.enableZ(true);
int ci = 0;
+ int numCards = 0;
for (int x = 0; x < width; x += mSpacing) {
for (int y = 0; y < height; y += mSpacing) {
@@ -42,6 +45,13 @@
});
canvas.drawRenderNode(card.get());
cards.push_back(card);
+ ++numCards;
+ if (numCards >= mMaxCards) {
+ break;
+ }
+ }
+ if (numCards >= mMaxCards) {
+ break;
}
}
@@ -71,3 +81,22 @@
[](const TestScene::Options&) -> test::TestScene* {
return new RoundRectClippingAnimation(dp(20), dp(20));
}});
+
+static TestScene::Registrar _RoundRectClippingGrid(TestScene::Info{
+ "roundRectClipping-grid", "A grid of RenderNodes with round rect clipping outlines.",
+ [](const TestScene::Options&) -> test::TestScene* {
+ return new RoundRectClippingAnimation(dp(100), dp(80));
+ }});
+
+static TestScene::Registrar _RoundRectClippingSingle(TestScene::Info{
+ "roundRectClipping-single", "A single RenderNodes with round rect clipping outline.",
+ [](const TestScene::Options&) -> test::TestScene* {
+ return new RoundRectClippingAnimation(dp(100), dp(80), 1);
+ }});
+
+static TestScene::Registrar _RoundRectClippingSingleLarge(TestScene::Info{
+ "roundRectClipping-singlelarge",
+ "A single large RenderNodes with round rect clipping outline.",
+ [](const TestScene::Options&) -> test::TestScene* {
+ return new RoundRectClippingAnimation(dp(100), dp(350), 1);
+ }});
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 9993ce9..85e49cc 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -1187,6 +1187,9 @@
case AudioSystem.STREAM_ACCESSIBILITY:
mContentType = CONTENT_TYPE_SPEECH;
break;
+ case AudioSystem.STREAM_ASSISTANT:
+ mContentType = CONTENT_TYPE_SPEECH;
+ break;
default:
Log.e(TAG, "Invalid stream type " + streamType + " for AudioAttributes");
}
@@ -1611,6 +1614,8 @@
return USAGE_VOICE_COMMUNICATION_SIGNALLING;
case AudioSystem.STREAM_ACCESSIBILITY:
return USAGE_ASSISTANCE_ACCESSIBILITY;
+ case AudioSystem.STREAM_ASSISTANT:
+ return USAGE_ASSISTANT;
case AudioSystem.STREAM_TTS:
default:
return USAGE_UNKNOWN;
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index dd27cf1..5c4211f 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2399,6 +2399,77 @@
}
//====================================================================
+ // Direct playback query
+
+ /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
+ direct playback not supported. */
+ public static final int DIRECT_PLAYBACK_NOT_SUPPORTED = AudioSystem.DIRECT_NOT_SUPPORTED;
+ /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
+ direct offload playback supported. Compressed offload is a variant of direct playback.
+ It is the feature that allows audio processing tasks to be done on the Android device but
+ not on the application processor, instead, it is handled by dedicated hardware such as audio
+ DSPs. That will allow the application processor to be idle as much as possible, which is
+ good for power saving. Compressed offload playback supports
+ {@link AudioTrack.StreamEventCallback} for event notifications. */
+ public static final int DIRECT_PLAYBACK_OFFLOAD_SUPPORTED =
+ AudioSystem.DIRECT_OFFLOAD_SUPPORTED;
+ /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
+ direct offload playback supported with gapless transitions. Compressed offload is a variant
+ of direct playback. It is the feature that allows audio processing tasks to be done on the
+ Android device but not on the application processor, instead, it is handled by dedicated
+ hardware such as audio DSPs. That will allow the application processor to be idle as much as
+ possible, which is good for power saving. Compressed offload playback supports
+ {@link AudioTrack.StreamEventCallback} for event notifications. Gapless transitions
+ indicates the ability to play consecutive audio tracks without an audio silence in
+ between. */
+ public static final int DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
+ AudioSystem.DIRECT_OFFLOAD_GAPLESS_SUPPORTED;
+ /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
+ direct playback supported. This value covers direct playback that is bitstream pass-through
+ such as compressed pass-through. */
+ public static final int DIRECT_PLAYBACK_BITSTREAM_SUPPORTED =
+ AudioSystem.DIRECT_BITSTREAM_SUPPORTED;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = "DIRECT_PLAYBACK_", value = {
+ DIRECT_PLAYBACK_NOT_SUPPORTED,
+ DIRECT_PLAYBACK_OFFLOAD_SUPPORTED,
+ DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED,
+ DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}
+ )
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AudioDirectPlaybackMode {}
+
+ /**
+ * Returns a bitfield representing the different forms of direct playback currently available
+ * for a given audio format.
+ * <p>Direct playback means that the audio stream is not altered by the framework. The audio
+ * stream will not be resampled, volume scaled, downmixed or mixed with other content by
+ * the framework. But it may be wrapped in a higher level protocol such as IEC61937 for
+ * passthrough.
+ * <p>Checking for direct support can help the app select the representation of audio content
+ * that most closely matches the capabilities of the device and peripherals (e.g. A/V receiver)
+ * connected to it. Note that the provided stream can still be re-encoded or mixed with other
+ * streams, if needed.
+ * @param format the audio format (codec, sample rate, channels) being checked.
+ * @param attributes the {@link AudioAttributes} to be used for playback
+ * @return the direct playback mode available with given format and attributes. The returned
+ * value will be {@link #DIRECT_PLAYBACK_NOT_SUPPORTED} or a combination of
+ * {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED},
+ * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} and
+ * {@link #DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}. Note that if
+ * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} is present in the returned value,
+ * then {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED} will be too.
+ */
+ @AudioDirectPlaybackMode
+ public static int getDirectPlaybackSupport(@NonNull AudioFormat format,
+ @NonNull AudioAttributes attributes) {
+ Objects.requireNonNull(format);
+ Objects.requireNonNull(attributes);
+ return AudioSystem.getDirectPlaybackSupport(format, attributes);
+ }
+
+ //====================================================================
// Offload query
/**
* Returns whether offloaded playback of an audio format is supported on the device.
@@ -2458,7 +2529,9 @@
* {@link #PLAYBACK_OFFLOAD_SUPPORTED} if offload playback is supported or
* {@link #PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} if gapless transitions are
* also supported.
+ * @deprecated Use {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)} instead
*/
+ @Deprecated
@AudioOffloadMode
public static int getPlaybackOffloadSupport(@NonNull AudioFormat format,
@NonNull AudioAttributes attributes) {
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index e8792b3..d2c49e0 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1768,13 +1768,34 @@
/**
* @hide
+ * Direct playback modes supported by audio HAL implementation.
+ */
+ public static final int DIRECT_NOT_SUPPORTED = 0;
+ public static final int DIRECT_OFFLOAD_SUPPORTED = 1;
+ public static final int DIRECT_OFFLOAD_GAPLESS_SUPPORTED = 3;
+ public static final int DIRECT_BITSTREAM_SUPPORTED = 4;
+
+ /**
+ * @hide
* Compressed audio offload decoding modes supported by audio HAL implementation.
* Keep in sync with system/media/include/media/audio.h.
*/
- public static final int OFFLOAD_NOT_SUPPORTED = 0;
- public static final int OFFLOAD_SUPPORTED = 1;
+ public static final int OFFLOAD_NOT_SUPPORTED = DIRECT_NOT_SUPPORTED;
+ public static final int OFFLOAD_SUPPORTED = DIRECT_OFFLOAD_SUPPORTED;
public static final int OFFLOAD_GAPLESS_SUPPORTED = 2;
+ /**
+ * @hide
+ * Returns how direct playback of an audio format is currently available on the device.
+ * @param format the audio format (codec, sample rate, channels) being checked.
+ * @param attributes the {@link AudioAttributes} to be used for playback
+ * @return the direct playback mode available with given format and attributes. Any combination
+ * of {@link #DIRECT_NOT_SUPPORTED}, {@link #DIRECT_OFFLOAD_SUPPORTED},
+ * {@link #DIRECT_OFFLOAD_GAPLESS_SUPPORTED} and {@link #DIRECT_BITSTREAM_SUPPORTED}.
+ */
+ public static native int getDirectPlaybackSupport(
+ @NonNull AudioFormat format, @NonNull AudioAttributes attributes);
+
static int getOffloadSupport(@NonNull AudioFormat format, @NonNull AudioAttributes attr) {
return native_get_offload_support(format.getEncoding(), format.getSampleRate(),
format.getChannelMask(), format.getChannelIndexMask(),
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index ea692b9..55c558f 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1357,8 +1357,8 @@
throw new UnsupportedOperationException(
"Offload and low latency modes are incompatible");
}
- if (AudioSystem.getOffloadSupport(mFormat, mAttributes)
- == AudioSystem.OFFLOAD_NOT_SUPPORTED) {
+ if (AudioSystem.getDirectPlaybackSupport(mFormat, mAttributes)
+ == AudioSystem.DIRECT_NOT_SUPPORTED) {
throw new UnsupportedOperationException(
"Cannot create AudioTrack, offload format / attributes not supported");
}
@@ -1530,7 +1530,10 @@
* the audio data.
* @param attributes a non-null {@link AudioAttributes} instance.
* @return true if the given audio format can be played directly.
+ * @deprecated Use {@link AudioManager#getDirectPlaybackSupport(AudioFormat, AudioAttributes)}
+ * instead.
*/
+ @Deprecated
public static boolean isDirectPlaybackSupported(@NonNull AudioFormat format,
@NonNull AudioAttributes attributes) {
if (format == null) {
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index 875c6f5..7749564 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -31,35 +31,33 @@
/**
* JetPlayer provides access to JET content playback and control.
- *
- * <p>Please refer to the JET Creator User Manual for a presentation of the JET interactive
- * music concept and how to use the JetCreator tool to create content to be player by JetPlayer.
- *
+ *
+ * <p>Please refer to the
+ * <a href="https://developer.android.com/guide/topics/media/jet/jetcreator_manual">JET Creator User
+ * Manual</a> for a presentation of the JET interactive music concept and how to use the JetCreator
+ * tool to create content to be player by JetPlayer.
+ *
* <p>Use of the JetPlayer class is based around the playback of a number of JET segments
* sequentially added to a playback FIFO queue. The rendering of the MIDI content stored in each
* segment can be dynamically affected by two mechanisms:
* <ul>
- * <li>tracks in a segment can be muted or unmuted at any moment, individually or through
- * a mask (to change the mute state of multiple tracks at once)</li>
- * <li>parts of tracks in a segment can be played at predefined points in the segment, in order
- * to maintain synchronization with the other tracks in the segment. This is achieved through
- * the notion of "clips", which can be triggered at any time, but that will play only at the
- * right time, as authored in the corresponding JET file.</li>
+ * <li>Tracks in a segment can be muted or unmuted at any moment, individually or through a mask
+ * (to change the mute state of multiple tracks at once).
+ * <li>Parts of tracks in a segment can be played at predefined points in the segment, in order to
+ * maintain synchronization with the other tracks in the segment. This is achieved through the
+ * notion of "clips", which can be triggered at any time, but that will play only at the right
+ * time, as authored in the corresponding JET file.
* </ul>
- * As a result of the rendering and playback of the JET segments, the user of the JetPlayer instance
- * can receive notifications from the JET engine relative to:
- * <ul>
- * <li>the playback state,</li>
- * <li>the number of segments left to play in the queue,</li>
- * <li>application controller events (CC80-83) to mark points in the MIDI segments.</li>
- * </ul>
- * Use {@link #getJetPlayer()} to construct a JetPlayer instance. JetPlayer is a singleton class.
- * </p>
*
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about how to use JetPlayer, read the
- * <a href="{@docRoot}guide/topics/media/jetplayer.html">JetPlayer</a> developer guide.</p></div>
+ * <p>As a result of the rendering and playback of the JET segments, the user of the JetPlayer
+ * instance can receive notifications from the JET engine relative to:
+ * <ul>
+ * <li>Playback state
+ * <li>Number of segments left to play in the queue
+ * <li>Application controller events (CC80-83) to mark points in the MIDI segments
+ * </ul>
+ *
+ * <p>Use {@link #getJetPlayer()} to construct a JetPlayer instance. JetPlayer is a singleton class.
*/
public class JetPlayer
{
@@ -140,7 +138,7 @@
//------------------------
/**
* Factory method for the JetPlayer class.
- * @return the singleton JetPlayer instance
+ * @return the singleton JetPlayer instance.
*/
public static JetPlayer getJetPlayer() {
if (singletonRef == null) {
@@ -203,7 +201,8 @@
// Getters
//------------------------
/**
- * Returns the maximum number of simultaneous MIDI tracks supported by JetPlayer
+ * Gets the maximum number of simultaneous MIDI tracks supported by JetPlayer.
+ * @return the maximum number of simultaneous MIDI tracks supported by JetPlayer.
*/
public static int getMaxTracks() {
return JetPlayer.MAXTRACKS;
@@ -459,10 +458,9 @@
//------------------------
/**
* Sets the listener JetPlayer notifies when a JET event is generated by the rendering and
- * playback engine.
- * Notifications will be received in the same thread as the one in which the JetPlayer
- * instance was created.
- * @param listener
+ * playback engine. Notifications are received in the same thread as the one in which the
+ * JetPlayer instance was created.
+ * @param listener the listener that will be notified when a JET event is generated.
*/
public void setEventListener(OnJetEventListener listener) {
setEventListener(listener, null);
@@ -470,10 +468,9 @@
/**
* Sets the listener JetPlayer notifies when a JET event is generated by the rendering and
- * playback engine.
- * Use this method to receive JET events in the Handler associated with another
- * thread than the one in which you created the JetPlayer instance.
- * @param listener
+ * playback engine. Use this method to receive JET events in the Handler associated with
+ * another thread than the one in which you created the JetPlayer instance.
+ * @param listener the listener that will be notified when a JET event is generated.
* @param handler the Handler that will receive the event notification messages.
*/
public void setEventListener(OnJetEventListener listener, Handler handler) {
diff --git a/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java
index dcd4dce..ec56d61 100644
--- a/media/java/android/media/MediaActionSound.java
+++ b/media/java/android/media/MediaActionSound.java
@@ -16,8 +16,11 @@
package android.media;
-import android.media.AudioManager;
+import android.content.Context;
import android.media.SoundPool;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
/**
@@ -104,6 +107,26 @@
private static final int STATE_LOADING_PLAY_REQUESTED = 2;
private static final int STATE_LOADED = 3;
+ /**
+ * <p>Returns true if the application must play the shutter sound in accordance
+ * to certain regional restrictions. </p>
+ *
+ * <p>If this method returns true, applications are strongly recommended to use
+ * MediaActionSound.play(SHUTTER_CLICK) or START_VIDEO_RECORDING whenever it captures
+ * images or video to storage or sends them over the network.</p>
+ */
+ public static boolean mustPlayShutterSound() {
+ boolean result = false;
+ IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+ IAudioService audioService = IAudioService.Stub.asInterface(b);
+ try {
+ result = audioService.isCameraSoundForced();
+ } catch (RemoteException e) {
+ Log.e(TAG, "audio service is unavailable for queries, defaulting to false");
+ }
+ return result;
+ }
+
private class SoundState {
public final int name;
public int id;
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 7459e63..dab188e 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -250,6 +250,13 @@
@NonNull FileDescriptor fd, long offset, long length) throws IOException;
/**
+ * Sets the MediaCas instance to use. This should be called after a successful setDataSource()
+ * if at least one track reports mime type of
+ * {@link android.media.MediaFormat#MIMETYPE_AUDIO_SCRAMBLED} or
+ * {@link android.media.MediaFormat#MIMETYPE_VIDEO_SCRAMBLED}. Stream parsing will not proceed
+ * until a valid MediaCas object is provided.
+ *
+ * @param mediaCas the MediaCas object to use.
* @deprecated Use the {@code Descrambler} system API instead, or DRM public APIs like
* {@link MediaDrm}.
*/
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index c912759..1f89f99 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -145,10 +145,8 @@
final int match_rule = mRule & ~RULE_EXCLUSION_MASK;
switch (match_rule) {
case RULE_MATCH_ATTRIBUTE_USAGE:
- dest.writeInt(mAttr.getSystemUsage());
- break;
case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
- dest.writeInt(mAttr.getCapturePreset());
+ mAttr.writeToParcel(dest, AudioAttributes.FLATTEN_TAGS/*flags*/);
break;
case RULE_MATCH_UID:
case RULE_MATCH_USERID:
@@ -266,12 +264,14 @@
public boolean isForCallRedirection() {
for (AudioMixMatchCriterion criterion : mCriteria) {
if (criterion.mAttr != null
- && (criterion.mRule == RULE_MATCH_ATTRIBUTE_USAGE
- && criterion.mAttr.getUsage() == AudioAttributes.USAGE_VOICE_COMMUNICATION)
+ && criterion.mAttr.isForCallRedirection()
+ && ((criterion.mRule == RULE_MATCH_ATTRIBUTE_USAGE
+ && (criterion.mAttr.getUsage() == AudioAttributes.USAGE_VOICE_COMMUNICATION
+ || criterion.mAttr.getUsage()
+ == AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING))
|| (criterion.mRule == RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET
- && criterion.mAttr.getCapturePreset()
- == MediaRecorder.AudioSource.VOICE_COMMUNICATION)
- && criterion.mAttr.isForCallRedirection()) {
+ && (criterion.mAttr.getCapturePreset()
+ == MediaRecorder.AudioSource.VOICE_COMMUNICATION)))) {
return true;
}
}
@@ -713,19 +713,8 @@
Integer intProp = null;
switch (match_rule) {
case RULE_MATCH_ATTRIBUTE_USAGE:
- int usage = in.readInt();
- if (AudioAttributes.isSystemUsage(usage)) {
- attr = new AudioAttributes.Builder()
- .setSystemUsage(usage).build();
- } else {
- attr = new AudioAttributes.Builder()
- .setUsage(usage).build();
- }
- break;
case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
- int preset = in.readInt();
- attr = new AudioAttributes.Builder()
- .setInternalCapturePreset(preset).build();
+ attr = AudioAttributes.CREATOR.createFromParcel(in);
break;
case RULE_MATCH_UID:
case RULE_MATCH_USERID:
diff --git a/media/java/android/media/tv/AdRequest.aidl b/media/java/android/media/tv/AdRequest.aidl
new file mode 100644
index 0000000..ebfd748
--- /dev/null
+++ b/media/java/android/media/tv/AdRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv;
+
+parcelable AdRequest;
diff --git a/media/java/android/media/tv/AdRequest.java b/media/java/android/media/tv/AdRequest.java
new file mode 100644
index 0000000..536baf2
--- /dev/null
+++ b/media/java/android/media/tv/AdRequest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv;
+
+import android.annotation.NonNull;
+import android.annotation.StringDef;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** @hide */
+public final class AdRequest implements Parcelable {
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef(prefix = "REQUEST_TYPE_", value = {
+ REQUEST_TYPE_START,
+ REQUEST_TYPE_STOP
+ })
+ public @interface RequestType {}
+
+ public static final String REQUEST_TYPE_START = "START";
+ public static final String REQUEST_TYPE_STOP = "STOP";
+
+ public static final @NonNull Parcelable.Creator<AdRequest> CREATOR =
+ new Parcelable.Creator<AdRequest>() {
+ @Override
+ public AdRequest createFromParcel(Parcel source) {
+ return new AdRequest(source);
+ }
+
+ @Override
+ public AdRequest[] newArray(int size) {
+ return new AdRequest[size];
+ }
+ };
+
+ private final int mId;
+ private final @RequestType String mRequestType;
+ private final ParcelFileDescriptor mFileDescriptor;
+ private final long mStartTime;
+ private final long mStopTime;
+ private final long mEchoInterval;
+ private final String mMediaFileType;
+ private final Bundle mMetadata;
+
+ public AdRequest(int id, @RequestType String requestType, ParcelFileDescriptor fileDescriptor,
+ long startTime, long stopTime, long echoInterval, String mediaFileType,
+ Bundle metadata) {
+ mId = id;
+ mRequestType = requestType;
+ mFileDescriptor = fileDescriptor;
+ mStartTime = startTime;
+ mStopTime = stopTime;
+ mEchoInterval = echoInterval;
+ mMediaFileType = mediaFileType;
+ mMetadata = metadata;
+ }
+
+ private AdRequest(Parcel source) {
+ mId = source.readInt();
+ mRequestType = source.readString();
+ mFileDescriptor = source.readFileDescriptor();
+ mStartTime = source.readLong();
+ mStopTime = source.readLong();
+ mEchoInterval = source.readLong();
+ mMediaFileType = source.readString();
+ mMetadata = source.readBundle();
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ public @RequestType String getRequestType() {
+ return mRequestType;
+ }
+
+ public ParcelFileDescriptor getFileDescriptor() {
+ return mFileDescriptor;
+ }
+
+ public long getStartTime() {
+ return mStartTime;
+ }
+
+ public long getStopTime() {
+ return mStopTime;
+ }
+
+ public long getEchoInterval() {
+ return mEchoInterval;
+ }
+
+ public String getMediaFileType() {
+ return mMediaFileType;
+ }
+
+ public Bundle getMetadata() {
+ return mMetadata;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mId);
+ dest.writeString(mRequestType);
+ mFileDescriptor.writeToParcel(dest, flags);
+ dest.writeLong(mStartTime);
+ dest.writeLong(mStopTime);
+ dest.writeLong(mEchoInterval);
+ dest.writeString(mMediaFileType);
+ dest.writeBundle(mMetadata);
+ }
+}
diff --git a/media/java/android/media/tv/AdResponse.aidl b/media/java/android/media/tv/AdResponse.aidl
new file mode 100644
index 0000000..9c09a0a
--- /dev/null
+++ b/media/java/android/media/tv/AdResponse.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv;
+
+parcelable AdResponse;
diff --git a/media/java/android/media/tv/AdResponse.java b/media/java/android/media/tv/AdResponse.java
new file mode 100644
index 0000000..28cf5ac
--- /dev/null
+++ b/media/java/android/media/tv/AdResponse.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** @hide */
+public final class AdResponse implements Parcelable {
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef(prefix = "RESPONSE_TYPE_", value = {
+ RESPONSE_TYPE_PLAYING,
+ RESPONSE_TYPE_FINISHED,
+ RESPONSE_TYPE_STOPPED,
+ RESPONSE_TYPE_ERROR
+ })
+ public @interface ResponseType {}
+
+ public static final String RESPONSE_TYPE_PLAYING = "PLAYING";
+ public static final String RESPONSE_TYPE_FINISHED = "FINISHED";
+ public static final String RESPONSE_TYPE_STOPPED = "STOPPED";
+ public static final String RESPONSE_TYPE_ERROR = "ERROR";
+
+ public static final @NonNull Parcelable.Creator<AdResponse> CREATOR =
+ new Parcelable.Creator<AdResponse>() {
+ @Override
+ public AdResponse createFromParcel(Parcel source) {
+ return new AdResponse(source);
+ }
+
+ @Override
+ public AdResponse[] newArray(int size) {
+ return new AdResponse[size];
+ }
+ };
+
+ private final int mId;
+ private final @ResponseType String mResponseType;
+ private final Long mElapsedTime;
+
+ public AdResponse(int id, @ResponseType String responseType, @Nullable Long elapsedTime) {
+ mId = id;
+ mResponseType = responseType;
+ mElapsedTime = elapsedTime;
+ }
+
+ private AdResponse(Parcel source) {
+ mId = source.readInt();
+ mResponseType = source.readString();
+ mElapsedTime = (Long) source.readValue(Long.class.getClassLoader());
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ public @ResponseType String getResponseType() {
+ return mResponseType;
+ }
+
+ public Long getElapsedTime() {
+ return mElapsedTime;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mId);
+ dest.writeString(mResponseType);
+ dest.writeValue(mElapsedTime);
+ }
+}
diff --git a/media/java/android/media/tv/AitInfo.java b/media/java/android/media/tv/AitInfo.java
index 5f8487d..ff4c625 100644
--- a/media/java/android/media/tv/AitInfo.java
+++ b/media/java/android/media/tv/AitInfo.java
@@ -27,7 +27,7 @@
public final class AitInfo implements Parcelable {
static final String TAG = "AitInfo";
- public static final Creator<AitInfo> CREATOR = new Creator<AitInfo>() {
+ public static final @NonNull Creator<AitInfo> CREATOR = new Creator<AitInfo>() {
@Override
public AitInfo createFromParcel(Parcel in) {
return new AitInfo(in);
diff --git a/media/java/android/media/tv/ITvInputClient.aidl b/media/java/android/media/tv/ITvInputClient.aidl
index 6f7db4a..f4f55e4 100644
--- a/media/java/android/media/tv/ITvInputClient.aidl
+++ b/media/java/android/media/tv/ITvInputClient.aidl
@@ -17,11 +17,12 @@
package android.media.tv;
import android.content.ComponentName;
+import android.media.tv.AdResponse;
import android.media.tv.AitInfo;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.ITvInputSession;
-import android.net.Uri;
import android.media.tv.TvTrackInfo;
+import android.net.Uri;
import android.os.Bundle;
import android.view.InputChannel;
@@ -54,4 +55,7 @@
// For broadcast info
void onBroadcastInfoResponse(in BroadcastInfoResponse response, int seq);
+
+ // For ad response
+ void onAdResponse(in AdResponse response, int seq);
}
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 0070898..d34e636 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -20,6 +20,7 @@
import android.content.Intent;
import android.graphics.Rect;
import android.media.PlaybackParams;
+import android.media.tv.AdRequest;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.DvbDeviceInfo;
import android.media.tv.ITvInputClient;
@@ -46,6 +47,8 @@
TvInputInfo getTvInputInfo(in String inputId, int userId);
void updateTvInputInfo(in TvInputInfo inputInfo, int userId);
int getTvInputState(in String inputId, int userId);
+ List<String> getAvailableExtensionInterfaceNames(in String inputId, int userId);
+ IBinder getExtensionInterface(in String inputId, in String name, int userId);
List<TvContentRatingSystemInfo> getTvContentRatingSystemList(int userId);
@@ -102,6 +105,10 @@
// For broadcast info
void requestBroadcastInfo(in IBinder sessionToken, in BroadcastInfoRequest request, int userId);
+ void removeBroadcastInfo(in IBinder sessionToken, int id, int userId);
+
+ // For ad request
+ void requestAd(in IBinder sessionToken, in AdRequest request, int userId);
// For TV input hardware binding
List<TvInputHardwareInfo> getHardwareList();
diff --git a/media/java/android/media/tv/ITvInputService.aidl b/media/java/android/media/tv/ITvInputService.aidl
index 8ccf13a..64a23a2 100755
--- a/media/java/android/media/tv/ITvInputService.aidl
+++ b/media/java/android/media/tv/ITvInputService.aidl
@@ -26,18 +26,21 @@
* Top-level interface to a TV input component (implemented in a Service).
* @hide
*/
-oneway interface ITvInputService {
- void registerCallback(in ITvInputServiceCallback callback);
- void unregisterCallback(in ITvInputServiceCallback callback);
- void createSession(in InputChannel channel, in ITvInputSessionCallback callback,
+interface ITvInputService {
+ oneway void registerCallback(in ITvInputServiceCallback callback);
+ oneway void unregisterCallback(in ITvInputServiceCallback callback);
+ oneway void createSession(in InputChannel channel, in ITvInputSessionCallback callback,
in String inputId, in String sessionId);
- void createRecordingSession(in ITvInputSessionCallback callback, in String inputId,
+ oneway void createRecordingSession(in ITvInputSessionCallback callback, in String inputId,
in String sessionId);
+ List<String> getAvailableExtensionInterfaceNames();
+ IBinder getExtensionInterface(in String name);
+ String getExtensionInterfacePermission(in String name);
// For hardware TvInputService
- void notifyHardwareAdded(in TvInputHardwareInfo hardwareInfo);
- void notifyHardwareRemoved(in TvInputHardwareInfo hardwareInfo);
- void notifyHdmiDeviceAdded(in HdmiDeviceInfo deviceInfo);
- void notifyHdmiDeviceRemoved(in HdmiDeviceInfo deviceInfo);
- void notifyHdmiDeviceUpdated(in HdmiDeviceInfo deviceInfo);
+ oneway void notifyHardwareAdded(in TvInputHardwareInfo hardwareInfo);
+ oneway void notifyHardwareRemoved(in TvInputHardwareInfo hardwareInfo);
+ oneway void notifyHdmiDeviceAdded(in HdmiDeviceInfo deviceInfo);
+ oneway void notifyHdmiDeviceRemoved(in HdmiDeviceInfo deviceInfo);
+ oneway void notifyHdmiDeviceUpdated(in HdmiDeviceInfo deviceInfo);
}
diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl
index 984a551..f427501 100644
--- a/media/java/android/media/tv/ITvInputSession.aidl
+++ b/media/java/android/media/tv/ITvInputSession.aidl
@@ -18,6 +18,7 @@
import android.graphics.Rect;
import android.media.PlaybackParams;
+import android.media.tv.AdRequest;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.TvTrackInfo;
import android.net.Uri;
@@ -66,4 +67,8 @@
// For broadcast info
void requestBroadcastInfo(in BroadcastInfoRequest request);
+ void removeBroadcastInfo(int id);
+
+ // For ad request
+ void requestAd(in AdRequest request);
}
diff --git a/media/java/android/media/tv/ITvInputSessionCallback.aidl b/media/java/android/media/tv/ITvInputSessionCallback.aidl
index 9a0aaa3..9830e78 100644
--- a/media/java/android/media/tv/ITvInputSessionCallback.aidl
+++ b/media/java/android/media/tv/ITvInputSessionCallback.aidl
@@ -16,6 +16,7 @@
package android.media.tv;
+import android.media.tv.AdResponse;
import android.media.tv.AitInfo;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.ITvInputSession;
@@ -51,4 +52,7 @@
// For broadcast info
void onBroadcastInfoResponse(in BroadcastInfoResponse response);
+
+ // For ad response
+ void onAdResponse(in AdResponse response);
}
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index 6539472..418ab2c 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -71,7 +71,9 @@
private static final int DO_PAUSE_RECORDING = 22;
private static final int DO_RESUME_RECORDING = 23;
private static final int DO_REQUEST_BROADCAST_INFO = 24;
- private static final int DO_SET_IAPP_NOTIFICATION_ENABLED = 25;
+ private static final int DO_REMOVE_BROADCAST_INFO = 25;
+ private static final int DO_SET_IAPP_NOTIFICATION_ENABLED = 26;
+ private static final int DO_REQUEST_AD = 27;
private final boolean mIsRecordingSession;
private final HandlerCaller mCaller;
@@ -240,10 +242,18 @@
mTvInputSessionImpl.requestBroadcastInfo((BroadcastInfoRequest) msg.obj);
break;
}
+ case DO_REMOVE_BROADCAST_INFO: {
+ mTvInputSessionImpl.removeBroadcastInfo(msg.arg1);
+ break;
+ }
case DO_SET_IAPP_NOTIFICATION_ENABLED: {
mTvInputSessionImpl.setIAppNotificationEnabled((Boolean) msg.obj);
break;
}
+ case DO_REQUEST_AD: {
+ mTvInputSessionImpl.requestAd((AdRequest) msg.obj);
+ break;
+ }
default: {
Log.w(TAG, "Unhandled message code: " + msg.what);
break;
@@ -404,6 +414,16 @@
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_REQUEST_BROADCAST_INFO, request));
}
+ @Override
+ public void removeBroadcastInfo(int requestId) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageI(DO_REMOVE_BROADCAST_INFO, requestId));
+ }
+
+ @Override
+ public void requestAd(AdRequest request) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_REQUEST_AD, request));
+ }
+
private final class TvInputEventReceiver extends InputEventReceiver {
public TvInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
diff --git a/media/java/android/media/tv/OWNERS b/media/java/android/media/tv/OWNERS
index 8bccc9a..33acd0d 100644
--- a/media/java/android/media/tv/OWNERS
+++ b/media/java/android/media/tv/OWNERS
@@ -1,5 +1,6 @@
nchalko@google.com
quxiangfang@google.com
+shubang@google.com
# For android remote service
per-file ITvRemoteServiceInput.aidl = file:/media/lib/tvremote/OWNERS
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index aeb3e3c..ad86002 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -731,6 +731,9 @@
@Override
public void run() {
mSessionCallback.onTracksChanged(mSession, tracks);
+ if (mSession.mIAppNotificationEnabled && mSession.getIAppSession() != null) {
+ mSession.getIAppSession().notifyTracksChanged(tracks);
+ }
}
});
}
@@ -740,6 +743,9 @@
@Override
public void run() {
mSessionCallback.onTrackSelected(mSession, type, trackId);
+ if (mSession.mIAppNotificationEnabled && mSession.getIAppSession() != null) {
+ mSession.getIAppSession().notifyTrackSelected(type, trackId);
+ }
}
});
}
@@ -888,6 +894,19 @@
});
}
}
+
+ void postAdResponse(final AdResponse response) {
+ if (mSession.mIAppNotificationEnabled) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mSession.getIAppSession() != null) {
+ mSession.getIAppSession().notifyAdResponse(response);
+ }
+ }
+ });
+ }
+ }
}
/**
@@ -1273,12 +1292,6 @@
}
record.postTuned(channelUri);
// TODO: synchronized and wrap the channelUri
- if (record.mSession.mIAppNotificationEnabled) {
- TvIAppManager.Session iappSession = record.mSession.mIAppSession;
- if (iappSession != null) {
- iappSession.notifyTuned(channelUri);
- }
- }
}
}
@@ -1317,6 +1330,18 @@
record.postBroadcastInfoResponse(response);
}
}
+
+ @Override
+ public void onAdResponse(AdResponse response, int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postAdResponse(response);
+ }
+ }
};
ITvInputManagerCallback managerCallback = new ITvInputManagerCallback.Stub() {
@Override
@@ -1474,6 +1499,57 @@
}
/**
+ * Returns available extension interfaces of a given hardware TV input. This can be used to
+ * provide domain-specific features that are only known between certain hardware TV inputs
+ * and their clients.
+ *
+ * @param inputId The ID of the TV input.
+ * @return a non-null list of extension interface names available to the caller. An empty
+ * list indicates the given TV input is not found, or the given TV input is not a
+ * hardware TV input, or the given TV input doesn't support any extension
+ * interfaces, or the caller doesn't hold the required permission for the extension
+ * interfaces supported by the given TV input.
+ * @see #getExtensionInterface
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ public List<String> getAvailableExtensionInterfaceNames(@NonNull String inputId) {
+ Preconditions.checkNotNull(inputId);
+ try {
+ return mService.getAvailableExtensionInterfaceNames(inputId, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns an extension interface of a given hardware TV input. This can be used to provide
+ * domain-specific features that are only known between certain hardware TV inputs and
+ * their clients.
+ *
+ * @param inputId The ID of the TV input.
+ * @param name The extension interface name.
+ * @return an {@link IBinder} for the given extension interface, {@code null} if the given TV
+ * input is not found, or if the given TV input is not a hardware TV input, or if the
+ * given TV input doesn't support the given extension interface, or if the caller
+ * doesn't hold the required permission for the given extension interface.
+ * @see #getAvailableExtensionInterfaceNames
+ * @hide
+ */
+ @SystemApi
+ @Nullable
+ public IBinder getExtensionInterface(@NonNull String inputId, @NonNull String name) {
+ Preconditions.checkNotNull(inputId);
+ Preconditions.checkNotNull(name);
+ try {
+ return mService.getExtensionInterface(inputId, name, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Registers a {@link TvInputCallback}.
*
* @param callback A callback used to monitor status of the TV inputs.
@@ -2963,7 +3039,35 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
+ }
+ /**
+ * Removes broadcast info.
+ * @param requestId the corresponding request ID sent from
+ * {@link #requestBroadcastInfo(android.media.tv.BroadcastInfoRequest)}
+ */
+ public void removeBroadcastInfo(int requestId) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.removeBroadcastInfo(mToken, requestId, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ public void requestAd(AdRequest request) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.requestAd(mToken, request, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
private final class InputEventHandler extends Handler {
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 6743dd6..bd5a343 100755
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -202,6 +202,21 @@
}
@Override
+ public List<String> getAvailableExtensionInterfaceNames() {
+ return TvInputService.this.getAvailableExtensionInterfaceNames();
+ }
+
+ @Override
+ public IBinder getExtensionInterface(String name) {
+ return TvInputService.this.getExtensionInterface(name);
+ }
+
+ @Override
+ public String getExtensionInterfacePermission(String name) {
+ return TvInputService.this.getExtensionInterfacePermission(name);
+ }
+
+ @Override
public void notifyHardwareAdded(TvInputHardwareInfo hardwareInfo) {
mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HARDWARE_INPUT,
hardwareInfo).sendToTarget();
@@ -254,6 +269,67 @@
}
/**
+ * Returns available extension interfaces. This can be used to provide domain-specific
+ * features that are only known between certain hardware TV inputs and their clients.
+ *
+ * <p>Note that this service-level extension interface mechanism is only for hardware
+ * TV inputs that are bound even when sessions are not created.
+ *
+ * @return a non-null list of available extension interface names. An empty list
+ * indicates the TV input doesn't support any extension interfaces.
+ * @see #getExtensionInterface
+ * @see #getExtensionInterfacePermission
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public List<String> getAvailableExtensionInterfaceNames() {
+ return new ArrayList<>();
+ }
+
+ /**
+ * Returns an extension interface. This can be used to provide domain-specific features
+ * that are only known between certain hardware TV inputs and their clients.
+ *
+ * <p>Note that this service-level extension interface mechanism is only for hardware
+ * TV inputs that are bound even when sessions are not created.
+ *
+ * @param name The extension interface name.
+ * @return an {@link IBinder} for the given extension interface, {@code null} if the TV input
+ * doesn't support the given extension interface.
+ * @see #getAvailableExtensionInterfaceNames
+ * @see #getExtensionInterfacePermission
+ * @hide
+ */
+ @Nullable
+ @SystemApi
+ public IBinder getExtensionInterface(@NonNull String name) {
+ return null;
+ }
+
+ /**
+ * Returns a permission for the given extension interface. This can be used to provide
+ * domain-specific features that are only known between certain hardware TV inputs and their
+ * clients.
+ *
+ * <p>Note that this service-level extension interface mechanism is only for hardware
+ * TV inputs that are bound even when sessions are not created.
+ *
+ * @param name The extension interface name.
+ * @return a name of the permission being checked for the given extension interface,
+ * {@code null} if there is no required permission, or if the TV input doesn't
+ * support the given extension interface.
+ * @see #getAvailableExtensionInterfaceNames
+ * @see #getExtensionInterface
+ * @hide
+ */
+ @Nullable
+ @SystemApi
+ public String getExtensionInterfacePermission(@NonNull String name) {
+ return null;
+ }
+
+ /**
* Returns a concrete implementation of {@link Session}.
*
* <p>May return {@code null} if this TV input service fails to create a session for some
@@ -773,7 +849,7 @@
/**
* Notifies response for broadcast info.
*
- * @param response
+ * @param response broadcast info response.
* @hide
*/
public void notifyBroadcastInfoResponse(@NonNull final BroadcastInfoResponse response) {
@@ -793,6 +869,29 @@
});
}
+ /**
+ * Notifies response for advertisement.
+ *
+ * @param response advertisement response.
+ * @hide
+ */
+ public void notifyAdResponse(@NonNull final AdResponse response) {
+ executeOrPostRunnableOnMainThread(new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) Log.d(TAG, "notifyAdResponse");
+ if (mSessionCallback != null) {
+ mSessionCallback.onAdResponse(response);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in notifyAdResponse", e);
+ }
+ }
+ });
+ }
+
private void notifyTimeShiftStartPositionChanged(final long timeMs) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@@ -962,6 +1061,8 @@
public abstract void onSetStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume);
/**
+ * called when broadcast info is requested.
+ *
* @param request broadcast info request
* @hide
*/
@@ -969,6 +1070,21 @@
}
/**
+ * @hide
+ */
+ public void onRemoveBroadcastInfo(int requestId) {
+ }
+
+ /**
+ * called when advertisement is requested.
+ *
+ * @param request advertisement request
+ * @hide
+ */
+ public void onRequestAd(@NonNull AdRequest request) {
+ }
+
+ /**
* Tunes to a given channel.
*
* <p>No video will be displayed until {@link #notifyVideoAvailable()} is called.
@@ -1577,6 +1693,14 @@
onRequestBroadcastInfo(request);
}
+ void removeBroadcastInfo(int requestId) {
+ onRemoveBroadcastInfo(requestId);
+ }
+
+ void requestAd(AdRequest request) {
+ onRequestAd(request);
+ }
+
/**
* Takes care of dispatching incoming input events and tells whether the event was handled.
*/
diff --git a/media/java/android/media/tv/interactive/ITvIAppClient.aidl b/media/java/android/media/tv/interactive/ITvIAppClient.aidl
index a5f2331..892a800 100644
--- a/media/java/android/media/tv/interactive/ITvIAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvIAppClient.aidl
@@ -16,7 +16,10 @@
package android.media.tv.interactive;
+import android.graphics.Rect;
+import android.media.tv.AdRequest;
import android.media.tv.BroadcastInfoRequest;
+import android.net.Uri;
import android.os.Bundle;
import android.view.InputChannel;
@@ -30,6 +33,14 @@
void onSessionReleased(int seq);
void onLayoutSurface(int left, int top, int right, int bottom, int seq);
void onBroadcastInfoRequest(in BroadcastInfoRequest request, int seq);
+ void onRemoveBroadcastInfo(int id, int seq);
void onSessionStateChanged(int state, int seq);
+ void onBiInteractiveAppCreated(in Uri biIAppUri, in String biIAppId, int seq);
void onCommandRequest(in String cmdType, in Bundle parameters, int seq);
+ void onSetVideoBounds(in Rect rect, int seq);
+ void onRequestCurrentChannelUri(int seq);
+ void onRequestCurrentChannelLcn(int seq);
+ void onRequestStreamVolume(int seq);
+ void onRequestTrackInfoList(int seq);
+ void onAdRequest(in AdRequest request, int Seq);
}
diff --git a/media/java/android/media/tv/interactive/ITvIAppManager.aidl b/media/java/android/media/tv/interactive/ITvIAppManager.aidl
index 40d8034..23201fa 100644
--- a/media/java/android/media/tv/interactive/ITvIAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvIAppManager.aidl
@@ -17,7 +17,9 @@
package android.media.tv.interactive;
import android.graphics.Rect;
+import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoResponse;
+import android.media.tv.TvTrackInfo;
import android.media.tv.interactive.ITvIAppClient;
import android.media.tv.interactive.ITvIAppManagerCallback;
import android.media.tv.interactive.TvIAppInfo;
@@ -35,15 +37,26 @@
void notifyAppLinkInfo(String tiasId, in Bundle info, int userId);
void sendAppLinkCommand(String tiasId, in Bundle command, int userId);
void startIApp(in IBinder sessionToken, int userId);
+ void stopIApp(in IBinder sessionToken, int userId);
+ void createBiInteractiveApp(
+ in IBinder sessionToken, in Uri biIAppUri, in Bundle params, int userId);
+ void destroyBiInteractiveApp(in IBinder sessionToken, in String biIAppId, int userId);
+ void sendCurrentChannelUri(in IBinder sessionToken, in Uri channelUri, int userId);
+ void sendCurrentChannelLcn(in IBinder sessionToken, int lcn, int userId);
+ void sendStreamVolume(in IBinder sessionToken, float volume, int userId);
+ void sendTrackInfoList(in IBinder sessionToken, in List<TvTrackInfo> tracks, int userId);
void createSession(
in ITvIAppClient client, in String iAppServiceId, int type, int seq, int userId);
void releaseSession(in IBinder sessionToken, int userId);
void notifyTuned(in IBinder sessionToken, in Uri channelUri, int userId);
+ void notifyTrackSelected(in IBinder sessionToken, int type, in String trackId, int userId);
+ void notifyTracksChanged(in IBinder sessionToken, in List<TvTrackInfo> tracks, int userId);
void setSurface(in IBinder sessionToken, in Surface surface, int userId);
void dispatchSurfaceChanged(in IBinder sessionToken, int format, int width, int height,
int userId);
void notifyBroadcastInfoResponse(in IBinder sessionToken, in BroadcastInfoResponse response,
int UserId);
+ void notifyAdResponse(in IBinder sessionToken, in AdResponse response, int UserId);
void createMediaView(in IBinder sessionToken, in IBinder windowToken, in Rect frame,
int userId);
@@ -52,4 +65,4 @@
void registerCallback(in ITvIAppManagerCallback callback, int userId);
void unregisterCallback(in ITvIAppManagerCallback callback, int userId);
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/tv/interactive/ITvIAppSession.aidl b/media/java/android/media/tv/interactive/ITvIAppSession.aidl
index 0d37a2b..52f9a87 100644
--- a/media/java/android/media/tv/interactive/ITvIAppSession.aidl
+++ b/media/java/android/media/tv/interactive/ITvIAppSession.aidl
@@ -17,10 +17,13 @@
package android.media.tv.interactive;
import android.graphics.Rect;
+import android.media.tv.BroadcastInfoResponse;
import android.net.Uri;
+import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoResponse;
+import android.media.tv.TvTrackInfo;
+import android.os.Bundle;
import android.view.Surface;
-import android.media.tv.BroadcastInfoResponse;
/**
* Sub-interface of ITvIAppService.aidl which is created per session and has its own context.
@@ -28,13 +31,23 @@
*/
oneway interface ITvIAppSession {
void startIApp();
+ void stopIApp();
+ void createBiInteractiveApp(in Uri biIAppUri, in Bundle params);
+ void destroyBiInteractiveApp(in String biIAppId);
+ void sendCurrentChannelUri(in Uri channelUri);
+ void sendCurrentChannelLcn(int lcn);
+ void sendStreamVolume(float volume);
+ void sendTrackInfoList(in List<TvTrackInfo> tracks);
void release();
void notifyTuned(in Uri channelUri);
+ void notifyTrackSelected(int type, in String trackId);
+ void notifyTracksChanged(in List<TvTrackInfo> tracks);
void setSurface(in Surface surface);
void dispatchSurfaceChanged(int format, int width, int height);
void notifyBroadcastInfoResponse(in BroadcastInfoResponse response);
+ void notifyAdResponse(in AdResponse response);
void createMediaView(in IBinder windowToken, in Rect frame);
void relayoutMediaView(in Rect frame);
void removeMediaView();
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/tv/interactive/ITvIAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvIAppSessionCallback.aidl
index 66f5fc1..9b9e6af 100644
--- a/media/java/android/media/tv/interactive/ITvIAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvIAppSessionCallback.aidl
@@ -16,9 +16,11 @@
package android.media.tv.interactive;
+import android.graphics.Rect;
+import android.media.tv.AdRequest;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.interactive.ITvIAppSession;
-import android.media.tv.BroadcastInfoRequest;
+import android.net.Uri;
import android.os.Bundle;
/**
@@ -30,6 +32,14 @@
void onSessionCreated(in ITvIAppSession session);
void onLayoutSurface(int left, int top, int right, int bottom);
void onBroadcastInfoRequest(in BroadcastInfoRequest request);
+ void onRemoveBroadcastInfo(int id);
void onSessionStateChanged(int state);
+ void onBiInteractiveAppCreated(in Uri biIAppUri, in String biIAppId);
void onCommandRequest(in String cmdType, in Bundle parameters);
+ void onSetVideoBounds(in Rect rect);
+ void onRequestCurrentChannelUri();
+ void onRequestCurrentChannelLcn();
+ void onRequestStreamVolume();
+ void onRequestTrackInfoList();
+ void onAdRequest(in AdRequest request);
}
diff --git a/media/java/android/media/tv/interactive/TvIAppInfo.java b/media/java/android/media/tv/interactive/TvIAppInfo.java
index de3a47e..79d94cc 100644
--- a/media/java/android/media/tv/interactive/TvIAppInfo.java
+++ b/media/java/android/media/tv/interactive/TvIAppInfo.java
@@ -16,6 +16,8 @@
package android.media.tv.interactive;
+import android.annotation.NonNull;
+import android.annotation.StringDef;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -34,6 +36,8 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
@@ -45,6 +49,21 @@
private static final boolean DEBUG = false;
private static final String TAG = "TvIAppInfo";
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef(prefix = { "INTERACTIVE_APP_TYPE_" }, value = {
+ INTERACTIVE_APP_TYPE_HBBTV,
+ INTERACTIVE_APP_TYPE_ATSC,
+ INTERACTIVE_APP_TYPE_GINGA,
+ })
+ @interface InteractiveAppType {}
+
+ /** HbbTV interactive app type */
+ public static final String INTERACTIVE_APP_TYPE_HBBTV = "hbbtv";
+ /** ATSC interactive app type */
+ public static final String INTERACTIVE_APP_TYPE_ATSC = "atsc";
+ /** Ginga interactive app type */
+ public static final String INTERACTIVE_APP_TYPE_GINGA = "ginga";
+
private final ResolveInfo mService;
private final String mId;
private List<String> mTypes = new ArrayList<>();
@@ -55,13 +74,13 @@
mTypes = types;
}
- protected TvIAppInfo(Parcel in) {
+ private TvIAppInfo(@NonNull Parcel in) {
mService = ResolveInfo.CREATOR.createFromParcel(in);
mId = in.readString();
in.readStringList(mTypes);
}
- public static final Creator<TvIAppInfo> CREATOR = new Creator<TvIAppInfo>() {
+ public static final @NonNull Creator<TvIAppInfo> CREATOR = new Creator<TvIAppInfo>() {
@Override
public TvIAppInfo createFromParcel(Parcel in) {
return new TvIAppInfo(in);
@@ -79,12 +98,13 @@
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
mService.writeToParcel(dest, flags);
dest.writeString(mId);
dest.writeStringList(mTypes);
}
+ @NonNull
public String getId() {
return mId;
}
@@ -105,6 +125,13 @@
}
/**
+ * Gets supported interactive app types
+ */
+ public List<String> getSupportedTypes() {
+ return new ArrayList<>(mTypes);
+ }
+
+ /**
* A convenience builder for creating {@link TvIAppInfo} objects.
*/
public static final class Builder {
@@ -120,7 +147,7 @@
* @param component The name of the application component to be used for the
* {@link TvIAppService}.
*/
- public Builder(Context context, ComponentName component) {
+ public Builder(@NonNull Context context, @NonNull ComponentName component) {
if (context == null) {
throw new IllegalArgumentException("context cannot be null.");
}
@@ -140,6 +167,7 @@
*
* @return TvIAppInfo containing information about this TV IApp service.
*/
+ @NonNull
public TvIAppInfo build() {
ComponentName componentName = new ComponentName(mResolveInfo.serviceInfo.packageName,
mResolveInfo.serviceInfo.name);
@@ -183,7 +211,7 @@
CharSequence[] types = sa.getTextArray(
com.android.internal.R.styleable.TvIAppService_supportedTypes);
for (CharSequence cs : types) {
- mTypes.add(cs.toString());
+ mTypes.add(cs.toString().toLowerCase());
}
sa.recycle();
diff --git a/media/java/android/media/tv/interactive/TvIAppManager.java b/media/java/android/media/tv/interactive/TvIAppManager.java
index 9390d8d..d1fd1df 100644
--- a/media/java/android/media/tv/interactive/TvIAppManager.java
+++ b/media/java/android/media/tv/interactive/TvIAppManager.java
@@ -22,9 +22,12 @@
import android.annotation.SystemService;
import android.content.Context;
import android.graphics.Rect;
+import android.media.tv.AdRequest;
+import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.TvInputManager;
+import android.media.tv.TvTrackInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -244,6 +247,18 @@
}
@Override
+ public void onRemoveBroadcastInfo(int requestId, int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postRemoveBroadcastInfo(requestId);
+ }
+ }
+
+ @Override
public void onCommandRequest(@TvIAppService.IAppServiceCommandType String cmdType,
Bundle parameters, int seq) {
synchronized (mSessionCallbackRecordMap) {
@@ -257,6 +272,78 @@
}
@Override
+ public void onSetVideoBounds(Rect rect, int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postSetVideoBounds(rect);
+ }
+ }
+
+ @Override
+ public void onAdRequest(AdRequest request, int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postAdRequest(request);
+ }
+ }
+
+ @Override
+ public void onRequestCurrentChannelUri(int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postRequestCurrentChannelUri();
+ }
+ }
+
+ @Override
+ public void onRequestCurrentChannelLcn(int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postRequestCurrentChannelLcn();
+ }
+ }
+
+ @Override
+ public void onRequestStreamVolume(int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postRequestStreamVolume();
+ }
+ }
+
+ @Override
+ public void onRequestTrackInfoList(int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postRequestTrackInfoList();
+ }
+ }
+
+ @Override
public void onSessionStateChanged(int state, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
@@ -267,6 +354,18 @@
record.postSessionStateChanged(state);
}
}
+
+ @Override
+ public void onBiInteractiveAppCreated(Uri biIAppUri, String biIAppId, int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postBiInteractiveAppCreated(biIAppUri, biIAppId);
+ }
+ }
};
ITvIAppManagerCallback managerCallback = new ITvIAppManagerCallback.Stub() {
@Override
@@ -337,7 +436,7 @@
*
* @param iAppServiceId The ID of the TV IApp service.
*/
- public void onIAppServiceAdded(String iAppServiceId) {
+ public void onIAppServiceAdded(@NonNull String iAppServiceId) {
}
/**
@@ -348,7 +447,7 @@
*
* @param iAppServiceId The ID of the TV IApp service.
*/
- public void onIAppServiceRemoved(String iAppServiceId) {
+ public void onIAppServiceRemoved(@NonNull String iAppServiceId) {
}
/**
@@ -359,7 +458,7 @@
*
* @param iAppServiceId The ID of the TV IApp service.
*/
- public void onIAppServiceUpdated(String iAppServiceId) {
+ public void onIAppServiceUpdated(@NonNull String iAppServiceId) {
}
/**
@@ -372,16 +471,15 @@
*
* @param iAppInfo The <code>TvIAppInfo</code> object that contains new information.
*/
- public void onTvIAppInfoUpdated(TvIAppInfo iAppInfo) {
+ public void onTvIAppInfoUpdated(@NonNull TvIAppInfo iAppInfo) {
}
-
/**
* This is called when the state of the interactive app service is changed.
* @hide
*/
public void onTvIAppServiceStateChanged(
- String iAppServiceId, int type, @TvIAppRteState int state) {
+ @NonNull String iAppServiceId, int type, @TvIAppRteState int state) {
}
}
@@ -485,6 +583,7 @@
* information.
* @hide
*/
+ @NonNull
public List<TvIAppInfo> getTvIAppServiceList() {
try {
return mService.getTvIAppServiceList(mUserId);
@@ -497,7 +596,7 @@
* Prepares TV IApp service for the given type.
* @hide
*/
- public void prepare(String tvIAppServiceId, int type) {
+ public void prepare(@NonNull String tvIAppServiceId, int type) {
try {
mService.prepare(tvIAppServiceId, type, mUserId);
} catch (RemoteException e) {
@@ -509,7 +608,7 @@
* Notifies app link info.
* @hide
*/
- public void notifyAppLinkInfo(String tvIAppServiceId, Bundle appLinkInfo) {
+ public void notifyAppLinkInfo(@NonNull String tvIAppServiceId, @NonNull Bundle appLinkInfo) {
try {
mService.notifyAppLinkInfo(tvIAppServiceId, appLinkInfo, mUserId);
} catch (RemoteException e) {
@@ -622,6 +721,90 @@
}
}
+ void stopIApp() {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.stopIApp(mToken, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ void createBiInteractiveApp(Uri biIAppUri, Bundle params) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.createBiInteractiveApp(mToken, biIAppUri, params, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ void destroyBiInteractiveApp(String biIAppId) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.destroyBiInteractiveApp(mToken, biIAppId, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ void sendCurrentChannelUri(@Nullable Uri channelUri) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.sendCurrentChannelUri(mToken, channelUri, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ void sendCurrentChannelLcn(int lcn) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.sendCurrentChannelLcn(mToken, lcn, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ void sendStreamVolume(float volume) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.sendStreamVolume(mToken, volume, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ void sendTrackInfoList(@NonNull List<TvTrackInfo> tracks) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.sendTrackInfoList(mToken, tracks, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Sets the {@link android.view.Surface} for this session.
*
@@ -776,6 +959,23 @@
}
/**
+ * Notifies of any advertisement response passed in from TIS.
+ *
+ * @param response response passed in from TIS.
+ */
+ public void notifyAdResponse(AdResponse response) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.notifyAdResponse(mToken, response, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Releases this session.
*/
public void release() {
@@ -793,7 +993,7 @@
}
/**
- * Notifies IAPP session when a channels is tuned.
+ * Notifies IAPP session when a channel is tuned.
*/
public void notifyTuned(Uri channelUri) {
if (mToken == null) {
@@ -807,6 +1007,36 @@
}
}
+ /**
+ * Notifies IAPP session when a track is selected.
+ */
+ public void notifyTrackSelected(int type, String trackId) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.notifyTrackSelected(mToken, type, trackId, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Notifies IAPP session when tracks are changed.
+ */
+ public void notifyTracksChanged(List<TvTrackInfo> tracks) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.notifyTracksChanged(mToken, tracks, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private void flushPendingEventsLocked() {
mHandler.removeMessages(InputEventHandler.MSG_FLUSH_INPUT_EVENT);
@@ -1059,6 +1289,15 @@
});
}
+ void postRemoveBroadcastInfo(final int requestId) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mSession.getInputSession().removeBroadcastInfo(requestId);
+ }
+ });
+ }
+
void postCommandRequest(final @TvIAppService.IAppServiceCommandType String cmdType,
final Bundle parameters) {
mHandler.post(new Runnable() {
@@ -1069,6 +1308,62 @@
});
}
+ void postSetVideoBounds(Rect rect) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mSessionCallback.onSetVideoBounds(mSession, rect);
+ }
+ });
+ }
+
+ void postRequestCurrentChannelUri() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mSessionCallback.onRequestCurrentChannelUri(mSession);
+ }
+ });
+ }
+
+ void postRequestCurrentChannelLcn() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mSessionCallback.onRequestCurrentChannelLcn(mSession);
+ }
+ });
+ }
+
+ void postRequestStreamVolume() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mSessionCallback.onRequestStreamVolume(mSession);
+ }
+ });
+ }
+
+ void postRequestTrackInfoList() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mSessionCallback.onRequestTrackInfoList(mSession);
+ }
+ });
+ }
+
+ void postAdRequest(final AdRequest request) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mSession.getInputSession() != null) {
+ mSession.getInputSession().requestAd(request);
+ }
+ }
+ });
+ }
+
void postSessionStateChanged(int state) {
mHandler.post(new Runnable() {
@Override
@@ -1077,6 +1372,15 @@
}
});
}
+
+ void postBiInteractiveAppCreated(Uri biIAppUri, String biIAppId) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mSessionCallback.onBiInteractiveAppCreated(mSession, biIAppUri, biIAppId);
+ }
+ });
+ }
}
/**
@@ -1127,6 +1431,46 @@
}
/**
+ * This is called when {@link TvIAppService.Session#SetVideoBounds} is called.
+ *
+ * @param session A {@link TvIAppManager.Session} associated with this callback.
+ */
+ public void onSetVideoBounds(Session session, Rect rect) {
+ }
+
+ /**
+ * This is called when {@link TvIAppService.Session#RequestCurrentChannelUri} is called.
+ *
+ * @param session A {@link TvIAppManager.Session} associated with this callback.
+ */
+ public void onRequestCurrentChannelUri(Session session) {
+ }
+
+ /**
+ * This is called when {@link TvIAppService.Session#RequestCurrentChannelLcn} is called.
+ *
+ * @param session A {@link TvIAppManager.Session} associated with this callback.
+ */
+ public void onRequestCurrentChannelLcn(Session session) {
+ }
+
+ /**
+ * This is called when {@link TvIAppService.Session#RequestStreamVolume} is called.
+ *
+ * @param session A {@link TvIAppManager.Session} associated with this callback.
+ */
+ public void onRequestStreamVolume(Session session) {
+ }
+
+ /**
+ * This is called when {@link TvIAppService.Session#RequestTrackInfoList} is called.
+ *
+ * @param session A {@link TvIAppManager.Session} associated with this callback.
+ */
+ public void onRequestTrackInfoList(Session session) {
+ }
+
+ /**
* This is called when {@link TvIAppService.Session#notifySessionStateChanged} is called.
*
* @param session A {@link TvIAppManager.Session} associated with this callback.
@@ -1134,5 +1478,18 @@
*/
public void onSessionStateChanged(Session session, int state) {
}
+
+ /**
+ * This is called when {@link TvIAppService.Session#notifyBiInteractiveAppCreated} is
+ * called.
+ *
+ * @param session A {@link TvIAppManager.Session} associated with this callback.
+ * @param biIAppUri URI associated this BI interactive app. This is the same URI in
+ * {@link Session#createBiInteractiveApp(Uri, Bundle)}
+ * @param biIAppId BI interactive app ID, which can be used to destroy the BI interactive
+ * app.
+ */
+ public void onBiInteractiveAppCreated(Session session, Uri biIAppUri, String biIAppId) {
+ }
}
}
diff --git a/media/java/android/media/tv/interactive/TvIAppService.java b/media/java/android/media/tv/interactive/TvIAppService.java
index 6475f90..1480ff64 100644
--- a/media/java/android/media/tv/interactive/TvIAppService.java
+++ b/media/java/android/media/tv/interactive/TvIAppService.java
@@ -27,8 +27,11 @@
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.media.tv.AdRequest;
+import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.BroadcastInfoResponse;
+import android.media.tv.TvTrackInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -90,23 +93,26 @@
@Retention(RetentionPolicy.SOURCE)
@StringDef(prefix = "IAPP_SERVICE_COMMAND_TYPE_", value = {
IAPP_SERVICE_COMMAND_TYPE_TUNE,
- IAPP_SERVICE_COMMAND_TYPE_TUNENEXT,
- IAPP_SERVICE_COMMAND_TYPE_TUNEPREV,
+ IAPP_SERVICE_COMMAND_TYPE_TUNE_NEXT,
+ IAPP_SERVICE_COMMAND_TYPE_TUNE_PREV,
IAPP_SERVICE_COMMAND_TYPE_STOP,
- IAPP_SERVICE_COMMAND_TYPE_SETSTREAMVOLUME
+ IAPP_SERVICE_COMMAND_TYPE_SET_STREAM_VOLUME,
+ IAPP_SERVICE_COMMAND_TYPE_SELECT_TRACK
})
public @interface IAppServiceCommandType {}
/** @hide */
- public static final String IAPP_SERVICE_COMMAND_TYPE_TUNE = "Tune";
+ public static final String IAPP_SERVICE_COMMAND_TYPE_TUNE = "tune";
/** @hide */
- public static final String IAPP_SERVICE_COMMAND_TYPE_TUNENEXT = "TuneNext";
+ public static final String IAPP_SERVICE_COMMAND_TYPE_TUNE_NEXT = "tune_next";
/** @hide */
- public static final String IAPP_SERVICE_COMMAND_TYPE_TUNEPREV = "TunePrevious";
+ public static final String IAPP_SERVICE_COMMAND_TYPE_TUNE_PREV = "tune_previous";
/** @hide */
- public static final String IAPP_SERVICE_COMMAND_TYPE_STOP = "Stop";
+ public static final String IAPP_SERVICE_COMMAND_TYPE_STOP = "stop";
/** @hide */
- public static final String IAPP_SERVICE_COMMAND_TYPE_SETSTREAMVOLUME = "setStreamVolume";
+ public static final String IAPP_SERVICE_COMMAND_TYPE_SET_STREAM_VOLUME = "set_stream_volume";
+ /** @hide */
+ public static final String IAPP_SERVICE_COMMAND_TYPE_SELECT_TRACK = "select_track";
private final Handler mServiceHandler = new ServiceHandler();
private final RemoteCallbackList<ITvIAppServiceCallback> mCallbacks =
@@ -244,7 +250,7 @@
*
* @param context The context of the application
*/
- public Session(Context context) {
+ public Session(@NonNull Context context) {
mContext = context;
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mHandler = new Handler(context.getMainLooper());
@@ -288,6 +294,63 @@
}
/**
+ * Stops TvIAppService session.
+ * @hide
+ */
+ public void onStopIApp() {
+ }
+
+ /**
+ * Creates broadcast-independent(BI) interactive application.
+ *
+ * @see #onDestroyBiInteractiveApp(String)
+ * @hide
+ */
+ public void onCreateBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
+ }
+
+
+ /**
+ * Destroys broadcast-independent(BI) interactive application.
+ *
+ * @param biIAppId the BI interactive app ID from
+ * {@link #createBiInteractiveApp(Uri, Bundle)}
+ *
+ * @see #onCreateBiInteractiveApp(Uri, Bundle)
+ * @hide
+ */
+ public void onDestroyBiInteractiveApp(@NonNull String biIAppId) {
+ }
+
+ /**
+ * Receives current channel URI.
+ * @hide
+ */
+ public void onCurrentChannelUri(@Nullable Uri channelUri) {
+ }
+
+ /**
+ * Receives logical channel number (LCN) of current channel.
+ * @hide
+ */
+ public void onCurrentChannelLcn(int lcn) {
+ }
+
+ /**
+ * Receives stream volume.
+ * @hide
+ */
+ public void onStreamVolume(float volume) {
+ }
+
+ /**
+ * Receives track list.
+ * @hide
+ */
+ public void onTrackInfoList(@NonNull List<TvTrackInfo> tracks) {
+ }
+
+ /**
* Called when the application sets the surface.
*
* <p>The TV IApp service should render interactive app UI onto the given surface. When
@@ -332,6 +395,7 @@
*
* @return a view attached to the media window
*/
+ @Nullable
public View onCreateMediaView() {
return null;
}
@@ -347,14 +411,35 @@
* Called when the corresponding TV input tuned to a channel.
* @hide
*/
- public void onTuned(Uri channelUri) {
+ public void onTuned(@NonNull Uri channelUri) {
+ }
+
+ /**
+ * Called when the corresponding TV input selected to a track.
+ * @hide
+ */
+ public void onTrackSelected(int type, String trackId) {
+ }
+
+ /**
+ * Called when the tracks are changed.
+ * @hide
+ */
+ public void onTracksChanged(List<TvTrackInfo> tracks) {
}
/**
* Called when a broadcast info response is received.
* @hide
*/
- public void onBroadcastInfoResponse(BroadcastInfoResponse response) {
+ public void onBroadcastInfoResponse(@NonNull BroadcastInfoResponse response) {
+ }
+
+ /**
+ * Called when an advertisement response is received.
+ * @hide
+ */
+ public void onAdResponse(AdResponse response) {
}
/**
@@ -362,7 +447,7 @@
* @hide
*/
@Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
+ public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
return false;
}
@@ -370,7 +455,7 @@
* @hide
*/
@Override
- public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ public boolean onKeyLongPress(int keyCode, @NonNull KeyEvent event) {
return false;
}
@@ -378,7 +463,7 @@
* @hide
*/
@Override
- public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
+ public boolean onKeyMultiple(int keyCode, int count, @NonNull KeyEvent event) {
return false;
}
@@ -386,28 +471,28 @@
* @hide
*/
@Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
+ public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
return false;
}
/**
* @hide
*/
- public boolean onTouchEvent(MotionEvent event) {
+ public boolean onTouchEvent(@NonNull MotionEvent event) {
return false;
}
/**
* @hide
*/
- public boolean onTrackballEvent(MotionEvent event) {
+ public boolean onTrackballEvent(@NonNull MotionEvent event) {
return false;
}
/**
* @hide
*/
- public boolean onGenericMotionEvent(MotionEvent event) {
+ public boolean onGenericMotionEvent(@NonNull MotionEvent event) {
return false;
}
@@ -469,6 +554,30 @@
}
/**
+ * Remove broadcast information request from the related TV input.
+ * @param requestId the ID of the request
+ */
+ public void removeBroadcastInfo(final int requestId) {
+ executeOrPostRunnableOnMainThread(new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "removeBroadcastInfo (requestId="
+ + requestId + ")");
+ }
+ if (mSessionCallback != null) {
+ mSessionCallback.onRemoveBroadcastInfo(requestId);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in removeBroadcastInfo", e);
+ }
+ }
+ });
+ }
+
+ /**
* requests a specific command to be processed by the related TV input.
* @param cmdType type of the specific command
* @param parameters parameters of the specific command
@@ -493,10 +602,171 @@
});
}
+ /**
+ * Sets broadcast video bounds.
+ */
+ public void setVideoBounds(Rect rect) {
+ executeOrPostRunnableOnMainThread(new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "setVideoBounds (rect=" + rect + ")");
+ }
+ if (mSessionCallback != null) {
+ mSessionCallback.onSetVideoBounds(rect);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in setVideoBounds", e);
+ }
+ }
+ });
+ }
+
+ /**
+ * Requests the URI of the current channel.
+ */
+ public void requestCurrentChannelUri() {
+ executeOrPostRunnableOnMainThread(new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "requestCurrentChannelUri");
+ }
+ if (mSessionCallback != null) {
+ mSessionCallback.onRequestCurrentChannelUri();
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in requestCurrentChannelUri", e);
+ }
+ }
+ });
+ }
+
+ /**
+ * Requests the logic channel number (LCN) of the current channel.
+ */
+ public void requestCurrentChannelLcn() {
+ executeOrPostRunnableOnMainThread(new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "requestCurrentChannelLcn");
+ }
+ if (mSessionCallback != null) {
+ mSessionCallback.onRequestCurrentChannelLcn();
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in requestCurrentChannelLcn", e);
+ }
+ }
+ });
+ }
+
+ /**
+ * Requests stream volume.
+ */
+ public void requestStreamVolume() {
+ executeOrPostRunnableOnMainThread(new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "requestStreamVolume");
+ }
+ if (mSessionCallback != null) {
+ mSessionCallback.onRequestStreamVolume();
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in requestStreamVolume", e);
+ }
+ }
+ });
+ }
+
+ /**
+ * Requests the list of {@link TvTrackInfo}.
+ */
+ public void requestTrackInfoList() {
+ executeOrPostRunnableOnMainThread(new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "requestTrackInfoList");
+ }
+ if (mSessionCallback != null) {
+ mSessionCallback.onRequestTrackInfoList();
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in requestTrackInfoList", e);
+ }
+ }
+ });
+ }
+
+ /**
+ * requests an advertisement request to be processed by the related TV input.
+ * @param request advertisement request
+ */
+ public void requestAd(@NonNull final AdRequest request) {
+ executeOrPostRunnableOnMainThread(new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "requestAd (id=" + request.getId() + ")");
+ }
+ if (mSessionCallback != null) {
+ mSessionCallback.onAdRequest(request);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in requestAd", e);
+ }
+ }
+ });
+ }
+
void startIApp() {
onStartIApp();
}
+ void stopIApp() {
+ onStopIApp();
+ }
+
+ void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
+ onCreateBiInteractiveApp(biIAppUri, params);
+ }
+
+ void destroyBiInteractiveApp(@NonNull String biIAppId) {
+ onDestroyBiInteractiveApp(biIAppId);
+ }
+
+ void sendCurrentChannelUri(@Nullable Uri channelUri) {
+ onCurrentChannelUri(channelUri);
+ }
+
+ void sendCurrentChannelLcn(int lcn) {
+ onCurrentChannelLcn(lcn);
+ }
+
+ void sendStreamVolume(float volume) {
+ onStreamVolume(volume);
+ }
+
+ void sendTrackInfoList(@NonNull List<TvTrackInfo> tracks) {
+ onTrackInfoList(tracks);
+ }
+
void release() {
onRelease();
if (mSurface != null) {
@@ -519,6 +789,20 @@
onTuned(channelUri);
}
+ void notifyTrackSelected(int type, String trackId) {
+ if (DEBUG) {
+ Log.d(TAG, "notifyTrackSelected (type=" + type + "trackId=" + trackId + ")");
+ }
+ onTrackSelected(type, trackId);
+ }
+
+ void notifyTracksChanged(List<TvTrackInfo> tracks) {
+ if (DEBUG) {
+ Log.d(TAG, "notifyTracksChanged (tracks=" + tracks + ")");
+ }
+ onTracksChanged(tracks);
+ }
+
/**
* Calls {@link #onBroadcastInfoResponse}.
@@ -532,6 +816,16 @@
}
/**
+ * Calls {@link #onAdResponse}.
+ */
+ void notifyAdResponse(AdResponse response) {
+ if (DEBUG) {
+ Log.d(TAG, "notifyAdResponse (requestId=" + response.getId() + ")");
+ }
+ onAdResponse(response);
+ }
+
+ /**
* Notifies when the session state is changed.
* @param state the current state.
*/
@@ -556,6 +850,32 @@
}
/**
+ * Notifies the broadcast-independent(BI) interactive application has been created.
+ * @param biIAppId BI interactive app ID, which can be used to destroy the BI interactive
+ * app.
+ * @hide
+ */
+ public final void notifyBiInteractiveAppCreated(Uri biIAppUri, String biIAppId) {
+ executeOrPostRunnableOnMainThread(new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "notifyBiInteractiveAppCreated (biIAppId="
+ + biIAppId + ")");
+ }
+ if (mSessionCallback != null) {
+ mSessionCallback.onBiInteractiveAppCreated(biIAppUri, biIAppId);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in notifyBiInteractiveAppCreated", e);
+ }
+ }
+ });
+ }
+
+ /**
* Takes care of dispatching incoming input events and tells whether the event was handled.
*/
int dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
@@ -793,6 +1113,41 @@
}
@Override
+ public void stopIApp() {
+ mSessionImpl.stopIApp();
+ }
+
+ @Override
+ public void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
+ mSessionImpl.createBiInteractiveApp(biIAppUri, params);
+ }
+
+ @Override
+ public void destroyBiInteractiveApp(@NonNull String biIAppId) {
+ mSessionImpl.destroyBiInteractiveApp(biIAppId);
+ }
+
+ @Override
+ public void sendCurrentChannelUri(@Nullable Uri channelUri) {
+ mSessionImpl.sendCurrentChannelUri(channelUri);
+ }
+
+ @Override
+ public void sendCurrentChannelLcn(int lcn) {
+ mSessionImpl.sendCurrentChannelLcn(lcn);
+ }
+
+ @Override
+ public void sendStreamVolume(float volume) {
+ mSessionImpl.sendStreamVolume(volume);
+ }
+
+ @Override
+ public void sendTrackInfoList(@NonNull List<TvTrackInfo> tracks) {
+ mSessionImpl.sendTrackInfoList(tracks);
+ }
+
+ @Override
public void release() {
mSessionImpl.scheduleMediaViewCleanup();
mSessionImpl.release();
@@ -804,6 +1159,16 @@
}
@Override
+ public void notifyTrackSelected(int type, final String trackId) {
+ mSessionImpl.notifyTrackSelected(type, trackId);
+ }
+
+ @Override
+ public void notifyTracksChanged(List<TvTrackInfo> tracks) {
+ mSessionImpl.notifyTracksChanged(tracks);
+ }
+
+ @Override
public void setSurface(Surface surface) {
mSessionImpl.setSurface(surface);
}
@@ -819,6 +1184,11 @@
}
@Override
+ public void notifyAdResponse(AdResponse response) {
+ mSessionImpl.notifyAdResponse(response);
+ }
+
+ @Override
public void createMediaView(IBinder windowToken, Rect frame) {
mSessionImpl.createMediaView(windowToken, frame);
}
diff --git a/media/java/android/media/tv/interactive/TvIAppView.java b/media/java/android/media/tv/interactive/TvIAppView.java
index efbe9e3..1ce14ae 100644
--- a/media/java/android/media/tv/interactive/TvIAppView.java
+++ b/media/java/android/media/tv/interactive/TvIAppView.java
@@ -16,6 +16,7 @@
package android.media.tv.interactive;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
@@ -23,9 +24,11 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.media.tv.TvInputManager;
+import android.media.tv.TvTrackInfo;
import android.media.tv.TvView;
import android.media.tv.interactive.TvIAppManager.Session;
import android.media.tv.interactive.TvIAppManager.SessionCallback;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.AttributeSet;
@@ -37,6 +40,8 @@
import android.view.View;
import android.view.ViewGroup;
+import java.util.List;
+
/**
* Displays contents of interactive TV applications.
* @hide
@@ -104,12 +109,16 @@
}
};
- public TvIAppView(Context context) {
+ public TvIAppView(@NonNull Context context) {
this(context, null, 0);
}
- public TvIAppView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, /* attrs = */null, /* defStyleAttr = */0);
+ public TvIAppView(@NonNull Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public TvIAppView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
int sourceResId = Resources.getAttributeSetSourceResId(attrs);
if (sourceResId != Resources.ID_NULL) {
Log.d(TAG, "Build local AttributeSet");
@@ -122,7 +131,7 @@
}
mDefStyleAttr = defStyleAttr;
resetSurfaceView();
- mTvIAppManager = (TvIAppManager) getContext().getSystemService("tv_interactive_app");
+ mTvIAppManager = (TvIAppManager) getContext().getSystemService(Context.TV_IAPP_SERVICE);
}
/**
@@ -266,7 +275,7 @@
/**
* Prepares the interactive application.
*/
- public void prepareIApp(String iAppServiceId, int type) {
+ public void prepareIApp(@NonNull String iAppServiceId, int type) {
// TODO: document and handle the cases that this method is called multiple times.
if (DEBUG) {
Log.d(TAG, "prepareIApp");
@@ -289,6 +298,66 @@
}
}
+ /**
+ * Stops the interactive application.
+ */
+ public void stopIApp() {
+ if (DEBUG) {
+ Log.d(TAG, "stopIApp");
+ }
+ if (mSession != null) {
+ mSession.stopIApp();
+ }
+ }
+
+ /**
+ * Sends current channel URI to related TV interactive app.
+ */
+ public void sendCurrentChannelUri(Uri channelUri) {
+ if (DEBUG) {
+ Log.d(TAG, "sendCurrentChannelUri");
+ }
+ if (mSession != null) {
+ mSession.sendCurrentChannelUri(channelUri);
+ }
+ }
+
+ /**
+ * Sends current channel logical channel number (LCN) to related TV interactive app.
+ */
+ public void sendCurrentChannelLcn(int lcn) {
+ if (DEBUG) {
+ Log.d(TAG, "sendCurrentChannelLcn");
+ }
+ if (mSession != null) {
+ mSession.sendCurrentChannelLcn(lcn);
+ }
+ }
+
+ /**
+ * Sends stream volume to related TV interactive app.
+ */
+ public void sendStreamVolume(float volume) {
+ if (DEBUG) {
+ Log.d(TAG, "sendStreamVolume");
+ }
+ if (mSession != null) {
+ mSession.sendStreamVolume(volume);
+ }
+ }
+
+ /**
+ * Sends track info list to related TV interactive app.
+ */
+ public void sendTrackInfoList(List<TvTrackInfo> tracks) {
+ if (DEBUG) {
+ Log.d(TAG, "sendTrackInfoList");
+ }
+ if (mSession != null) {
+ mSession.sendTrackInfoList(tracks);
+ }
+ }
+
private void resetInternal() {
mSessionCallback = null;
if (mSession != null) {
@@ -301,6 +370,38 @@
}
}
+ /**
+ * Creates broadcast-independent(BI) interactive application.
+ *
+ * @see #destroyBiInteractiveApp(String)
+ * @hide
+ */
+ public void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
+ if (DEBUG) {
+ Log.d(TAG, "createBiInteractiveApp Uri=" + biIAppUri + ", params=" + params);
+ }
+ if (mSession != null) {
+ mSession.createBiInteractiveApp(biIAppUri, params);
+ }
+ }
+
+ /**
+ * Destroys broadcast-independent(BI) interactive application.
+ *
+ * @param biIAppId the BI interactive app ID from {@link #createBiInteractiveApp(Uri, Bundle)}
+ *
+ * @see #createBiInteractiveApp(Uri, Bundle)
+ * @hide
+ */
+ public void destroyBiInteractiveApp(@NonNull String biIAppId) {
+ if (DEBUG) {
+ Log.d(TAG, "destroyBiInteractiveApp biIAppId=" + biIAppId);
+ }
+ if (mSession != null) {
+ mSession.destroyBiInteractiveApp(biIAppId);
+ }
+ }
+
public Session getIAppSession() {
return mSession;
}
@@ -346,8 +447,72 @@
* @param cmdType type of the command
* @param parameters parameters of the command
*/
- public void onCommandRequest(String iAppServiceId,
- @TvIAppService.IAppServiceCommandType String cmdType, Bundle parameters) {
+ public void onCommandRequest(
+ @NonNull String iAppServiceId,
+ @NonNull @TvIAppService.IAppServiceCommandType String cmdType,
+ @Nullable Bundle parameters) {
+ }
+
+ /**
+ * This is called when the session state is changed.
+ *
+ * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ * @param state current session state.
+ */
+ public void onSessionStateChanged(@NonNull String iAppServiceId, int state) {
+ }
+
+ /**
+ * This is called when broadcast-independent (BI) interactive app is created.
+ *
+ * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ * @param biIAppUri URI associated this BI interactive app. This is the same URI in
+ * {@link Session#createBiInteractiveApp(Uri, Bundle)}
+ * @param biIAppId BI interactive app ID, which can be used to destroy the BI interactive
+ * app.
+ */
+ public void onBiInteractiveAppCreated(@NonNull String iAppServiceId, @NonNull Uri biIAppUri,
+ @Nullable String biIAppId) {
+ }
+
+ /**
+ * This is called when {@link TvIAppService.Session#SetVideoBounds} is called.
+ *
+ * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ */
+ public void onSetVideoBounds(@NonNull String iAppServiceId, @NonNull Rect rect) {
+ }
+
+ /**
+ * This is called when {@link TvIAppService.Session#RequestCurrentChannelUri} is called.
+ *
+ * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ */
+ public void onRequestCurrentChannelUri(@NonNull String iAppServiceId) {
+ }
+
+ /**
+ * This is called when {@link TvIAppService.Session#RequestCurrentChannelLcn} is called.
+ *
+ * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ */
+ public void onRequestCurrentChannelLcn(@NonNull String iAppServiceId) {
+ }
+
+ /**
+ * This is called when {@link TvIAppService.Session#RequestStreamVolume} is called.
+ *
+ * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ */
+ public void onRequestStreamVolume(@NonNull String iAppServiceId) {
+ }
+
+ /**
+ * This is called when {@link TvIAppService.Session#RequestTrackInfoList} is called.
+ *
+ * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ */
+ public void onRequestTrackInfoList(@NonNull String iAppServiceId) {
}
}
@@ -440,5 +605,104 @@
mCallback.onCommandRequest(mIAppServiceId, cmdType, parameters);
}
}
+
+ @Override
+ public void onSessionStateChanged(Session session, int state) {
+ if (DEBUG) {
+ Log.d(TAG, "onSessionStateChanged (state=" + state + ")");
+ }
+ if (this != mSessionCallback) {
+ Log.w(TAG, "onSessionStateChanged - session not created");
+ return;
+ }
+ if (mCallback != null) {
+ mCallback.onSessionStateChanged(mIAppServiceId, state);
+ }
+ }
+
+ @Override
+ public void onBiInteractiveAppCreated(Session session, Uri biIAppUri, String biIAppId) {
+ if (DEBUG) {
+ Log.d(TAG, "onBiInteractiveAppCreated (biIAppUri=" + biIAppUri + ", biIAppId="
+ + biIAppId + ")");
+ }
+ if (this != mSessionCallback) {
+ Log.w(TAG, "onBiInteractiveAppCreated - session not created");
+ return;
+ }
+ if (mCallback != null) {
+ mCallback.onBiInteractiveAppCreated(mIAppServiceId, biIAppUri, biIAppId);
+ }
+ }
+
+ @Override
+ public void onSetVideoBounds(Session session, Rect rect) {
+ if (DEBUG) {
+ Log.d(TAG, "onSetVideoBounds (rect=" + rect + ")");
+ }
+ if (this != mSessionCallback) {
+ Log.w(TAG, "onSetVideoBounds - session not created");
+ return;
+ }
+ if (mCallback != null) {
+ mCallback.onSetVideoBounds(mIAppServiceId, rect);
+ }
+ }
+
+ @Override
+ public void onRequestCurrentChannelUri(Session session) {
+ if (DEBUG) {
+ Log.d(TAG, "onRequestCurrentChannelUri");
+ }
+ if (this != mSessionCallback) {
+ Log.w(TAG, "onRequestCurrentChannelUri - session not created");
+ return;
+ }
+ if (mCallback != null) {
+ mCallback.onRequestCurrentChannelUri(mIAppServiceId);
+ }
+ }
+
+ @Override
+ public void onRequestCurrentChannelLcn(Session session) {
+ if (DEBUG) {
+ Log.d(TAG, "onRequestCurrentChannelLcn");
+ }
+ if (this != mSessionCallback) {
+ Log.w(TAG, "onRequestCurrentChannelLcn - session not created");
+ return;
+ }
+ if (mCallback != null) {
+ mCallback.onRequestCurrentChannelLcn(mIAppServiceId);
+ }
+ }
+
+ @Override
+ public void onRequestStreamVolume(Session session) {
+ if (DEBUG) {
+ Log.d(TAG, "onRequestStreamVolume");
+ }
+ if (this != mSessionCallback) {
+ Log.w(TAG, "onRequestStreamVolume - session not created");
+ return;
+ }
+ if (mCallback != null) {
+ mCallback.onRequestStreamVolume(mIAppServiceId);
+ }
+ }
+
+ @Override
+ public void onRequestTrackInfoList(Session session) {
+ if (DEBUG) {
+ Log.d(TAG, "onRequestTrackInfoList");
+ }
+ if (this != mSessionCallback) {
+ Log.w(TAG, "onRequestTrackInfoList - session not created");
+ return;
+ }
+ if (mCallback != null) {
+ mCallback.onRequestTrackInfoList(mIAppServiceId);
+ }
+ }
}
}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 255b391b..7c08913 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -687,6 +687,7 @@
private native FrontendInfo nativeGetFrontendInfo(int id);
private native Filter nativeOpenFilter(int type, int subType, long bufferSize);
private native TimeFilter nativeOpenTimeFilter();
+ private native String nativeGetFrontendHardwareInfo();
private native Lnb nativeOpenLnbByHandle(int handle);
private native Lnb nativeOpenLnbByName(String name);
@@ -1278,6 +1279,34 @@
return Arrays.asList(feInfoList);
}
+ /**
+ * Gets the currently initialized and activated frontend hardware information. The return values
+ * would differ per device makers. E.g. RF chip version, Demod chip version, detailed status of
+ * dvbs blind scan, etc
+ *
+ * <p>This API is only supported by Tuner HAL 2.0 or higher. Unsupported version would return
+ * {@code null}. Use {@link TunerVersionChecker#getTunerVersion()} to check the version.
+ *
+ * @return The active frontend hardware information. {@code null} if the operation failed.
+ * @throws IllegalStateException if there is no active frontend currently.
+ */
+ @Nullable
+ public String getCurrentFrontendHardwardInfo() {
+ mFrontendLock.lock();
+ try {
+ if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_2_0, "Get Frontend hardware info")) {
+ return null;
+ }
+ if (mFrontend == null) {
+ throw new IllegalStateException("frontend is not initialized");
+ }
+ return nativeGetFrontendHardwareInfo();
+ } finally {
+ mFrontendLock.unlock();
+ }
+ }
+
/** @hide */
public FrontendInfo getFrontendInfoById(int id) {
mFrontendLock.lock();
@@ -1353,6 +1382,24 @@
}
}
+ private void onUnLocked() {
+ Log.d(TAG, "Wrote Stats Log for unlocked event from scanning.");
+ FrameworkStatsLog.write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
+ FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__LOCKED);
+
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onUnLocked();
+ }
+ }
+ });
+ }
+ }
+ }
+
private void onScanStopped() {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) {
@@ -1577,6 +1624,20 @@
}
}
+ private void onDvbtCellIdsReported(int[] dvbtCellIds) {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(() -> {
+ synchronized (mScanCallbackLock) {
+ if (mScanCallback != null) {
+ mScanCallback.onDvbtCellIdsReported(dvbtCellIds);
+ }
+ }
+ });
+ }
+ }
+ }
+
/**
* Opens a filter object based on the given types and buffer size.
*
diff --git a/media/java/android/media/tv/tuner/filter/AvSettings.java b/media/java/android/media/tv/tuner/filter/AvSettings.java
index ed04754..15811d2 100644
--- a/media/java/android/media/tv/tuner/filter/AvSettings.java
+++ b/media/java/android/media/tv/tuner/filter/AvSettings.java
@@ -107,7 +107,8 @@
AUDIO_STREAM_TYPE_AAC, AUDIO_STREAM_TYPE_AC3, AUDIO_STREAM_TYPE_EAC3,
AUDIO_STREAM_TYPE_AC4, AUDIO_STREAM_TYPE_DTS, AUDIO_STREAM_TYPE_DTS_HD,
AUDIO_STREAM_TYPE_WMA, AUDIO_STREAM_TYPE_OPUS, AUDIO_STREAM_TYPE_VORBIS,
- AUDIO_STREAM_TYPE_DRA})
+ AUDIO_STREAM_TYPE_DRA, AUDIO_STREAM_TYPE_AAC_ADTS, AUDIO_STREAM_TYPE_AAC_LATM,
+ AUDIO_STREAM_TYPE_AAC_HE_ADTS, AUDIO_STREAM_TYPE_AAC_HE_LATM})
@Retention(RetentionPolicy.SOURCE)
public @interface AudioStreamType {}
@@ -182,6 +183,41 @@
*/
public static final int AUDIO_STREAM_TYPE_DRA = android.hardware.tv.tuner.AudioStreamType.DRA;
+ /*
+ * AAC with ADTS (Audio Data Transport Format).
+ *
+ * This API is only supported by Tuner HAL 2.0 or higher. Use
+ * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+ */
+ public static final int AUDIO_STREAM_TYPE_AAC_ADTS =
+ android.hardware.tv.tuner.AudioStreamType.AAC_ADTS;
+
+ /*
+ * AAC with ADTS with LATM (Low-overhead MPEG-4 Audio Transport Multiplex).
+ *
+ * This API is only supported by Tuner HAL 2.0 or higher. Use
+ * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+ */
+ public static final int AUDIO_STREAM_TYPE_AAC_LATM =
+ android.hardware.tv.tuner.AudioStreamType.AAC_LATM;
+
+ /*
+ * High-Efficiency AAC (HE-AAC) with ADTS (Audio Data Transport Format).
+ *
+ * This API is only supported by Tuner HAL 2.0 or higher. Use
+ * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+ */
+ public static final int AUDIO_STREAM_TYPE_AAC_HE_ADTS =
+ android.hardware.tv.tuner.AudioStreamType.AAC_HE_ADTS;
+
+ /*
+ * High-Efficiency AAC (HE-AAC) with LATM (Low-overhead MPEG-4 Audio Transport Multiplex).
+ *
+ * This API is only supported by Tuner HAL 2.0 or higher. Use
+ * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+ */
+ public static final int AUDIO_STREAM_TYPE_AAC_HE_LATM =
+ android.hardware.tv.tuner.AudioStreamType.AAC_HE_LATM;
private final boolean mIsPassthrough;
private int mAudioStreamType = AUDIO_STREAM_TYPE_UNDEFINED;
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index 5d71a13..f9fc17f 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -254,6 +254,8 @@
private native int nativeClose();
private native String nativeAcquireSharedFilterToken();
private native void nativeFreeSharedFilterToken(String token);
+ private native int nativeSetTimeDelayHint(int timeDelayInMs);
+ private native int nativeSetDataSizeDelayHint(int dataSizeDelayInBytes);
// Called by JNI
private Filter(long id) {
@@ -599,4 +601,52 @@
mIsShared = false;
}
}
+
+ /**
+ * Set filter time delay.
+ *
+ * <p> Setting a time delay instructs the filter to delay its event callback invocation until
+ * the specified amount of time has passed. The default value (delay disabled) is {@code 0}.
+ *
+ * <p>This functionality is only available in Tuner version 2.0 and higher and will otherwise
+ * be a no-op. Use {@link TunerVersionChecker#getTunerVersion()} to get the version information.
+ *
+ * @param delayInMs specifies the duration of the delay in milliseconds.
+ */
+ public int delayCallbackUntilTimeMillis(long delayInMs) {
+ if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_2_0, "setTimeDelayHint")) {
+ return Tuner.RESULT_UNAVAILABLE;
+ }
+
+ if (delayInMs >= 0 && delayInMs <= Integer.MAX_VALUE) {
+ synchronized (mLock) {
+ return nativeSetTimeDelayHint((int) delayInMs);
+ }
+ }
+ return Tuner.RESULT_INVALID_ARGUMENT;
+ }
+
+ /**
+ * Set filter data size delay.
+ *
+ * <p> Setting a data size delay instructs the filter to delay its event callback invocation
+ * until a specified amount of data has accumulated. The default value (delay disabled) is
+ * {@code 0}.
+ *
+ * <p>This functionality is only available in Tuner version 2.0 and higher and will otherwise
+ * be a no-op. Use {@link TunerVersionChecker#getTunerVersion()} to get the version information.
+ *
+ * @param delayInBytes specifies the duration of the delay in bytes.
+ */
+ public int delayCallbackUntilBufferFilled(int delayInBytes) {
+ if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_2_0, "setTimeDelayHint")) {
+ return Tuner.RESULT_UNAVAILABLE;
+ }
+
+ synchronized (mLock) {
+ return nativeSetDataSizeDelayHint(delayInBytes);
+ }
+ }
}
diff --git a/media/java/android/media/tv/tuner/filter/MediaEvent.java b/media/java/android/media/tv/tuner/filter/MediaEvent.java
index 79d4062..d958db1 100644
--- a/media/java/android/media/tv/tuner/filter/MediaEvent.java
+++ b/media/java/android/media/tv/tuner/filter/MediaEvent.java
@@ -49,12 +49,14 @@
private final long mDataId;
private final int mMpuSequenceNumber;
private final boolean mIsPrivateData;
+ private final int mScIndexMask;
private final AudioDescriptor mExtraMetaData;
// This constructor is used by JNI code only
private MediaEvent(int streamId, boolean isPtsPresent, long pts, boolean isDtsPresent, long dts,
long dataLength, long offset, LinearBlock buffer, boolean isSecureMemory, long dataId,
- int mpuSequenceNumber, boolean isPrivateData, AudioDescriptor extraMetaData) {
+ int mpuSequenceNumber, boolean isPrivateData, int scIndexMask,
+ AudioDescriptor extraMetaData) {
mStreamId = streamId;
mIsPtsPresent = isPtsPresent;
mPts = pts;
@@ -67,6 +69,7 @@
mDataId = dataId;
mMpuSequenceNumber = mpuSequenceNumber;
mIsPrivateData = isPrivateData;
+ mScIndexMask = scIndexMask;
mExtraMetaData = extraMetaData;
}
@@ -194,6 +197,17 @@
}
/**
+ * Gets SC (Start Code) index mask.
+ *
+ * <p>This API is only supported by Tuner HAL 2.0 or higher. Unsupported version would return
+ * {@code 0}. Use {@link TunerVersionChecker#getTunerVersion()} to check the version.
+ */
+ @RecordSettings.ScIndexMask
+ public int getScIndexMask() {
+ return mScIndexMask;
+ }
+
+ /**
* Gets audio extra metadata.
*/
@Nullable
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index 92eafec..8cedd04 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -53,7 +53,8 @@
FRONTEND_STATUS_TYPE_MODULATIONS_EXT, FRONTEND_STATUS_TYPE_ROLL_OFF,
FRONTEND_STATUS_TYPE_IS_MISO_ENABLED, FRONTEND_STATUS_TYPE_IS_LINEAR,
FRONTEND_STATUS_TYPE_IS_SHORT_FRAMES_ENABLED, FRONTEND_STATUS_TYPE_ISDBT_MODE,
- FRONTEND_STATUS_TYPE_ISDBT_PARTIAL_RECEPTION_FLAG, FRONTEND_STATUS_TYPE_STREAM_IDS})
+ FRONTEND_STATUS_TYPE_ISDBT_PARTIAL_RECEPTION_FLAG, FRONTEND_STATUS_TYPE_STREAM_IDS,
+ FRONTEND_STATUS_TYPE_DVBT_CELL_IDS})
@Retention(RetentionPolicy.SOURCE)
public @interface FrontendStatusType {}
@@ -260,6 +261,12 @@
public static final int FRONTEND_STATUS_TYPE_STREAM_IDS =
android.hardware.tv.tuner.FrontendStatusType.STREAM_ID_LIST;
+ /**
+ * DVB-T Cell IDs.
+ */
+ public static final int FRONTEND_STATUS_TYPE_DVBT_CELL_IDS =
+ android.hardware.tv.tuner.FrontendStatusType.DVBT_CELL_IDS;
+
/** @hide */
@IntDef(value = {
AtscFrontendSettings.MODULATION_UNDEFINED,
@@ -500,6 +507,7 @@
private Integer mIsdbtMode;
private Integer mIsdbtPartialReceptionFlag;
private int[] mStreamIds;
+ private int[] mDvbtCellIds;
// Constructed and fields set by JNI code.
private FrontendStatus() {
@@ -1052,6 +1060,24 @@
}
/**
+ * Gets DVB-T cell ids.
+ *
+ * <p>This query is only supported by Tuner HAL 2.0 or higher. Unsupported version or if HAL
+ * doesn't return cell ids will throw IllegalStateException. Use
+ * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+ */
+ @SuppressLint("ArrayReturn")
+ @NonNull
+ public int[] getDvbtCellIds() {
+ TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_2_0, "dvbt cell ids status");
+ if (mDvbtCellIds == null) {
+ throw new IllegalStateException("dvbt cell ids are empty");
+ }
+ return mDvbtCellIds;
+ }
+
+ /**
* Information of each tuning Physical Layer Pipes.
*/
public static class Atsc3PlpTuningInfo {
diff --git a/media/java/android/media/tv/tuner/frontend/ScanCallback.java b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
index cb35edb..6bbc13fe 100644
--- a/media/java/android/media/tv/tuner/frontend/ScanCallback.java
+++ b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
@@ -36,6 +36,9 @@
*/
void onLocked();
+ /** Scan unlocked the signal. */
+ default void onUnLocked() {}
+
/** Scan stopped. */
void onScanStopped();
@@ -94,4 +97,7 @@
/** DVBC Frontend Annex reported. */
default void onDvbcAnnexReported(@DvbcFrontendSettings.Annex int dvbcAnnex) {}
+
+ /** DVBT Frontend Cell Ids reported. */
+ default void onDvbtCellIdsReported(@NonNull int[] dvbtCellIds) {}
}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index e91e238..f5606bc 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -62,6 +62,8 @@
#include <aidl/android/hardware/tv/tuner/DemuxTsFilterType.h>
#include <aidl/android/hardware/tv/tuner/DemuxTsIndex.h>
#include <aidl/android/hardware/tv/tuner/DvrSettings.h>
+#include <aidl/android/hardware/tv/tuner/FilterDelayHint.h>
+#include <aidl/android/hardware/tv/tuner/FilterDelayHintType.h>
#include <aidl/android/hardware/tv/tuner/FrontendAnalogAftFlag.h>
#include <aidl/android/hardware/tv/tuner/FrontendAnalogSettings.h>
#include <aidl/android/hardware/tv/tuner/FrontendAnalogSifStandard.h>
@@ -210,6 +212,8 @@
using ::aidl::android::hardware::tv::tuner::DemuxTsFilterType;
using ::aidl::android::hardware::tv::tuner::DemuxTsIndex;
using ::aidl::android::hardware::tv::tuner::DvrSettings;
+using ::aidl::android::hardware::tv::tuner::FilterDelayHint;
+using ::aidl::android::hardware::tv::tuner::FilterDelayHintType;
using ::aidl::android::hardware::tv::tuner::FrontendAnalogAftFlag;
using ::aidl::android::hardware::tv::tuner::FrontendAnalogSettings;
using ::aidl::android::hardware::tv::tuner::FrontendAnalogSifStandard;
@@ -604,9 +608,11 @@
const DemuxFilterEvent &event) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MediaEvent");
- jmethodID eventInit = env->GetMethodID(eventClazz, "<init>",
- "(IZJZJJJLandroid/media/MediaCodec$LinearBlock;"
- "ZJIZLandroid/media/tv/tuner/filter/AudioDescriptor;)V");
+ jmethodID eventInit = env->GetMethodID(
+ eventClazz,
+ "<init>",
+ "(IZJZJJJLandroid/media/MediaCodec$LinearBlock;"
+ "ZJIZILandroid/media/tv/tuner/filter/AudioDescriptor;)V");
jfieldID eventContext = env->GetFieldID(eventClazz, "mNativeContext", "J");
const DemuxFilterMediaEvent &mediaEvent = event.get<DemuxFilterEvent::Tag::media>();
@@ -639,10 +645,20 @@
jlong avDataId = mediaEvent.avDataId;
jint mpuSequenceNumber = mediaEvent.mpuSequenceNumber;
jboolean isPesPrivateData = mediaEvent.isPesPrivateData;
+ jint sc = 0;
+ if (mediaEvent.scIndexMask.getTag() == DemuxFilterScIndexMask::Tag::scIndex) {
+ sc = mediaEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scIndex>();
+ } else if (mediaEvent.scIndexMask.getTag() == DemuxFilterScIndexMask::Tag::scHevc) {
+ sc = mediaEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scHevc>();
+ } else if (mediaEvent.scIndexMask.getTag() == DemuxFilterScIndexMask::Tag::scAvc) {
+ sc = mediaEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scAvc>();
+ // Java uses the values defined by HIDL HAL. Left shift 4 bits.
+ sc = sc << 4;
+ }
jobject obj = env->NewObject(eventClazz, eventInit, streamId, isPtsPresent, pts, isDtsPresent,
dts, dataLength, offset, nullptr, isSecureMemory, avDataId,
- mpuSequenceNumber, isPesPrivateData, audioDescriptor);
+ mpuSequenceNumber, isPesPrivateData, sc, audioDescriptor);
uint64_t avSharedMemSize = mFilterClient->getAvSharedHandleInfo().size;
if (mediaEvent.avMemory.fds.size() > 0 || mediaEvent.avDataId != 0 ||
@@ -1025,6 +1041,10 @@
env->CallVoidMethod(
frontend,
env->GetMethodID(clazz, "onLocked", "()V"));
+ } else {
+ env->CallVoidMethod(
+ frontend,
+ env->GetMethodID(clazz, "onUnLocked", "()V"));
}
break;
}
@@ -1191,6 +1211,14 @@
dvbcAnnex);
break;
}
+ case FrontendScanMessageType::DVBT_CELL_IDS: {
+ std::vector<int32_t> jintV = message.get<FrontendScanMessage::dvbtCellIds>();
+ jintArray cellIds = env->NewIntArray(jintV.size());
+ env->SetIntArrayRegion(cellIds, 0, jintV.size(), reinterpret_cast<jint *>(&jintV[0]));
+ env->CallVoidMethod(frontend, env->GetMethodID(clazz, "onDvbtCellIdsReported", "([I)V"),
+ cellIds);
+ break;
+ }
default:
break;
}
@@ -1540,6 +1568,15 @@
maxSymbolRate, acquireRange, exclusiveGroupId, statusCaps, jcaps);
}
+Result JTuner::getFrontendHardwareInfo(string &info) {
+ if (mFeClient == nullptr) {
+ ALOGE("frontend is not initialized");
+ return Result::INVALID_STATE;
+ }
+
+ return mFeClient->getHardwareInfo(info);
+}
+
jobject JTuner::openLnbByHandle(int handle) {
if (mTunerClient == nullptr) {
return nullptr;
@@ -1649,11 +1686,10 @@
}
int JTuner::setLna(bool enable) {
- if (mFeClient == nullptr) {
- ALOGE("frontend client is not initialized");
- return (int)Result::INVALID_STATE;
+ if (mTunerClient == nullptr) {
+ return (int)Result::NOT_INITIALIZED;
}
- Result result = mFeClient->setLna(enable);
+ Result result = mTunerClient->setLna(enable);
return (int)result;
}
@@ -2519,6 +2555,16 @@
env->SetObjectField(statusObj, field, valObj);
break;
}
+ case FrontendStatus::Tag::dvbtCellIds: {
+ jfieldID field = env->GetFieldID(clazz, "mDvbtCellIds", "[I");
+ std::vector<int32_t> ids = s.get<FrontendStatus::Tag::dvbtCellIds>();
+
+ jintArray valObj = env->NewIntArray(v.size());
+ env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast<jint *>(&ids[0]));
+
+ env->SetObjectField(statusObj, field, valObj);
+ break;
+ }
}
}
return statusObj;
@@ -4016,6 +4062,36 @@
filterClient->freeSharedFilterToken(filterToken);
}
+static jint android_media_tv_Tuner_set_filter_time_delay_hint(
+ JNIEnv *env, jobject filter, int timeDelayInMs) {
+ sp<FilterClient> filterClient = getFilterClient(env, filter);
+ if (filterClient == nullptr) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Failed to set filter delay: filter client not found");
+ }
+
+ FilterDelayHint delayHint {
+ .hintType = FilterDelayHintType::TIME_DELAY_IN_MS,
+ .hintValue = timeDelayInMs,
+ };
+ return static_cast<jint>(filterClient->setDelayHint(delayHint));
+}
+
+static jint android_media_tv_Tuner_set_filter_data_size_delay_hint(
+ JNIEnv *env, jobject filter, int dataSizeDelayInBytes) {
+ sp<FilterClient> filterClient = getFilterClient(env, filter);
+ if (filterClient == nullptr) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Failed to set filter delay: filter client not found");
+ }
+
+ FilterDelayHint delayHint {
+ .hintType = FilterDelayHintType::DATA_SIZE_DELAY_IN_BYTES,
+ .hintValue = dataSizeDelayInBytes,
+ };
+ return static_cast<jint>(filterClient->setDelayHint(delayHint));
+}
+
static sp<TimeFilterClient> getTimeFilterClient(JNIEnv *env, jobject filter) {
return (TimeFilterClient *)env->GetLongField(filter, gFields.timeFilterContext);
}
@@ -4195,6 +4271,16 @@
return filterObj;
}
+static jstring android_media_tv_Tuner_get_frontend_hardware_info(JNIEnv *env, jobject thiz) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ string info;
+ Result r = tuner->getFrontendHardwareInfo(info);
+ if (r != Result::SUCCESS) {
+ return nullptr;
+ }
+ return env->NewStringUTF(info.data());
+}
+
static jint android_media_tv_Tuner_close_frontend(JNIEnv* env, jobject thiz, jint /* handle */) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->closeFrontend();
@@ -4504,6 +4590,8 @@
{ "nativeOpenSharedFilter",
"(Ljava/lang/String;)Landroid/media/tv/tuner/filter/SharedFilter;",
(void *)android_media_tv_Tuner_open_shared_filter},
+ { "nativeGetFrontendHardwareInfo","()Ljava/lang/String;",
+ (void *)android_media_tv_Tuner_get_frontend_hardware_info },
};
static const JNINativeMethod gFilterMethods[] = {
@@ -4524,6 +4612,10 @@
(void *)android_media_tv_Tuner_acquire_shared_filter_token},
{ "nativeFreeSharedFilterToken", "(Ljava/lang/String;)V",
(void *)android_media_tv_Tuner_free_shared_filter_token},
+ {"nativeSetTimeDelayHint", "(I)I",
+ (void *)android_media_tv_Tuner_set_filter_time_delay_hint},
+ {"nativeSetDataSizeDelayHint", "(I)I",
+ (void *)android_media_tv_Tuner_set_filter_data_size_delay_hint},
};
static const JNINativeMethod gSharedFilterMethods[] = {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 06e2492..4cad92b 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -200,6 +200,7 @@
jint close();
jint closeFrontend();
jint closeDemux();
+ Result getFrontendHardwareInfo(string& info);
jweak getObject();
diff --git a/media/jni/tuner/FrontendClient.cpp b/media/jni/tuner/FrontendClient.cpp
index 70309a0..0fdd8d8 100644
--- a/media/jni/tuner/FrontendClient.cpp
+++ b/media/jni/tuner/FrontendClient.cpp
@@ -102,15 +102,6 @@
return Result::INVALID_STATE;
}
-Result FrontendClient::setLna(bool bEnable) {
- if (mTunerFrontend != nullptr) {
- Status s = mTunerFrontend->setLna(bEnable);
- return ClientHelper::getServiceSpecificErrorCode(s);
- }
-
- return Result::INVALID_STATE;
-}
-
int32_t FrontendClient::linkCiCamToFrontend(int32_t ciCamId) {
int32_t ltsId = static_cast<int32_t>(Constant::INVALID_LTS_ID);
@@ -143,6 +134,15 @@
return Result::INVALID_STATE;
}
+Result FrontendClient::getHardwareInfo(string& info) {
+ if (mTunerFrontend != nullptr) {
+ Status s = mTunerFrontend->getHardwareInfo(&info);
+ return ClientHelper::getServiceSpecificErrorCode(s);
+ }
+
+ return Result::INVALID_STATE;
+}
+
shared_ptr<ITunerFrontend> FrontendClient::getAidlFrontend() {
return mTunerFrontend;
}
diff --git a/media/jni/tuner/FrontendClient.h b/media/jni/tuner/FrontendClient.h
index 08c0b20..77d9098 100644
--- a/media/jni/tuner/FrontendClient.h
+++ b/media/jni/tuner/FrontendClient.h
@@ -99,11 +99,6 @@
Result setLnb(sp<LnbClient> lnbClient);
/**
- * Enable or Disable Low Noise Amplifier (LNA).
- */
- Result setLna(bool bEnable);
-
- /**
* Link Frontend to the cicam with given id.
*
* @return lts id
@@ -120,7 +115,13 @@
*/
Result close();
+ /**
+ * Get Frontend hardware info.
+ */
+ Result getHardwareInfo(string& info);
+
int32_t getId();
+
shared_ptr<ITunerFrontend> getAidlFrontend();
private:
/**
diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp
index 861d78d..f917f01 100644
--- a/media/jni/tuner/TunerClient.cpp
+++ b/media/jni/tuner/TunerClient.cpp
@@ -185,4 +185,13 @@
return nullptr;
}
+Result TunerClient::setLna(bool bEnable) {
+ if (mTunerService != nullptr) {
+ Status s = mTunerService->setLna(bEnable);
+ return ClientHelper::getServiceSpecificErrorCode(s);
+ }
+
+ return Result::INVALID_STATE;
+}
+
} // namespace android
diff --git a/media/jni/tuner/TunerClient.h b/media/jni/tuner/TunerClient.h
index 3e59e26..37b8ee1 100644
--- a/media/jni/tuner/TunerClient.h
+++ b/media/jni/tuner/TunerClient.h
@@ -127,6 +127,11 @@
*/
sp<FilterClient> openSharedFilter(const string& filterToken, sp<FilterClientCallback> cb);
+ /**
+ * Enable or Disable Low Noise Amplifier (LNA).
+ */
+ Result setLna(bool bEnable);
+
private:
/**
* An AIDL Tuner Service Singleton assigned at the first time the Tuner Client
diff --git a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
index c87bac6..313e164 100644
--- a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/activity_confirmation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/dialog_background"
@@ -23,6 +24,8 @@
android:padding="18dp"
android:layout_gravity="center">
+ <!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
+
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
@@ -30,7 +33,6 @@
android:gravity="center"
android:paddingHorizontal="12dp"
style="@*android:style/TextAppearance.Widget.Toolbar.Title"/>
- <!-- style="@*android:style/TextAppearance.Widget.Toolbar.Title" -->
<TextView
android:id="@+id/summary"
@@ -61,8 +63,10 @@
android:orientation="horizontal"
android:gravity="end">
+ <!-- Do NOT change the IDs of the buttons: they are referenced in CTS tests. -->
+
<Button
- android:id="@+id/button_cancel"
+ android:id="@+id/btn_negative"
style="@android:style/Widget.Material.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -70,7 +74,7 @@
android:textColor="?android:attr/textColorSecondary" />
<Button
- android:id="@+id/button_allow"
+ android:id="@+id/btn_positive"
style="@android:style/Widget.Material.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/packages/CompanionDeviceManager/res/layout/list_item_device.xml b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
new file mode 100644
index 0000000..d79aea6
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/list_item_device"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:padding="12dp">
+
+ <!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginRight="12dp"/>
+
+ <TextView
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index aec8f89..00a5210 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Laat <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toe om jou <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> te bestuur"</string>
<string name="profile_name_watch" msgid="576290739483672360">"horlosie"</string>
<string name="chooser_title" msgid="2262294130493605839">"Kies \'n <xliff:g id="PROFILE_NAME">%1$s</xliff:g> om deur <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> bestuur te word"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sal interaksie met jou kennisgewings mag hê en toegang kry tot jou Foon-, SMS-, Kontakte- en Kalender-toestemmings."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sal interaksie met jou kennisgewings mag hê en toegang kry tot jou Foon-, SMS-, Kontakte- en Kalender-toestemmings."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Laat <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toe om programme te stroom?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> afstandtoegang tot programme wat op <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> geïnstalleer is wanneer hierdie foon aan die internet gekoppel is."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> afstandtoegang tot programme wat op <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> geïnstalleer is wanneer hierdie tablet aan die internet gekoppel is."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> afstandtoegang tot programme wat op <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> geïnstalleer is wanneer hierdie toestel aan die internet gekoppel is."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"toestel"</string>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index 2359124..2254e1f 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> የእርስዎን <xliff:g id="DEVICE_NAME">%2$s</xliff:g> - <strong></strong> እንዲያስተዳደር ይፍቀዱ"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ሰዓት"</string>
<string name="chooser_title" msgid="2262294130493605839">"በ<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> የሚተዳደር <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ይምረጡ"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ እውቂያዎች እና የቀን መቁጠሪያ ፈቃዶች እንዲደርስ ይፈቀድለታል።"</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ እውቂያዎች እና የቀን መቁጠሪያ ፈቃዶች እንዲደርስ ይፈቀድለታል።"</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> መተግበሪያዎችን እንዲለቅቅ ይፈቀድለት?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ሲገናኙ በዚህ ስልክ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ሲገናኙ በዚህ ጡባዊ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ሲገናኙ በዚህ መሳሪያ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"መሣሪያ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index 5fc3a4f..5944dba3 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"السماح للتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بإدارة <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ساعة"</string>
<string name="chooser_title" msgid="2262294130493605839">"اختَر <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ليديره تطبيق <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"سيتم السماح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والتقويم."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"سيتم السماح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والتقويم."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"هل تريد السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ببث التطبيقات؟"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بمنح الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الهاتف عندما يكون متصلاً بالإنترنت."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بمنح <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الجهاز اللوحي عندما يكون متصلاً بالإنترنت."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بمنح <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الجهاز عندما يكون متصلاً بالإنترنت."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"جهاز"</string>
diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index 743d725..e58aed7 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক আপোনাৰ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> পৰিচালনা কৰিবলৈ দিয়ক"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ঘড়ী"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>এ পৰিচালনা কৰিব লগা এটা <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বাছনি কৰক"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক আপোনাৰ জাননী ব্যৱহাৰ কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক আৰু কেলেণ্ডাৰৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক আপোনাৰ জাননী ব্যৱহাৰ কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক আৰু কেলেণ্ডাৰৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক এপ্লিকেশ্বন ষ্ট্ৰীম কৰিবলৈ অনুমতি দিবনে?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"সংযোগ কৰিলে <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক এই ফ’নটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"সংযোগ কৰিলে <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক এই টেবলেটটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"সংযোগ কৰিলে <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক এই ডিভাইচটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইচ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index ca32052..7577776 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazınızı idarə etməsinə icazə verin"</string>
<string name="profile_name_watch" msgid="576290739483672360">"izləyin"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> tərəfindən idarə ediləcək <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar və Təqvimə giriş əldə edəcək."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar və Təqvimə giriş əldə edəcək."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinin tətbiqlərdə yayım etməsinə icazə verilsin?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazının qoşulduqda bu telefonda quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazının qoşulduqda bu planşetdə quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazının qoşulduqda bu cihazda quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index d919e67..8a63b11 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Dozvolite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja uređajem <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
<string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS poruke, kontakte i kalendar."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS poruke, kontakte i kalendar."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Želite da dozvolite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da strimuje aplikacije?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Dozvolite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da daljinski pristupa aplikacijama instaliranim na telefonu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> kada je povezan."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dozvolite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da daljinski pristupa aplikacijama instaliranim na tabletu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> kada je povezan."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dozvolite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da daljinski pristupa aplikacijama instaliranim na uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> kada je povezan."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index 919d729..bf4fe3e 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Дазвольце праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> кіраваць прыладай <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"гадзіннік"</string>
<string name="chooser_title" msgid="2262294130493605839">"Выберыце прыладу (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), якой будзе кіраваць праграма <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> атрымае доступ да вашых апавяшчэнняў, тэлефона, SMS, кантактаў і календара."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> атрымае доступ да вашых апавяшчэнняў, тэлефона, SMS, кантактаў і календара."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Дазволіць праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> перадаваць праграмы плынню?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дазвольце праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> атрымліваць аддалены доступ да праграм, усталяваных на тэлефоне <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> (калі тэлефон падключаны)."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дазвольце праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> атрымліваць аддалены доступ да праграм, усталяваных на планшэце <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> (калі планшэт падключаны)."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дазвольце праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> атрымліваць аддалены доступ да праграм, усталяваных на прыладзе <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> (калі прылада падключана)."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"прылада"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml
index 1e2aa4e..cc67b13 100644
--- a/packages/CompanionDeviceManager/res/values-bg/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Разрешаване на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да управлява устройството ви <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
<string name="chooser_title" msgid="2262294130493605839">"Изберете устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), което да се управлява от <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ще получи разрешение да взаимодейства с известията ви и да осъществява достъп до разрешенията за телефона, SMS съобщенията, контактите и календара."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ще получи разрешение да взаимодейства с известията ви и да осъществява достъп до разрешенията за телефона, SMS съобщенията, контактите и календара."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Разрешавате ли на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да предава поточно приложения?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Разрешете на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да предоставя на <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> отдалечен достъп до приложенията, инсталирани на този телефон, когато има установена връзка."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Разрешете на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да предоставя на <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> отдалечен достъп до приложенията, инсталирани на този таблет, когато има установена връзка."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Разрешете на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да предоставя на <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> отдалечен достъп до приложенията, инсталирани на това устройство, когато има установена връзка."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index 3b537b6..08ffab0 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"আপনার <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ম্যানেজ করার জন্য <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> -কে অনুমতি দিন"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ঘড়ি"</string>
<string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> বেছে নিন যেটি <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ম্যানেজ করবে"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> আপনার বিজ্ঞপ্তির সাথে ইন্টার্যাক্ট করতে পারবে, তার সাথে আপনার ফোন, এমএসএস, পরিচিতি এবং ক্যালেন্ডারের অনুমতিও অ্যাক্সেস করতে পারবে।"</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> আপনার বিজ্ঞপ্তির সাথে ইন্টার্যাক্ট করতে পারবে, তার সাথে আপনার ফোন, এমএসএস, পরিচিতি এবং ক্যালেন্ডারের অনুমতিও অ্যাক্সেস করতে পারবে।"</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"অ্যাপ্লিকেশন স্ট্রিম করার জন্য <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> কে অনুমতি দেবেন?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> কে <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ফোনে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> কে <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ট্যাবলেটে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> কে <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ডিভাইসে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইস"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index b010626..8b0daaa 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Dozvolite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja uređajem <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
<string name="chooser_title" msgid="2262294130493605839">"Odaberite uređaj <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> će se dozvoliti da ostvari interakciju s vašim obavještenjima i da pristupi odobrenjima za Telefon, SMS, Kontakte i Kalendar."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> će se dozvoliti da ostvari interakciju s vašim obavještenjima i da pristupi odobrenjima za Telefon, SMS, Kontakte i Kalendar."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Dozvoliti da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prenosi aplikacije?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> omogući daljinski pristup uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> radi pristupanja aplikacijama instaliranim na ovom telefonu kada je povezan s mrežom."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> omogući daljinski pristup uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> radi pristupanja aplikacijama instaliranim na ovom tabletu kada je povezan s mrežom."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> omogući daljinski pristup uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> radi pristupanja aplikacijama instaliranim na njemu kada je povezan s mrežom."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index efd801e..c98feb3 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gestioni el teu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"rellotge"</string>
<string name="chooser_title" msgid="2262294130493605839">"Tria un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> perquè el gestioni <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes i al calendari."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes i al calendari."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Vols permetre que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> reprodueixi aplicacions en continu?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> proporcioni accés remot a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> per accedir a les aplicacions instal·lades en aquest telèfon quan estigui connectat."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> proporcioni accés remot a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> per accedir a les aplicacions instal·lades en aquesta tauleta quan estigui connectada."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> proporcioni accés remot a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> per accedir a les aplicacions instal·lades en aquest dispositiu quan estigui connectat."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositiu"</string>
diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml
index bd57213..c758b6e 100644
--- a/packages/CompanionDeviceManager/res/values-cs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> spravovat <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
<string name="chooser_title" msgid="2262294130493605839">"Vyberte zařízení <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, které chcete spravovat pomocí aplikace <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> bude moci interagovat s vašimi oznámeními a získá přístup k telefonu, SMS, kontaktům a kalendáři."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> bude moci interagovat s vašimi oznámeními a získá přístup k telefonu, SMS, kontaktům a kalendáři."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> streamovat aplikace?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> poskytovat <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> vzdálený přístup k aplikacím nainstalovaným v tomto telefonu, když je připojen."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> poskytovat <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> vzdálený přístup k aplikacím nainstalovaným v tomto tabletu, když je připojen."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> poskytovat <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> vzdálený přístup k aplikacím nainstalovaným v tomto zařízení, když je připojeno."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"zařízení"</string>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index 7428453..b026bb1 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Tillad at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> kan administrere: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ur"</string>
<string name="chooser_title" msgid="2262294130493605839">"Vælg den enhed (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), som skal administreres af <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tilladelse til at interagere med dine notifikationer og adgang til dine tilladelser for Opkald, Sms, Kontakter og Kalender."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tilladelse til at interagere med dine notifikationer og adgang til dine tilladelser for Opkald, Sms, Kontakter og Kalender."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Vil du give <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilladelse til at streame apps?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Giver <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilladelse til at fjernstyre apps, som er installeret på <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, når telefonen har forbindelse til internettet."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Giver <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilladelse til at fjernstyre apps, som er installeret på <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, når tabletten har forbindelse til internettet."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Giver <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilladelse til at fjernstyre apps, som er installeret på <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, når enheden har forbindelse til internettet."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"enhed"</string>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index 4c43140..345b971 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> erlauben, dein Gerät <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> zu verwalten"</string>
<string name="profile_name_watch" msgid="576290739483672360">"Smartwatch"</string>
<string name="chooser_title" msgid="2262294130493605839">"Gerät (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) auswählen, das von <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> verwaltet werden soll"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“ und „Kalender“ zugreifen."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“ und „Kalender“ zugreifen."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Möchtest du <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> erlauben, Apps zu streamen?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Besteht eine Verbindung, darf <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> Remotezugriff auf die auf diesem Smartphone installierten Apps geben."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Besteht eine Verbindung, darf <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> Remotezugriff auf die auf diesem Tablet installierten Apps geben."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Besteht eine Verbindung, darf <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> Remotezugriff auf die auf diesem Gerät installierten Apps geben."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index 07a4fda..64d500e 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Επιτρέψτε στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να διαχειρίζεται τη συσκευή <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ρολόι"</string>
<string name="chooser_title" msgid="2262294130493605839">"Επιλέξτε ένα προφίλ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> για διαχείριση από την εφαρμογή <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> θα επιτρέπεται να αλληλεπιδρά με τις ειδοποιήσεις σας και να έχει πρόσβαση στις άδειες Τηλεφώνου, SMS, Επαφών και Ημερολογίου."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> θα επιτρέπεται να αλληλεπιδρά με τις ειδοποιήσεις σας και να έχει πρόσβαση στις άδειες Τηλεφώνου, SMS, Επαφών και Ημερολογίου."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Να επιτρέπεται στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> η ροή εφαρμογών;"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Επιτρέψτε στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να παρέχει απομακρυσμένη πρόσβαση στη συσκευή <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτό το τηλέφωνο."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Επιτρέψτε στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να παρέχει απομακρυσμένη πρόσβαση στη συσκευή <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτό το tablet."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Επιτρέψτε στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να παρέχει απομακρυσμένη πρόσβαση στη συσκευή <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτήν τη συσκευή."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"συσκευή"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
index 9bbc1b8..90e33a5 100644
--- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> administre tu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
<string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para que <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> lo administre"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos y Calendario."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos y Calendario."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"¿Deseas permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> transmita aplicaciones?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> proporcione a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acceso remoto a las aplicaciones instaladas en este teléfono cuando esté conectado."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> proporcione <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acceso remoto a las aplicaciones instaladas en esta tablet cuando esté conectada."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> proporcione a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acceso remoto a las aplicaciones instaladas en este dispositivo cuando esté conectado."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index daece56..78ac63f 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gestione tu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
<string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para gestionarlo con <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos y calendario."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos y calendario."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"¿Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> inicie aplicaciones?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda de forma remota a las aplicaciones instaladas en este teléfono cuando <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> esté conectado a Internet."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda de forma remota a las aplicaciones instaladas en este tablet cuando <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> esté conectado a Internet."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda de forma remota a las aplicaciones instaladas en este dispositivo cuando <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> esté conectado a Internet."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index ffaa0c0..165dc97 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Lubage rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> hallata teie seadet <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"käekell"</string>
<string name="chooser_title" msgid="2262294130493605839">"Valige seade <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, mida haldab rakendus <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saab kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide ja kalendri lubadele."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saab kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide ja kalendri lubadele."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Kas lubada rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> rakendusi voogesituse kaudu üle kanda?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> lubatakse seadmele <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse telefoni installitud rakendustele."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> lubatakse seadmele <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse tahvelarvutisse installitud rakendustele."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> lubatakse seadmele <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse seadmesse installitud rakendustele."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"seade"</string>
diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml
index 5bf6677..377e0c3 100644
--- a/packages/CompanionDeviceManager/res/values-eu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Eman <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> kudeatzeko baimena <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari"</string>
<string name="profile_name_watch" msgid="576290739483672360">"erlojua"</string>
<string name="chooser_title" msgid="2262294130493605839">"Aukeratu <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> aplikazioak kudeatu beharreko <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"Jakinarazpenekin interakzioan aritzeko eta telefonoa, SMSak, kontaktuak eta egutegia erabiltzeko baimena izango du <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Jakinarazpenekin interakzioan aritzeko eta telefonoa, SMSak, kontaktuak eta egutegia erabiltzeko baimena izango du <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Aplikazioak igortzeko baimena eman nahi diozu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Utzi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> urrunetik atzitzen, telefonoa konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Utzi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> urrunetik atzitzen, tableta konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Utzi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> urrunetik atzitzen, gailua konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index 1ede28c..d9053fd 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"مجاز کردن <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> برای مدیریت کردن <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ساعت"</string>
<string name="chooser_title" msgid="2262294130493605839">"انتخاب <xliff:g id="PROFILE_NAME">%1$s</xliff:g> برای مدیریت کردن با <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> میتواند با اعلانهای شما تعامل داشته باشد و به اجازههای «تلفن»، «پیامک»، «مخاطبین»، و «تقویم» دسترسی پیدا کند."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> میتواند با اعلانهای شما تعامل داشته باشد و به اجازههای «تلفن»، «پیامک»، «مخاطبین»، و «تقویم» دسترسی پیدا کند."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه میدهید برنامهها را جاریسازی کند؟"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه میدهد برای <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> دسترسی ازراهدور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامههای نصبشده در این تلفن دسترسی داشته باشد."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه میدهد برای <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> دسترسی ازراهدور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامههای نصبشده در این رایانه لوحی دسترسی داشته باشد."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه میدهد برای <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> دسترسی ازراهدور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامههای نصبشده در این دستگاه دسترسی داشته باشد."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"دستگاه"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index ac948df..e76f89d 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Salli, että <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> voi hallinnoida tätä laitettasi: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"kello"</string>
<string name="chooser_title" msgid="2262294130493605839">"Valitse <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, jota <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> hallinnoi"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeesi, tekstiviesteihisi, kontakteihisi ja kalenteriisi."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeesi, tekstiviesteihisi, kontakteihisi ja kalenteriisi."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Saako <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> striimata sovelluksia?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Salli, että <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> voi saada sovellukselta (<strong><xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle puhelimelle asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Salli, että <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> voi saada sovellukselta (<strong><xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle tabletille asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Salli, että <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> voi saada sovellukselta (<strong><xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle laitteelle asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"laite"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index 19f97f0..f6a4855 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à gérer votre <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
<string name="chooser_title" msgid="2262294130493605839">"Choisissez un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré par <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations pour votre téléphone, vos messages texte, vos contacts et votre agenda."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations pour votre téléphone, vos messages texte, vos contacts et votre agenda."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Permettre à l\'application <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> de diffuser des applications?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permettez à l\'application <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> de donner à l\'appareil <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> un accès à distance aux applications installées sur ce téléphone lorsqu\'il est connecté."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permettez à l\'application <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> de donner à l\'appareil <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> un accès à distance aux applications installées sur cette tablette lorsqu\'elle est connectée."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permettez à l\'application <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> de donner à l\'appareil <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> un accès à distance aux applications installées sur cet appareil lorsqu\'il est connecté."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index 8a7ae1a..a214b89 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à gérer votre <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
<string name="chooser_title" msgid="2262294130493605839">"Sélectionner le/la <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré(e) par <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder au téléphone, aux SMS, aux contacts et à l\'agenda."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder au téléphone, aux SMS, aux contacts et à l\'agenda."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à diffuser des applis en streaming ?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à distance aux applis installées sur <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> quand ce téléphone est connecté à Internet."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à distance aux applis installées sur <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> quand cette tablette est connectée à Internet."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à distance aux applis installées sur <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> quand cet appareil est connecté à Internet."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index 052c207..c179378 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> xestione o teu dispositivo (<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>)"</string>
<string name="profile_name_watch" msgid="576290739483672360">"reloxo"</string>
<string name="chooser_title" msgid="2262294130493605839">"Escolle un perfil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) para que o xestione a aplicación <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das mensaxes, dos contactos e do calendario."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das mensaxes, dos contactos e do calendario."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Queres permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> emita aplicacións noutros dispositivos?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> lle outorgue a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acceso remoto a aplicacións instaladas neste teléfono cando teña conexión a Internet."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> lle outorgue a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acceso remoto a aplicacións instaladas nesta tableta cando teña conexión a Internet."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> lle outorgue a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acceso remoto a aplicacións instaladas neste dispositivo cando teña conexión a Internet."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index 279de16..ff9a89e 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"તમારા <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ને મેનેજ કરવા માટે <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને મંજૂર કરો"</string>
<string name="profile_name_watch" msgid="576290739483672360">"સ્માર્ટવૉચ"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> દ્વારા મેનેજ કરવા માટે કોઈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> પસંદ કરો"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની તેમજ તમારો ફોન, SMS, સંપર્કો તેમજ કૅલેન્ડરની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની તેમજ તમારો ફોન, SMS, સંપર્કો તેમજ કૅલેન્ડરની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"શું </strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને ઍપ્લિકેશનો સ્ટ્રીમ કરવાની મંજૂરી આપીએ?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ફોન પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ને પ્રદાન કરવા દો."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ટૅબ્લેટ પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ને પ્રદાન કરવા દો."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ડિવાઇસ પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ને પ્રદાન કરવા દો."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"ડિવાઇસ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index 7704829..557e1f8 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को, अपनी <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> मैनेज करने की अनुमति दें"</string>
<string name="profile_name_watch" msgid="576290739483672360">"स्मार्टवॉच"</string>
<string name="chooser_title" msgid="2262294130493605839">"कोई <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चुनें, ताकि उसे <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> की मदद से प्रबंधित किया जा सके"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपकी सूचनाओं पर कार्रवाई कर पाएगा. साथ ही, यह आपके फ़ोन, एसएमएस, संपर्कों, और कैलेंडर की अनुमतियों को भी ऐक्सेस कर पाएगा."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपकी सूचनाओं पर कार्रवाई कर पाएगा. साथ ही, यह आपके फ़ोन, एसएमएस, संपर्कों, और कैलेंडर की अनुमतियों को भी ऐक्सेस कर पाएगा."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को ऐप्लिकेशन स्ट्रीम करने की अनुमति देनी है?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"कनेक्ट होने पर, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> के रिमोट ऐक्सेस की अनुमति दें, ताकि इस फ़ोन पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"कनेक्ट होने पर, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> के रिमोट ऐक्सेस की अनुमति दें, ताकि इस टैबलेट पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"कनेक्ट होने पर, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> के रिमोट ऐक्सेस की अनुमति दें, ताकि इस डिवाइस पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index e7db2ba..453a4dd 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Dopustite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja vašim <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"satom"</string>
<string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte i kalendar."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte i kalendar."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Dopustiti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pokretanje streama aplikacija?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Dopustite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da telefonu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> omogući udaljeni pristup aplikacijama koje su instalirane na tom telefonu kada su povezani."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dopustite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da tabletu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> omogući udaljeni pristup aplikacijama koje su instalirane na tom tabletu kada su povezani."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dopustite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> omogući udaljeni pristup aplikacijama koje su instalirane na tom uređaju kada su povezani."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index 56f02a5..dacc4e4 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"A(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> engedélyezése a(z) <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> kezelésére"</string>
<string name="profile_name_watch" msgid="576290739483672360">"óra"</string>
<string name="chooser_title" msgid="2262294130493605839">"A(z) <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> alkalmazással kezelni kívánt <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiválasztása"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet a telefonra, az SMS-ekre, a névjegyekre és a naptárra vonatkozó engedélyekhez."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet a telefonra, az SMS-ekre, a névjegyekre és a naptárra vonatkozó engedélyekhez."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Engedélyezi a(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> alkalmazásnak appok streamelését?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Engedélyezheti a(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> alkalmazásnak, hogy a(z) <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> eszköz számára távoli hozzáférést biztosítson a telefonra telepített alkalmazásokhoz, amikor a telefon csatlakoztatva van."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Engedélyezheti a(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> alkalmazásnak, hogy a(z) <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> eszköz számára távoli hozzáférést biztosítson a táblagépre telepített alkalmazásokhoz, amikor a táblagép csatlakoztatva van."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Engedélyezheti a(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> alkalmazásnak, hogy a(z) <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> eszköz számára távoli hozzáférést biztosítson az eszközre telepített alkalmazásokhoz, amikor az eszköz csatlakoztatva van."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"eszköz"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index cf22fbc..9b79f4b 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Թույլատրեք <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին կառավարել ձեր <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> սարքը"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ժամացույց"</string>
<string name="chooser_title" msgid="2262294130493605839">"Ընտրեք <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ը, որը պետք է կառավարվի <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> հավելվածի կողմից"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ» և «Օրացույց» ծառայությունների թույլտվությունները։"</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ» և «Օրացույց» ծառայությունների թույլտվությունները։"</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Թույլատրե՞լ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին բացել հավելվածներ"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Թույլ տվեք, որ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածը կապի հաստատման դեպքում <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-ին տրամադրի այս հեռախոսում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Թույլ տվեք, որ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածը կապի հաստատման դեպքում <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-ին տրամադրի այս պլանշետում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Թույլ տվեք, որ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածը ինտերնետ կապի հաստատման դեպքում <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-ին տրամադրի այս սարքում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"սարք"</string>
diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index 41f1d09..684167e 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengelola <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string>
<string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk dikelola oleh <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Telepon, SMS, Kontak, dan Kalender."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Telepon, SMS, Kontak, dan Kalender."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> men-streaming aplikasi?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> memberikan akses jarak jauh ke <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> guna mengakses aplikasi yang diinstal di ponsel ini saat terhubung."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> memberikan akses jarak jauh ke <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> guna mengakses aplikasi yang diinstal di tablet ini saat terhubung."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> memberikan akses jarak jauh ke <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> guna mengakses aplikasi yang diinstal di perangkat ini saat terhubung."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index 5376912..cdfc47a 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Veita <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> stjórn á: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"úr"</string>
<string name="chooser_title" msgid="2262294130493605839">"Velja <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sem <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> á að stjórna"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> fær aðgang að tilkynningum og heimildum síma, SMS, tengiliða og dagatals."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> fær aðgang að tilkynningum og heimildum síma, SMS, tengiliða og dagatals."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Leyfa <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> að streyma forritum?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Leyfa <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> að veita <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> fjaraðgang að forritum sem eru sett upp í þessum síma þegar tenging er á."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Leyfa <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> að veita <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> fjaraðgang að forritum sem eru sett upp í þessari spjaldtölvu þegar tenging er á."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Leyfa <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> að veita <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> fjaraðgang að forritum sem eru sett upp í þessu tæki þegar tenging er á."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"tæki"</string>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index af9e8ca..fc7100a 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Consenti all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di gestire <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"orologio"</string>
<string name="chooser_title" msgid="2262294130493605839">"Scegli un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> che sia gestito da <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti e Calendario."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti e Calendario."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Vuoi consentire all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di riprodurre applicazioni in streaming?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Consenti all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di fornire l\'accesso remoto a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> per accedere alle applicazioni installate su questo telefono quando è connesso."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Consenti all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di fornire l\'accesso remoto a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> per accedere alle applicazioni installate su questo tablet quando è connesso."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Consenti all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di fornire l\'accesso remoto a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> per accedere alle applicazioni installate su questo dispositivo quando è connesso."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index 68ca9d9..295df783 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"אישור לאפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> לנהל את <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"שעון"</string>
<string name="chooser_title" msgid="2262294130493605839">"בחירת <xliff:g id="PROFILE_NAME">%1$s</xliff:g> לניהול באמצעות <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS לאנשי הקשר וליומן."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS לאנשי הקשר וליומן."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"לאפשר לאפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> לשדר אפליקציות?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"האפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> יכולה לספק ל-<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> גישה מרחוק כדי לגשת לאפליקציות שמותקנות בטלפון הזה כשיש חיבור."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"האפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> יכולה לספק ל-<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> גישה מרחוק כדי לגשת לאפליקציות שמותקנות בטאבלט הזה כשיש חיבור."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"האפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> יכולה לספק למכשיר <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> גישה מרחוק כדי לגשת לאפליקציות שמותקנות במכשיר הזה כשיש חיבור."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"מכשיר"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml
index c10a1e1..a9438be 100644
--- a/packages/CompanionDeviceManager/res/values-ja/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> の管理を許可する"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ウォッチ"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> の管理対象となる<xliff:g id="PROFILE_NAME">%1$s</xliff:g>の選択"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> は通知を使用でき、電話、SMS、連絡先、カレンダーの権限にもアクセスできるようになります。"</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> は通知を使用でき、電話、SMS、連絡先、カレンダーの権限にもアクセスできるようになります。"</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> にアプリのストリーミングを許可しますか?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"インターネット接続時に <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> がスマートフォン内にインストールされているアプリにリモートでアクセスすることを <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に許可します。"</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"インターネット接続時に <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> がタブレット内にインストールされているアプリにリモートでアクセスすることを <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に許可します。"</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"インターネット接続時に <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> がデバイス内にインストールされているアプリにリモートでアクセスすることを <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に許可します。"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"デバイス"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index 6372481..8354f4a 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"ნება დართეთ <strong><xliff:g id="APP_NAME">%1$s</xliff:g>-ს</strong>, რომ მართოს თქვენი <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"საათი"</string>
<string name="chooser_title" msgid="2262294130493605839">"აირჩიეთ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, რომელიც უნდა მართოს <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>-მა"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენი ტელეფონის, SMS-ების, კონტაქტებისა და კალენდრის ნებართვებზე წვდომას."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენი ტელეფონის, SMS-ების, კონტაქტებისა და კალენდრის ნებართვებზე წვდომას."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"გსურთ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-ს მისცეთ აპების სტრიმინგის საშუალება?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"მიეცით <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-ს საშუალება, <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-ისთვის დაუშვას დისტანციური წვდომა ამ ტელეფონზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"მიეცით <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-ს საშუალება, <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-ისთვის დაუშვას დისტანციური წვდომა ამ ტაბლეტზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"მიეცით <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-ს საშუალება, <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-ისთვის დაუშვას დისტანციური წვდომა ამ მოწყობილობაზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"მოწყობილობა"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index 6ac9c04..722b570 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> құрылғысын басқаруға рұқсат беру"</string>
<string name="profile_name_watch" msgid="576290739483672360">"сағат"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> арқылы басқарылатын <xliff:g id="PROFILE_NAME">%1$s</xliff:g> құрылғысын таңдаңыз"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы хабарландыруларды, телефонды, SMS хабардарын, контактілерді және күнтізбе рұқсаттарын пайдалана алады."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы хабарландыруларды, телефонды, SMS хабардарын, контактілерді және күнтізбе рұқсаттарын пайдалана алады."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына қолданбаларды трансляциялауға рұқсат етілсін бе?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> желіге қосылған кезде, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына осы телефонға орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> желіге қосылған кезде, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына осы планшетке орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> желіге қосылған кезде, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына осы құрылғыға орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"құрылғы"</string>
diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml
index db2634f..d47d6c4 100644
--- a/packages/CompanionDeviceManager/res/values-km/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-km/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> គ្រប់គ្រង <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> របស់អ្នក"</string>
<string name="profile_name_watch" msgid="576290739483672360">"នាឡិកា"</string>
<string name="chooser_title" msgid="2262294130493605839">"ជ្រើសរើស <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ដើម្បីឱ្យស្ថិតក្រោមការគ្រប់គ្រងរបស់ <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យធ្វើអន្តរកម្មជាមួយការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាតប្រតិទិន, ទូរសព្ទ, SMS និងទំនាក់ទំនងរបស់អ្នក។"</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យធ្វើអន្តរកម្មជាមួយការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាតប្រតិទិន, ទូរសព្ទ, SMS និងទំនាក់ទំនងរបស់អ្នក។"</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ផ្សាយកម្មវិធីឬ?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើទូរសព្ទនេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើថេប្លេតនេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើឧបករណ៍នេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"ឧបករណ៍"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index e6413da..ba9f8ff 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"ನಿಮ್ಮ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ಅನ್ನು ನಿರ್ವಹಿಸಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಅನ್ನು ಅನುಮತಿಸಿ"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ವೀಕ್ಷಿಸಿ"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ಮೂಲಕ ನಿರ್ವಹಿಸಬೇಕಾದ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು ಮತ್ತು Calendar ಅನುಮತಿಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು ಮತ್ತು Calendar ಅನುಮತಿಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"ಆ್ಯಪ್ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಿ?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಫೋನ್ನಲ್ಲಿ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಿ."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಟ್ಯಾಬ್ಲೆಟ್ನಲ್ಲಿ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಿ."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಸಾಧನದಲ್ಲಿ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಿ."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"ಸಾಧನ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 02459d5..8faab71 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> 기기를 관리하도록 허용"</string>
<string name="profile_name_watch" msgid="576290739483672360">"시계"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>에서 관리할 <xliff:g id="PROFILE_NAME">%1$s</xliff:g>을(를) 선택"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 알림과 상호작용하고 전화, SMS, 연락처, 캘린더 권한에 액세스할 수 있게 됩니다."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 알림과 상호작용하고 전화, SMS, 연락처, 캘린더 권한에 액세스할 수 있게 됩니다."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 애플리케이션을 스트리밍하도록 허용하시겠습니까?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"연결 시 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>에 이 휴대전화에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"연결 시 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>에 이 태블릿에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"연결 시 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>에 이 기기에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"기기"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index ea4230a..eec1775 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> түзмөгүңүздү башкарууга уруксат бериңиз"</string>
<string name="profile_name_watch" msgid="576290739483672360">"саат"</string>
<string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> тарабынан башкарылсын"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> билдирмелериңизди көрүп, телефонуңуздун, SMS билдирүүлөрүңүздүн, байланыштарыңыздын жана жылнаамаңыздын уруксаттарын пайдалана алат."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> билдирмелериңизди көрүп, телефонуңуздун, SMS билдирүүлөрүңүздүн, байланыштарыңыздын жана жылнаамаңыздын уруксаттарын пайдалана алат."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна колдонмолорду алып ойнотууга уруксат бересизби?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна Интернетке туташкан <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> телефонундагы колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна Интернетке туташкан <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> планшетиндеги колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна Интернетке туташкан <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> түзмөгүндөгү колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"түзмөк"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index b6c6289..ed24422 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"ອະນຸຍາດໃຫ້ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ຈັດການ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ຂອງທ່ານໄດ້"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ໂມງ"</string>
<string name="chooser_title" msgid="2262294130493605839">"ເລືອກ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ເພື່ອໃຫ້ຖືກຈັດການໂດຍ <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ເຂົ້າເຖິງການອະນຸຍາດໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່ ແລະ ປະຕິທິນຂອງທ່ານໄດ້."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ເຂົ້າເຖິງການອະນຸຍາດໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່ ແລະ ປະຕິທິນຂອງທ່ານໄດ້."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"ອະນຸຍາດໃຫ້ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ສະຕຣີມແອັບພລິເຄຊັນໄດ້ບໍ?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ໃຫ້ສິດ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ເພື່ອເຂົ້າເຖິງ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ໂທລະສັບນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ໃຫ້ສິດ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ເພື່ອເຂົ້າເຖິງ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ແທັບເລັດນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ໃຫ້ສິດ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ເພື່ອເຂົ້າເຖິງ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ອຸປະກອນນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"ອຸປະກອນ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index e5ff480..8472d79 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Leisti <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tvarkyti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"laikrodį"</string>
<string name="chooser_title" msgid="2262294130493605839">"Jūsų <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, kurį valdys <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> (pasirinkite)"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ galės sąveikauti su pranešimų funkcija ir pasiekti telefoną, SMS, kontaktus ir kalendorių."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ galės sąveikauti su pranešimų funkcija ir pasiekti telefoną, SMS, kontaktus ir kalendorių."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Leisti <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> perduoti srautu programas?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Leiskite <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prisijungus suteikti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> nuotolinę prieigą prie šiame telefone įdiegtų programų."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Leiskite <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prisijungus suteikti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> nuotolinę prieigą prie šiame planšetiniame kompiuteryje įdiegtų programų."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Leiskite <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prisijungus suteikti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> nuotolinę prieigą prie šiame įrenginyje įdiegtų programų."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"įrenginys"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index d521240..8b27a08 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Atļauja lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pārvaldīt ierīci <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"pulkstenis"</string>
<string name="chooser_title" msgid="2262294130493605839">"Profila (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) izvēle, ko pārvaldīt lietotnē <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"Lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un piekļūt šādām atļaujām: Tālrunis, Īsziņas, Kontaktpersonas un Kalendārs."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un piekļūt šādām atļaujām: Tālrunis, Īsziņas, Kontaktpersonas un Kalendārs."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Vai atļaujat lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> straumēt lietojumprogrammas?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> nodrošināt attālu piekļuvi tālrunim <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, lai piekļūtu šajā tālrunī instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> nodrošināt attālu piekļuvi planšetdatoram <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, lai piekļūtu šajā planšetdatorā instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> nodrošināt attālu piekļuvi ierīcei <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, lai piekļūtu šajā ierīcē instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"ierīce"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index 639909a..e35a733 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"നിങ്ങളുടെ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> മാനേജ് ചെയ്യാൻ, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കുക"</string>
<string name="profile_name_watch" msgid="576290739483672360">"വാച്ച്"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ഉപയോഗിച്ച് മാനേജ് ചെയ്യുന്നതിന് ഒരു <xliff:g id="PROFILE_NAME">%1$s</xliff:g> തിരഞ്ഞെടുക്കുക"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"നിങ്ങളുടെ അറിയിപ്പുകളുമായി സംവദിക്കാനും നിങ്ങളുടെ ഫോൺ, SMS, കോൺടാക്റ്റുകൾ, കലണ്ടർ അനുമതികൾ എന്നിവ ആക്സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"നിങ്ങളുടെ അറിയിപ്പുകളുമായി സംവദിക്കാനും നിങ്ങളുടെ ഫോൺ, SMS, കോൺടാക്റ്റുകൾ, കലണ്ടർ അനുമതികൾ എന്നിവ ആക്സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"ആപ്പുകൾ സ്ട്രീം ചെയ്യാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കണോ?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"കണക്റ്റ് ചെയ്യുമ്പോൾ, ഈ ഫോണിൽ ഇൻസ്റ്റാൾ ചെയ്തിട്ടുള്ള ആപ്പുകൾ ആക്സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്സസ് <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> എന്നതിന് നൽകാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കുക."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"കണക്റ്റ് ചെയ്യുമ്പോൾ, ഈ ടാബ്ലെറ്റിൽ ഇൻസ്റ്റാൾ ചെയ്തിട്ടുള്ള ആപ്പുകൾ ആക്സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്സസ് <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> എന്നതിന് നൽകാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കുക."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"കണക്റ്റ് ചെയ്യുമ്പോൾ, ഈ ഉപകരണത്തിൽ ഇൻസ്റ്റാൾ ചെയ്തിട്ടുള്ള ആപ്പുകൾ ആക്സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്സസ് <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> എന്നതിന് നൽകാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കുക."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"ഉപകരണം"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index adbe62d..1ea1c9b 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-г удирдахын тулд <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-г зөвшөөрнө үү"</string>
<string name="profile_name_watch" msgid="576290739483672360">"цаг"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>-н удирдах<xliff:g id="PROFILE_NAME">%1$s</xliff:g>-г сонгоно уу"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д таны мэдэгдлүүдтэй харилцаж, таны Утас, SMS, Харилцагчид болон Календарийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д таны мэдэгдлүүдтэй харилцаж, таны Утас, SMS, Харилцагчид болон Календарийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д аппуудыг дамжуулахыг зөвшөөрөх үү?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-г холбогдсон үед энэ утсанд суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-г холбогдсон үед энэ таблетад суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-г холбогдсон үед энэ төхөөрөмжид суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"төхөөрөмж"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index fce0583..1936ede 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"तुमचे <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> व्यवस्थापित करण्यासाठी <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला अनुमती द्या"</string>
<string name="profile_name_watch" msgid="576290739483672360">"वॉच"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> द्वारे व्यवस्थापित करण्यासाठी <xliff:g id="PROFILE_NAME">%1$s</xliff:g> निवडा"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क आणि Calendar च्या परवानग्या अॅक्सेस करण्याची अनुमती मिळेल."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क आणि Calendar च्या परवानग्या अॅक्सेस करण्याची अनुमती मिळेल."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला अॅप्लिकेशन स्ट्रीम करण्याची अनुमती द्यायची आहे का?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"कनेक्ट केलेले असताना या फोनवरील अॅप्लिकेशन अॅक्सेस करता यावीत यासाठी <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> चा रिमोट अॅक्सेस द्या."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"कनेक्ट केलेले असताना या टॅबलेटवरील अॅप्लिकेशन अॅक्सेस करता यावीत यासाठी <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> चा रिमोट अॅक्सेस द्या."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"कनेक्ट केलेले असताना या डिव्हाइसवरील अॅप्लिकेशन अॅक्सेस करता यावीत यासाठी <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> चा रिमोट अॅक्सेस द्या."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"डिव्हाइस"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index 5c4ec78..fb69cb1 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengurus <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> anda"</string>
<string name="profile_name_watch" msgid="576290739483672360">"jam tangan"</string>
<string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk diurus oleh <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan dibenarkan berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan dan Kalendar anda."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> akan dibenarkan berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan dan Kalendar anda."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> menstrim aplikasi?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Membenarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> memberi akses jauh kepada <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> untuk mengakses aplikasi yang dipasang pada telefon ini apabila disambungkan."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Membenarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> memberi akses jauh kepada <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> untuk mengakses aplikasi yang dipasang pada tablet ini apabila disambungkan."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Membenarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> memberi akses jauh kepada <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> untuk mengakses aplikasi yang dipasang pada peranti ini apabila disambungkan."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string>
diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index f3e572e..31596a4 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"သင်၏ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ကို စီမံခန့်ခွဲရန် <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ကို ခွင့်ပြုပါ"</string>
<string name="profile_name_watch" msgid="576290739483672360">"နာရီ"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> က စီမံခန့်ခွဲရန် <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို ရွေးချယ်ပါ"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"သင်၏ ‘ဖုန်း’၊ ‘SMS စာတိုစနစ်’၊ ‘အဆက်အသွယ်များ’ နှင့် ‘ပြက္ခဒိန်’ ခွင့်ပြုချက်များကို သုံးရန်နှင့် အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%1$s</xliff:g> အား ခွင့်ပြုပါမည်။"</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"သင်၏ ‘ဖုန်း’၊ ‘SMS စာတိုစနစ်’၊ ‘အဆက်အသွယ်များ’ နှင့် ‘ပြက္ခဒိန်’ ခွင့်ပြုချက်များကို သုံးရန်နှင့် အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%1$s</xliff:g> အား ခွင့်ပြုပါမည်။"</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"အပလီကေးရှင်းများကို တိုက်ရိုက်လွှင့်ရန် <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ကိုခွင့်ပြုမလား။"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ချိတ်ဆက်ထားသည့်အခါ ဤဖုန်းတွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> အားခွင့်ပြုပါ။"</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ချိတ်ဆက်ထားသည့်အခါ ဤတက်ဘလက်တွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> အားခွင့်ပြုပါ။"</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ချိတ်ဆက်ထားသည့်အခါ ဤစက်တွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> အားခွင့်ပြုပါ။"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"စက်"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index d3eb7e5..52afcf0 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Tillat at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> administrerer <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"klokke"</string>
<string name="chooser_title" msgid="2262294130493605839">"Velg <xliff:g id="PROFILE_NAME">%1$s</xliff:g> som skal administreres av <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tillatelse til å samhandle med varslene dine og får tilgang til Telefon, SMS, kontakter og Kalender."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får tillatelse til å samhandle med varslene dine og får tilgang til Telefon, SMS, kontakter og Kalender."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Vil du gi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tillatelse til å strømme apper?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Tillat at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gir <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ekstern tilgang til apper som er installert på denne telefonen, når den er koblet til internett."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Tillat at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gir <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ekstern tilgang til apper som er installert på dette nettbrettet, når det er koblet til internett."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Tillat at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gir <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ekstern tilgang til apper som er installert på denne enheten, når den er koblet til internett."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index 9bcf69b..9b42c1e 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"आफ्नो <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> लाई <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> व्यवस्थापन गर्ने अनुमति दिनुहोस्"</string>
<string name="profile_name_watch" msgid="576290739483672360">"घडी"</string>
<string name="chooser_title" msgid="2262294130493605839">"आफूले <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> प्रयोग गरी व्यवस्थापन गर्न चाहेको <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चयन गर्नुहोस्"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट तथा पात्रोसम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> लाई तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट तथा पात्रोसम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> लाई एपहरू स्ट्रिम गर्ने अनुमति दिने हो?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>लाई <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> लाई यो फोनमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>लाई <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> लाई यो ट्याब्लेटमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> लाई <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> लाई यो डिभाइसमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"यन्त्र"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index 9ee09db..354cb93 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toestaan je <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> te beheren"</string>
<string name="profile_name_watch" msgid="576290739483672360">"horloge"</string>
<string name="chooser_title" msgid="2262294130493605839">"Een <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiezen om te beheren met <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot je rechten voor telefoon, sms, contacten en agenda."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot je rechten voor telefoon, sms, contacten en agenda."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Toestaan dat <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> apps streamt?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Toestaan dat <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> als er verbinding is <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> externe toegang geeft tot apps die zijn geïnstalleerd op deze telefoon."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Toestaan dat <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> als er verbinding is <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> externe toegang geeft tot apps die zijn geïnstalleerd op deze tablet."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Toestaan dat <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> als er verbinding is <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> externe toegang geeft tot apps die zijn geïnstalleerd op dit apparaat."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index e08ec28..b58ebd34 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"ଆପଣଙ୍କ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>କୁ ପରିଚାଳନା କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ୱାଚ୍"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ଦ୍ୱାରା ପରିଚାଳିତ ହେବା ପାଇଁ ଏକ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>କୁ ବାଛନ୍ତୁ"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କ ଫୋନ, SMS, ଯୋଗାଯୋଗ ଓ କ୍ୟାଲେଣ୍ଡର ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କ ଫୋନ, SMS, ଯୋଗାଯୋଗ ଓ କ୍ୟାଲେଣ୍ଡର ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ଆପ୍ଲିକେସନଗୁଡ଼ିକ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ ଅନୁମତି ଦେବେ କି?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ, ଏହି ଫୋନଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ, ଏହି ଟାବଲେଟଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ, ଏହି ଡିଭାଇସଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"ଡିଭାଇସ୍"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index e317a464f..f2a5c29 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ ਤੁਹਾਡੇ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ਸਮਾਰਟ-ਵਾਚ"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੇ ਜਾਣ ਲਈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ਚੁਣੋ"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕ ਅਤੇ ਕੈਲੰਡਰ ਦੀਆਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਹੋਵੇਗੀ।"</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕ ਅਤੇ ਕੈਲੰਡਰ ਦੀਆਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਹੋਵੇਗੀ।"</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"ਕੀ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong&gt ਨੂੰ ਐਪਲੀਕੇਸ਼ਨਾਂ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਫ਼ੋਨ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਟੈਬਲੈੱਟ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"ਡੀਵਾਈਸ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index 6cb7cc6..9356792 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Zezwól na zarządzanie urządzeniem <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> przez aplikację <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"zegarek"</string>
<string name="chooser_title" msgid="2262294130493605839">"Wybierz profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, którym ma zarządzać aplikacja <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących Telefonu, SMS-ów, Kontaktów i Kalendarza."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących Telefonu, SMS-ów, Kontaktów i Kalendarza."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Zezwolić aplikacji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na strumieniowanie danych z aplikacji?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Zezwól na zapewnianie przez aplikację <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> zdalnego dostępu do aplikacji zainstalowanych na telefonie <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> po połączeniu jej z tym telefonem."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Zezwól na zapewnianie przez aplikację <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> zdalnego dostępu do aplikacji zainstalowanych na tablecie <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> po połączeniu jej z tym tabletem."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Zezwól na zapewnianie przez aplikację <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> zdalnego dostępu do aplikacji zainstalowanych na urządzeniu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> po połączeniu jej z urządzeniem."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"urządzenie"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index 4306286..7d79608 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gerencie seu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
<string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça streaming de aplicativos?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> conceda ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acesso remoto aos aplicativos instalados no smartphone quando ele estiver conectado."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> conceda ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acesso remoto aos aplicativos instalados no tablet quando ele estiver conectado."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> conceda ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acesso remoto aos aplicativos instalados no dispositivo quando ele estiver conectado."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
index 8f05d49..bc30ed8 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça a gestão do seu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
<string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerido pela app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com as suas notificações e aceder às autorizações do Telefone, SMS, Contactos e Calendário."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com as suas notificações e aceder às autorizações do Telefone, SMS, Contactos e Calendário."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Permitir que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça stream de aplicações?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> forneça acesso remoto ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> para aceder a aplicações instaladas neste telemóvel quando estiver ligado."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> forneça acesso remoto ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> para aceder a aplicações instaladas neste tablet quando estiver ligado."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> forneça acesso remoto ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> para aceder a aplicações instaladas neste dispositivo quando estiver ligado."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index 4306286..7d79608 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gerencie seu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
<string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> poderá interagir com suas notificações e acessar as permissões do Telefone, de SMS, de Contatos e da Agenda."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça streaming de aplicativos?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> conceda ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acesso remoto aos aplicativos instalados no smartphone quando ele estiver conectado."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> conceda ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acesso remoto aos aplicativos instalados no tablet quando ele estiver conectado."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> conceda ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acesso remoto aos aplicativos instalados no dispositivo quando ele estiver conectado."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index 43a4de7..dd38f1f 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Permiteți ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să vă gestioneze dispozitivul <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ceas"</string>
<string name="chooser_title" msgid="2262294130493605839">"Alegeți un profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> pe care să îl gestioneze <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> va putea să interacționeze cu notificările dvs. și să vă acceseze permisiunile pentru Telefon, SMS-uri, Agendă și Calendar."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> va putea să interacționeze cu notificările dvs. și să vă acceseze permisiunile pentru Telefon, SMS-uri, Agendă și Calendar."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Lăsați <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să redea în stream aplicații?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Lăsați <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să ofere acces la distanță pentru <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ca să se poată accesa aplicațiile instalate pe acest telefon când se conectează utilizatorul."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Lăsați <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să ofere acces la distanță pentru <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ca să se poată accesa aplicațiile instalate pe această tabletă când se conectează utilizatorul."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Lăsați <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să ofere acces la distanță pentru <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ca să se poată accesa aplicațiile instalate pe acest dispozitiv când se conectează utilizatorul."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"dispozitiv"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index 6d5c0de..8e2b4d8 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Разрешите приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> управлять этим устройством: <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"часы"</string>
<string name="chooser_title" msgid="2262294130493605839">"Выберите устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), которым будет управлять приложение <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"Приложению \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" будет предоставлен доступ к уведомлениям, а также следующие разрешения: телефон, SMS, контакты и календарь."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Приложению \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" будет предоставлен доступ к уведомлениям, а также следующие разрешения: телефон, SMS, контакты и календарь."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Разрешить приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> транслировать приложения?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Разрешить приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> при наличии подключения предоставить устройству <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> удаленный доступ к приложениям, установленным на этом телефоне."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Разрешить приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> при наличии подключения предоставить устройству <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> удаленный доступ к приложениям, установленным на этом планшете."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Разрешить приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> при наличии подключения предоставить устройству <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> удаленный доступ к приложениям, установленным на этом устройстве."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index b4e28d8..489ecf9 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට ඔබගේ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> කළමනාකරණය කිරීමට ඉඩ දෙන්න"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ඔරලෝසුව"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> මගින් කළමනාකරණය කරනු ලැබීමට <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ක් තෝරන්න"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ දැනුම්දීම් සමඟ අන්තර්ක්රියා කිරීමට සහ ඔබගේ දුරකථනය, කෙටි පණිවුඩ, සම්බන්ධතා සහ දින දර්ශන අවසර වෙත ප්රවේශ වීමට ඉඩ දෙනු ඇත."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ දැනුම්දීම් සමඟ අන්තර්ක්රියා කිරීමට සහ ඔබගේ දුරකථනය, කෙටි පණිවුඩ, සම්බන්ධතා සහ දින දර්ශන අවසර වෙත ප්රවේශ වීමට ඉඩ දෙනු ඇත."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට යෙදුම් ප්රවාහ කිරීමට ඉඩ දෙන්නද?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"සම්බන්ධ වූ විට මෙම දුරකථනයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්රවේශ වීමට <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> හට දුරස්ථ ප්රවේශය ලබා දීමට ඉඩ දෙන්න."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"සම්බන්ධ වූ විට මෙම ටැබ්ලටයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්රවේශ වීමට <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> හට දුරස්ථ ප්රවේශය ලබා දීමට ඉඩ දෙන්න."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"සම්බන්ධ වූ විට මෙම උපාංගයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්රවේශ වීමට <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> හට දුරස්ථ ප්රවේශය ලබා දීමට ඉඩ දෙන්න."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"උපාංගය"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index 4f86f08..cbee372 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Povoliť aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> spravovať zariadenie <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
<string name="chooser_title" msgid="2262294130493605839">"Vyberte profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ktorý bude spravovať aplikácia <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získavať prístup k povoleniam telefónu, SMS, kontaktov a kalendára."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získavať prístup k povoleniam telefónu, SMS, kontaktov a kalendára."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Chcete aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> povoliť streamovanie aplikácií?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Povoľte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> vzdialený prístup k telefónu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Povoľte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> vzdialený prístup k tabletu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Povoľte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> vzdialený prístup k zariadeniu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index a54af21..53eb85d 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovolite upravljanje naprave <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ura"</string>
<string name="chooser_title" msgid="2262294130493605839">"Izbira naprave <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ki jo bo upravljala aplikacija <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> bosta omogočena interakcija z obvestili in dostop do dovoljenj za telefon, sporočila SMS, stike in koledar."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> bosta omogočena interakcija z obvestili in dostop do dovoljenj za telefon, sporočila SMS, stike in koledar."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Želite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovoliti pretočno predvajanje aplikacij?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovoli oddaljen dostop do telefona <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> za dostop do aplikacij, nameščenih v tem telefonu, ko je povezan v internet."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovoli oddaljen dostop do tabličnega računalnika <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> za dostop do aplikacij, nameščenih v tem tabličnem računalniku, ko je povezan v internet."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovoli oddaljen dostop do naprave <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> za dostop do aplikacij, nameščenih v tej napravi, ko je povezana v internet."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"naprava"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index d3f97df..0704b9b 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të menaxhojë pajisjen tënde <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"ora inteligjente"</string>
<string name="chooser_title" msgid="2262294130493605839">"Zgjidh një profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> që do të menaxhohet nga <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\" dhe \"Kalendarit\"."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\" dhe \"Kalendarit\"."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Të lejohet që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të transmetojë aplikacionet?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të ofrojë <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë telefon kur lidhet."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të ofrojë <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë tablet kur lidhet."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> t\'i ofrojë <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë pajisje kur lidhet."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index db8f291..eb768a2 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Дозволите апликацији <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да управља уређајем <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"сат"</string>
<string name="chooser_title" msgid="2262294130493605839">"Одаберите профил <xliff:g id="PROFILE_NAME">%1$s</xliff:g> којим ће управљати апликација <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS поруке, контакте и календар."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS поруке, контакте и календар."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Желите да дозволите апликацији <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да стримује апликације?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дозволите апликацији <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да даљински приступа апликацијама инсталираним на телефону <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> када је повезан."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дозволите апликацији <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да даљински приступа апликацијама инсталираним на таблету <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> када је повезан."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дозволите апликацији <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да даљински приступа апликацијама инсталираним на уређају <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> када је повезан."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"уређај"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index 733b2f7..24db58d 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Tillåt att <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> hanterar din <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"klocka"</string>
<string name="chooser_title" msgid="2262294130493605839">"Välj en <xliff:g id="PROFILE_NAME">%1$s</xliff:g> för hantering av <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får behörighet att interagera med dina aviseringar och komma åt behörigheterna för Telefon, Sms, Kontakter och Kalender."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> får behörighet att interagera med dina aviseringar och komma åt behörigheterna för Telefon, Sms, Kontakter och Kalender."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Vill du tillåta att <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> streamar appar?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Låt <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ge <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> fjärråtkomst till åt appar som är installerade på den här telefonen när den är ansluten."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Låt <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ge <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> fjärråtkomst till appar som är installerade på den här surfplattan när den är ansluten."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Låt <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ge <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> fjärråtkomst till appar som är installerade på den här enheten när den är ansluten."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index 02db256..d06f1c6 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Ruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> idhibiti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> yako"</string>
<string name="profile_name_watch" msgid="576290739483672360">"saa"</string>
<string name="chooser_title" msgid="2262294130493605839">"Chagua <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ili idhibitiwe na <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> itaruhusiwa kufikia arifa zako na kufikia ruhusa za Simu, SMS, Anwani na Kalenda yako."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> itaruhusiwa kufikia arifa zako na kufikia ruhusa za Simu, SMS, Anwani na Kalenda yako."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Ungependa kuruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> itiririshe programu?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Ruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> iipe <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ufikiaji wa mbali wa programu zilizosakinishwa kwenye simu hii wakati imeunganishwa."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Ruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> iipe <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ufikiaji wa mbali wa programu zilizosakinishwa kwenye kompyuta hii kibao wakati imeunganishwa."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Ruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> iipe <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ufikiaji wa mbali wa programu zilizosakinishwa kwenye kifaa hiki wakati kimeunganishwa."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"kifaa"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index 3e998c8..d58d2ae 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"உங்கள் <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ஐ நிர்வகிக்க <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதியுங்கள்"</string>
<string name="profile_name_watch" msgid="576290739483672360">"வாட்ச்"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ஆப்ஸ் நிர்வகிக்கக்கூடிய <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ஐத் தேர்ந்தெடுங்கள்"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"உங்கள் அறிவிப்புகளைப் பார்க்கவும் மொபைல், மெசேஜ், தொடர்புகள், கேலெண்டர் ஆகியவற்றை அணுகவும் <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு அனுமதி வழங்கப்படும்."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"உங்கள் அறிவிப்புகளைப் பார்க்கவும் மொபைல், மெசேஜ், தொடர்புகள், கேலெண்டர் ஆகியவற்றை அணுகவும் <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு அனுமதி வழங்கப்படும்."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"ஆப்ஸை ஸ்ட்ரீம் செய்ய <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கவா?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"இணைக்கப்பட்டிருக்கும்போது இந்த மொபைலில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> சாதனத்திற்கு வழங்க <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கும்."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"இணைக்கப்பட்டிருக்கும்போது இந்த டேப்லெட்டில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> சாதனத்திற்கு வழங்க <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கும்."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"இணைக்கப்பட்டிருக்கும்போது இந்தச் சாதனத்தில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> சாதனத்திற்கு வழங்க <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கும்."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"சாதனம்"</string>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index 8c53126..9e9fec5 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"మీ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ను మేనేజ్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను అనుమతించండి;"</string>
<string name="profile_name_watch" msgid="576290739483672360">"వాచ్"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> ద్వారా మేనేజ్ చేయబడటానికి ఒక <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ను ఎంచుకోండి"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"మీ నోటిఫికేషన్లతో ఇంటరాక్ట్ అవ్వడానికి ఇంకా మీ ఫోన్, SMS, కాంటాక్ట్లు, Calendar అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> అనుమతించబడుతుంది."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"మీ నోటిఫికేషన్లతో ఇంటరాక్ట్ అవ్వడానికి ఇంకా మీ ఫోన్, SMS, కాంటాక్ట్లు, Calendar అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> అనుమతించబడుతుంది."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"యాప్లను స్ట్రీమ్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను అనుమతించాలా?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"కనెక్ట్ అయినప్పుడు ఈ ఫోన్లో ఇన్స్టాల్ చేయబడిన యాప్లను యాక్సెస్ చేయడానికి <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> రిమోట్ యాక్సెస్ను అందించడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను అనుమతించండి."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"కనెక్ట్ అయినప్పుడు ఈ టాబ్లెట్లో ఇన్స్టాల్ చేయబడిన యాప్లను యాక్సెస్ చేయడానికి <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> రిమోట్ యాక్సెస్ను అందించడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను అనుమతించండి."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"కనెక్ట్ అయినప్పుడు ఈ పరికరంలో ఇన్స్టాల్ చేయబడిన యాప్లను యాక్సెస్ చేయడానికి <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> రిమోట్ యాక్సెస్ను అందించడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను అనుమతించండి."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"పరికరం"</string>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index 504731e..9d9c91d 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> จัดการ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ของคุณ"</string>
<string name="profile_name_watch" msgid="576290739483672360">"นาฬิกา"</string>
<string name="chooser_title" msgid="2262294130493605839">"เลือก<xliff:g id="PROFILE_NAME">%1$s</xliff:g>ที่จะให้มีการจัดการโดย <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและได้รับสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ และปฏิทิน"</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและได้รับสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ และปฏิทิน"</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> สตรีมแอปพลิเคชันใช่ไหม"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในโทรศัพท์เครื่องนี้จากระยะไกลให้แก่ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> เมื่อมีการเชื่อมต่อ"</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในแท็บเล็ตเครื่องนี้จากระยะไกลให้แก่ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> เมื่อมีการเชื่อมต่อ"</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในอุปกรณ์เครื่องนี้จากระยะไกลให้แก่ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> เมื่อมีการเชื่อมต่อ"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"อุปกรณ์"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml
index 30d5e57..436097c 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na pamahalaan ang iyong <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"relo"</string>
<string name="chooser_title" msgid="2262294130493605839">"Pumili ng <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para pamahalaan ng <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"Papayagan ang <xliff:g id="APP_NAME">%1$s</xliff:g> na makipag-ugnayan sa mga notification mo at ma-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, at Kalendaryo."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Papayagan ang <xliff:g id="APP_NAME">%1$s</xliff:g> na makipag-ugnayan sa mga notification mo at ma-access ang iyong mga pahintulot sa Telepono, SMS, Mga Contact, at Kalendaryo."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na mag-stream ng mga application?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na bigyan ang <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ng malayuang access para ma-access ang mga application na naka-install sa teleponong ito kapag nakakonekta."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na bigyan ang <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ng malayuang access para ma-access ang mga application na naka-install sa tablet na ito kapag nakakonekta."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na bigyan ang <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ng malayuang access para ma-access ang mga application na naka-install sa device na ito kapag nakakonekta."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index 1b1d71d..3a256a7 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulaması <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazınızı yönetebilsin mi?"</string>
<string name="profile_name_watch" msgid="576290739483672360">"saat"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> tarafından yönetilecek bir <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler ve Takvim izinlerinize erişmesine izin verilir."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler ve Takvim izinlerinize erişmesine izin verilir."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, uygulamalarda akış gerçekleştirmesine izin verilsin mi?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, internete bağlanan bu telefondaki yüklü uygulamalara erişebilmesi için <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> adlı cihaza uzaktan erişim izni verin."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, internete bağlanan bu tabletteki yüklü uygulamalara erişebilmesi için <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> adlı cihaza uzaktan erişim izni verin."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, internete bağlanan bu cihazdaki yüklü uygulamalara erişebilmesi için <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> adlı cihaza uzaktan erişim izni verin."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index 149841a..9f40a0c 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Дозволити додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> керувати вашим пристроєм <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"годинник"</string>
<string name="chooser_title" msgid="2262294130493605839">"Виберіть <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, яким керуватиме додаток <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями та отримає дозволи \"Телефон\", \"SMS\", \"Контакти\" й \"Календар\"."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями та отримає дозволи \"Телефон\", \"SMS\", \"Контакти\" й \"Календар\"."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Дозволити додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> транслювати інші додатки?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дозвольте додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> за наявності з’єднання надавати пристрою <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> віддалений доступ до додатків, установлених на цьому телефоні."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дозвольте додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> за наявності з’єднання надавати пристрою <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> віддалений доступ до додатків, установлених на цьому планшеті."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дозвольте додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> за наявності з’єднання надавати пристрою <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> віддалений доступ до додатків, установлених на цьому пристрої."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"пристрій"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml
index b467550..3c1fe5d 100644
--- a/packages/CompanionDeviceManager/res/values-ur/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"اپنے <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> کا نظم کرنے کے لیے <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو اجازت دیں"</string>
<string name="profile_name_watch" msgid="576290739483672360">"دیکھیں"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> کے ذریعے نظم کئے جانے کیلئے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کو منتخب کریں"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں اور کیلنڈر کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں اور کیلنڈر کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو ایپلیکیشنز کی سلسلہ بندی کرنے کی اجازت دیں؟"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"منسلک ہونے پر، اس فون پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"منسلک ہونے پر، اس ٹیبلیٹ پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"منسلک ہونے پر، اس آلے پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"آلہ"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index 8505ca9..ff5e4b9 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> qurilmasini boshqarish uchun <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga ruxsat bering"</string>
<string name="profile_name_watch" msgid="576290739483672360">"soat"</string>
<string name="chooser_title" msgid="2262294130493605839">"<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> boshqaradigan <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qurilmasini tanlang"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar va taqvimga kirishga ruxsat beriladi"</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar va taqvimga kirishga ruxsat beriladi"</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga ilovalarni strim qilishi uchun ruxsat berilsinmi?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ulanganda ushbu telefonda oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ulanganda ushbu planshetda oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ulanganda ushbu qurilmada oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index 5dec271..f52dde1 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> quản lý <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> của bạn"</string>
<string name="profile_name_watch" msgid="576290739483672360">"đồng hồ"</string>
<string name="chooser_title" msgid="2262294130493605839">"Chọn một <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sẽ do <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> quản lý"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sẽ được phép tương tác với thông báo cũng như truy cập vào Điện thoại, SMS, Danh bạ và Lịch."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"<xliff:g id="APP_NAME">%1$s</xliff:g> sẽ được phép tương tác với thông báo cũng như truy cập vào Điện thoại, SMS, Danh bạ và Lịch."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truyền trực tuyến ứng dụng?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cập từ xa vào các ứng dụng đã cài đặt trên <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> khi điện thoại này có kết nối."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cập từ xa vào các ứng dụng đã cài đặt trên <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> khi máy tính bảng này có kết nối."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cập từ xa vào các ứng dụng đã cài đặt trên <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> khi thiết bị này có kết nối."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"thiết bị"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index f414067..f1facc1 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"允许<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>管理您的<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手表"</string>
<string name="chooser_title" msgid="2262294130493605839">"选择要由<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”将能与通知互动,并可访问电话、短信、通讯录和日历。"</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”将能与通知互动,并可访问电话、短信、通讯录和日历。"</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"是否允许 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 流式传输应用?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"在 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> 连接到网络后,允许 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 远程访问该手机上安装的应用。"</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"在 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> 连接到网络后,允许 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 远程访问该平板电脑上安装的应用。"</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"在 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> 连接到网络后,允许 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 远程访问该设备上安装的应用。"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"设备"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index 37f4bd9..aed008f 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"允許 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 管理您的<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
<string name="chooser_title" msgid="2262294130493605839">"選擇由 <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong> 管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、短訊、聯絡人和日曆資料。"</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、短訊、聯絡人和日曆資料。"</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>串流播放應用程式的內容嗎?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此手機上安裝的應用程式。"</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此平板電腦上安裝的應用程式。"</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此裝置上安裝的應用程式。"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index 76c8379..22a9d9c 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>管理你的「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>"</string>
<string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
<string name="chooser_title" msgid="2262294130493605839">"選擇要讓「<xliff:g id="APP_NAME">%2$s</xliff:g>」<strong></strong>管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、簡訊、聯絡人和日曆資料。"</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」將可存取通知、電話、簡訊、聯絡人和日曆資料。"</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"要允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>串流播放應用程式的內容嗎?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>連上網際網路時可從遠端存取該手機上安裝的應用程式。"</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>連上網際網路時可從遠端存取該平板電腦上安裝的應用程式。"</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>連上網際網路時可從遠端存取該裝置上安裝的應用程式。"</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index fdfda00..5c5756b 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -20,18 +20,12 @@
<string name="confirmation_title" msgid="8455544820286920304">"Vumela i-<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukuthi iphathe i-<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> yakho"</string>
<string name="profile_name_watch" msgid="576290739483672360">"buka"</string>
<string name="chooser_title" msgid="2262294130493605839">"Khetha i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ezophathwa yi-<strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string>
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for summary_watch (7113724443198337683) -->
- <skip />
- <!-- no translation found for title_app_streaming (4459136600249308574) -->
- <skip />
- <!-- no translation found for summary_app_streaming (6105916810614498138) -->
- <skip />
- <!-- no translation found for summary_app_streaming (2996373715966272792) -->
- <skip />
- <!-- no translation found for summary_app_streaming (7614171699434639963) -->
- <skip />
+ <string name="summary_watch" product="default" msgid="7113724443198337683">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> izovunyelwa ukuxhumana nezaziso zakho futhi ifinyelele izimvume Zefoni yakho, -SMS, Abathintwayo kanye Nekhalenda."</string>
+ <string name="summary_watch" product="tablet" msgid="7113724443198337683">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> izovunyelwa ukuxhumana nezaziso zakho futhi ifinyelele izimvume Zefoni yakho, -SMS, Abathintwayo kanye Nekhalenda."</string>
+ <string name="title_app_streaming" msgid="4459136600249308574">"Vumela <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukusakaza ama-applications?"</string>
+ <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Vumela <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukunikezela <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ngokufinyelela kwerimothi kuma-applications afakiwe kule foni uma ixhunyiwe."</string>
+ <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Vumela <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukunikezela <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ngokufinyelela kwerimothi kuma-applications afakiwe kule thebhulethi uma ixhunyiwe."</string>
+ <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Vumela <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukunikezela <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ngokufinyelela kwerimothi kuma-applications afakiwe kule divayisi uma ixhunyiwe."</string>
<string name="title_automotive_projection" msgid="3296005598978412847"></string>
<string name="summary_automotive_projection" msgid="8683801274662496164"></string>
<string name="profile_name_generic" msgid="6851028682723034988">"idivayisi"</string>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index cc887c3..8d14172 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -21,6 +21,8 @@
import static android.companion.AssociationRequest.DEVICE_PROFILE_WATCH;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.SCAN_RESULTS_OBSERVABLE;
+import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.TIMEOUT_OBSERVABLE;
import static com.android.companiondevicemanager.Utils.getApplicationLabel;
import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
import static com.android.companiondevicemanager.Utils.prepareResultReceiverForIpc;
@@ -91,10 +93,16 @@
// The flag used to prevent double taps, that may lead to sending several requests for creating
// an association to CDM.
- private boolean mAssociationApproved;
+ private boolean mApproved;
+ private boolean mCancelled;
+ // A reference to the device selected by the user, to be sent back to the application via
+ // onActivityResult() after the association is created.
+ private @Nullable DeviceFilterPair<?> mSelectedDevice;
@Override
public void onCreate(Bundle savedInstanceState) {
+ if (DEBUG) Log.d(TAG, "onCreate()");
+
super.onCreate(savedInstanceState);
getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
}
@@ -117,26 +125,13 @@
// Start discovery services if needed.
if (!mRequest.isSelfManaged()) {
CompanionDeviceDiscoveryService.startForRequest(this, mRequest);
+ TIMEOUT_OBSERVABLE.addObserver((o, arg) -> cancel(true));
}
// Init UI.
initUI();
}
@Override
- protected void onStop() {
- super.onStop();
- if (DEBUG) Log.d(TAG, "onStop(), finishing=" + isFinishing());
-
- // TODO: handle config changes without cancelling.
- if (!isFinishing()) {
- cancel(); // will finish()
- }
-
- // mAdapter may be observing - need to remove it.
- CompanionDeviceDiscoveryService.SCAN_RESULTS_OBSERVABLE.deleteObservers();
- }
-
- @Override
protected void onNewIntent(Intent intent) {
// Handle another incoming request (while we are not done with the original - mRequest -
// yet).
@@ -153,6 +148,39 @@
}
}
+ @Override
+ protected void onStop() {
+ super.onStop();
+ if (DEBUG) Log.d(TAG, "onStop(), finishing=" + isFinishing());
+
+ // TODO: handle config changes without cancelling.
+ if (!isDone()) {
+ cancel(false); // will finish()
+ }
+
+ TIMEOUT_OBSERVABLE.deleteObservers();
+ // mAdapter may also be observing - need to remove it.
+ SCAN_RESULTS_OBSERVABLE.deleteObservers();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (DEBUG) Log.d(TAG, "onDestroy()");
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (DEBUG) Log.d(TAG, "onBackPressed()");
+ super.onBackPressed();
+ }
+
+ @Override
+ public void finish() {
+ if (DEBUG) Log.d(TAG, "finish()", new Exception("Stack Trace Dump"));
+ super.finish();
+ }
+
private void initUI() {
if (DEBUG) Log.d(TAG, "initUI(), request=" + mRequest);
@@ -164,21 +192,61 @@
mListView = findViewById(R.id.device_list);
mListView.setOnItemClickListener((av, iv, position, id) -> onListItemClick(position));
- mButtonAllow = findViewById(R.id.button_allow);
- mButtonAllow.setOnClickListener(this::onAllowButtonClick);
-
- findViewById(R.id.button_cancel).setOnClickListener(v -> cancel());
+ mButtonAllow = findViewById(R.id.btn_positive);
+ mButtonAllow.setOnClickListener(this::onPositiveButtonClick);
+ findViewById(R.id.btn_negative).setOnClickListener(this::onNegativeButtonClick);
final CharSequence appLabel = getApplicationLabel(this, mRequest.getPackageName());
if (mRequest.isSelfManaged()) {
initUiForSelfManagedAssociation(appLabel);
} else if (mRequest.isSingleDevice()) {
- initUiForSingleDevice(appLabel);
+ // TODO(b/211722613)
+ // Treat singleDevice as the multipleDevices for now
+ // initUiForSingleDevice(appLabel);
+ initUiForMultipleDevices(appLabel);
} else {
initUiForMultipleDevices(appLabel);
}
}
+ private void onUserSelectedDevice(@NonNull DeviceFilterPair<?> selectedDevice) {
+ if (mSelectedDevice != null) {
+ if (DEBUG) Log.w(TAG, "Already selected.");
+ return;
+ }
+ mSelectedDevice = requireNonNull(selectedDevice);
+
+ final MacAddress macAddress = selectedDevice.getMacAddress();
+ onAssociationApproved(macAddress);
+ }
+
+ private void onAssociationApproved(@Nullable MacAddress macAddress) {
+ if (isDone()) {
+ if (DEBUG) Log.w(TAG, "Already done: " + (mApproved ? "Approved" : "Cancelled"));
+ return;
+ }
+ mApproved = true;
+
+ if (DEBUG) Log.i(TAG, "onAssociationApproved() macAddress=" + macAddress);
+
+ if (!mRequest.isSelfManaged()) {
+ requireNonNull(macAddress);
+ CompanionDeviceDiscoveryService.stop(this);
+ }
+
+ final Bundle data = new Bundle();
+ data.putParcelable(EXTRA_ASSOCIATION_REQUEST, mRequest);
+ data.putBinder(EXTRA_APPLICATION_CALLBACK, mAppCallback.asBinder());
+ if (macAddress != null) {
+ data.putParcelable(EXTRA_MAC_ADDRESS, macAddress);
+ }
+
+ data.putParcelable(EXTRA_RESULT_RECEIVER,
+ prepareResultReceiverForIpc(mOnAssociationCreatedReceiver));
+
+ mCdmServiceReceiver.send(RESULT_CODE_ASSOCIATION_APPROVED, data);
+ }
+
private void onAssociationCreated(@NonNull AssociationInfo association) {
if (DEBUG) Log.i(TAG, "onAssociationCreated(), association=" + association);
@@ -186,17 +254,26 @@
setResultAndFinish(association);
}
- private void cancel() {
- if (DEBUG) Log.i(TAG, "cancel()");
+ private void cancel(boolean discoveryTimeout) {
+ if (DEBUG) {
+ Log.i(TAG, "cancel(), discoveryTimeout=" + discoveryTimeout,
+ new Exception("Stack Trace Dump"));
+ }
+
+ if (isDone()) {
+ if (DEBUG) Log.w(TAG, "Already done: " + (mApproved ? "Approved" : "Cancelled"));
+ return;
+ }
+ mCancelled = true;
// Stop discovery service if it was used.
- if (!mRequest.isSelfManaged()) {
+ if (!mRequest.isSelfManaged() || discoveryTimeout) {
CompanionDeviceDiscoveryService.stop(this);
}
// First send callback to the app directly...
try {
- mAppCallback.onFailure("Cancelled.");
+ mAppCallback.onFailure(discoveryTimeout ? "Timeout." : "Cancelled.");
} catch (RemoteException ignore) {
}
@@ -211,8 +288,7 @@
if (association != null) {
data.putExtra(CompanionDeviceManager.EXTRA_ASSOCIATION, association);
if (!association.isSelfManaged()) {
- data.putExtra(CompanionDeviceManager.EXTRA_DEVICE,
- association.getDeviceMacAddressAsString());
+ data.putExtra(CompanionDeviceManager.EXTRA_DEVICE, mSelectedDevice.getDevice());
}
}
setResult(association != null ? RESULT_OK : RESULT_CANCELED, data);
@@ -297,7 +373,7 @@
mSummary.setText(summary);
mAdapter = new DeviceListAdapter(this);
- CompanionDeviceDiscoveryService.SCAN_RESULTS_OBSERVABLE.addObserver(mAdapter);
+ SCAN_RESULTS_OBSERVABLE.addObserver(mAdapter);
// TODO: hide the list and show a spinner until a first device matching device is found.
mListView.setAdapter(mAdapter);
@@ -309,49 +385,35 @@
if (DEBUG) Log.d(TAG, "onListItemClick() " + position);
final DeviceFilterPair<?> selectedDevice = mAdapter.getItem(position);
- final MacAddress macAddress = selectedDevice.getMacAddress();
- onAssociationApproved(macAddress);
+ onUserSelectedDevice(selectedDevice);
}
- private void onAllowButtonClick(View v) {
- if (DEBUG) Log.d(TAG, "onAllowButtonClick()");
+ private void onPositiveButtonClick(View v) {
+ if (DEBUG) Log.d(TAG, "on_Positive_ButtonClick()");
// Disable the button, to prevent more clicks.
v.setEnabled(false);
- final MacAddress macAddress;
if (mRequest.isSelfManaged()) {
- macAddress = null;
+ onAssociationApproved(null);
} else {
- // TODO: implement.
+ // TODO(b/211722613): call onUserSelectedDevice().
throw new UnsupportedOperationException(
"isSingleDevice() requests are not supported yet.");
}
- onAssociationApproved(macAddress);
}
- private void onAssociationApproved(@Nullable MacAddress macAddress) {
- if (mAssociationApproved) return;
- mAssociationApproved = true;
+ private void onNegativeButtonClick(View v) {
+ if (DEBUG) Log.d(TAG, "on_Negative_ButtonClick()");
- if (DEBUG) Log.i(TAG, "onAssociationApproved() macAddress=" + macAddress);
+ // Disable the button, to prevent more clicks.
+ v.setEnabled(false);
- if (!mRequest.isSelfManaged()) {
- requireNonNull(macAddress);
- CompanionDeviceDiscoveryService.stop(this);
- }
+ cancel(false);
+ }
- final Bundle data = new Bundle();
- data.putParcelable(EXTRA_ASSOCIATION_REQUEST, mRequest);
- data.putBinder(EXTRA_APPLICATION_CALLBACK, mAppCallback.asBinder());
- if (macAddress != null) {
- data.putParcelable(EXTRA_MAC_ADDRESS, macAddress);
- }
-
- data.putParcelable(EXTRA_RESULT_RECEIVER,
- prepareResultReceiverForIpc(mOnAssociationCreatedReceiver));
-
- mCdmServiceReceiver.send(RESULT_CODE_ASSOCIATION_APPROVED, data);
+ private boolean isDone() {
+ return mApproved || mCancelled;
}
private final ResultReceiver mOnAssociationCreatedReceiver =
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index a4ff1dc..f859130 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -22,6 +22,8 @@
import static com.android.internal.util.CollectionUtils.find;
import static com.android.internal.util.CollectionUtils.map;
+import static java.lang.Math.max;
+import static java.lang.Math.min;
import static java.util.Objects.requireNonNull;
import android.annotation.MainThread;
@@ -50,6 +52,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Parcelable;
+import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;
@@ -64,13 +67,17 @@
private static final boolean DEBUG = false;
private static final String TAG = CompanionDeviceDiscoveryService.class.getSimpleName();
+ private static final String SYS_PROP_DEBUG_TIMEOUT = "debug.cdm.discovery_timeout";
+ private static final long TIMEOUT_DEFAULT = 20_000L; // 20 seconds
+ private static final long TIMEOUT_MIN = 1_000L; // 1 sec
+ private static final long TIMEOUT_MAX = 60_000L; // 1 min
+
private static final String ACTION_START_DISCOVERY =
"com.android.companiondevicemanager.action.START_DISCOVERY";
private static final String ACTION_STOP_DISCOVERY =
"com.android.companiondevicemanager.action.ACTION_STOP_DISCOVERY";
private static final String EXTRA_ASSOCIATION_REQUEST = "association_request";
- private static final long SCAN_TIMEOUT = 20_000L; // 20 seconds
// TODO: replace with LiveData-s?
static final Observable TIMEOUT_OBSERVABLE = new MyObservable();
@@ -180,8 +187,7 @@
// Start BLE scanning (if needed)
mBleScanCallback = startBleScanningIfNeeded(bleFilters, forceStartScanningAll);
- // Schedule a time-out.
- Handler.getMain().postDelayed(mTimeoutRunnable, SCAN_TIMEOUT);
+ scheduleTimeout();
}
@MainThread
@@ -338,6 +344,21 @@
});
}
+ private void scheduleTimeout() {
+ long timeout = SystemProperties.getLong(SYS_PROP_DEBUG_TIMEOUT, -1);
+ if (timeout <= 0) {
+ // 0 or negative values indicate that the sysprop was never set or should be ignored.
+ timeout = TIMEOUT_DEFAULT;
+ } else {
+ timeout = min(timeout, TIMEOUT_MAX); // should be <= 1 min (TIMEOUT_MAX)
+ timeout = max(timeout, TIMEOUT_MIN); // should be >= 1 sec (TIMEOUT_MIN)
+ }
+
+ if (DEBUG) Log.d(TAG, "scheduleTimeout(), timeout=" + timeout);
+
+ Handler.getMain().postDelayed(mTimeoutRunnable, timeout);
+ }
+
private void timeout() {
if (DEBUG) Log.i(TAG, "timeout()");
stopDiscoveryAndFinish();
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
index cf2a2bf..2499cf0 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
@@ -16,18 +16,14 @@
package com.android.companiondevicemanager;
-import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.util.TypedValue;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
+import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
@@ -39,51 +35,12 @@
*/
class DeviceListAdapter extends BaseAdapter implements Observer {
private final Context mContext;
- private final Resources mResources;
-
- private final Drawable mBluetoothIcon;
- private final Drawable mWifiIcon;
-
- private final @ColorInt int mTextColor;
// List if pairs (display name, address)
private List<DeviceFilterPair<?>> mDevices;
DeviceListAdapter(Context context) {
mContext = context;
- mResources = context.getResources();
- mBluetoothIcon = getTintedIcon(mResources, android.R.drawable.stat_sys_data_bluetooth);
- mWifiIcon = getTintedIcon(mResources, com.android.internal.R.drawable.ic_wifi_signal_3);
- mTextColor = getColor(context, android.R.attr.colorForeground);
- }
-
- @Override
- public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
- final TextView view = convertView != null ? (TextView) convertView : newView();
- bind(view, getItem(position));
- return view;
- }
-
- private void bind(TextView textView, DeviceFilterPair<?> item) {
- textView.setText(item.getDisplayName());
- textView.setBackgroundColor(Color.TRANSPARENT);
- /*
- textView.setCompoundDrawablesWithIntrinsicBounds(
- item.getDevice() instanceof android.net.wifi.ScanResult
- ? mWifiIcon
- : mBluetoothIcon,
- null, null, null);
- textView.getCompoundDrawables()[0].setTint(mTextColor);
- */
- }
-
- private TextView newView() {
- final TextView textView = new TextView(mContext);
- textView.setTextColor(mTextColor);
- final int padding = 24;
- textView.setPadding(padding, padding, padding, padding);
- //textView.setCompoundDrawablePadding(padding);
- return textView;
}
@Override
@@ -107,17 +64,29 @@
notifyDataSetChanged();
}
- private @ColorInt int getColor(Context context, int attr) {
- final TypedArray a = context.obtainStyledAttributes(new TypedValue().data,
- new int[] { attr });
- final int color = a.getColor(0, 0);
- a.recycle();
- return color;
+ @Override
+ public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
+ final View view = convertView != null
+ ? convertView
+ : LayoutInflater.from(mContext).inflate(R.layout.list_item_device, parent, false);
+
+ final DeviceFilterPair<?> item = getItem(position);
+ bindView(view, item);
+
+ return view;
}
- private static Drawable getTintedIcon(Resources resources, int drawableRes) {
- Drawable icon = resources.getDrawable(drawableRes, null);
- icon.setTint(Color.DKGRAY);
- return icon;
+ private void bindView(@NonNull View view, DeviceFilterPair<?> item) {
+ final TextView textView = view.findViewById(android.R.id.text1);
+ textView.setText(item.getDisplayName());
+
+ final ImageView iconView = view.findViewById(android.R.id.icon);
+
+ // TODO(b/211417476): Set either Bluetooth or WiFi icon.
+ iconView.setVisibility(View.GONE);
+ // final int iconRes = isBt ? android.R.drawable.stat_sys_data_bluetooth
+ // : com.android.internal.R.drawable.ic_wifi_signal_3;
+ // final Drawable icon = getTintedIcon(mResources, iconRes);
+ // iconView.setImageDrawable(icon);
}
}
diff --git a/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp
index 0bda923..38bac1c 100644
--- a/packages/ConnectivityT/framework-t/Android.bp
+++ b/packages/ConnectivityT/framework-t/Android.bp
@@ -150,8 +150,18 @@
":framework-connectivity-ethernet-sources",
":framework-connectivity-ipsec-sources",
":framework-connectivity-netstats-sources",
+ ],
+ visibility: ["//frameworks/base"],
+}
+
+filegroup {
+ name: "framework-connectivity-tiramisu-updatable-sources",
+ srcs: [
":framework-connectivity-nsd-sources",
":framework-connectivity-tiramisu-internal-sources",
],
- visibility: ["//frameworks/base"],
+ visibility: [
+ "//frameworks/base",
+ "//packages/modules/Connectivity:__subpackages__",
+ ],
}
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
index 216a4a0..f684a4d 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
@@ -24,13 +24,15 @@
import android.net.NetworkTemplate;
import android.net.TrafficStats;
import android.os.RemoteException;
-import android.util.IntArray;
import android.util.Log;
+import com.android.net.module.util.CollectionUtils;
+
import dalvik.system.CloseGuard;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
/**
* Class providing enumeration over buckets of network usage statistics. {@link NetworkStats} objects
@@ -568,7 +570,7 @@
// the filtering logic below can be removed.
int[] uids = mSession.getRelevantUids();
// Filtering of uids with empty history.
- IntArray filteredUids = new IntArray(uids.length);
+ final ArrayList<Integer> filteredUids = new ArrayList<>();
for (int uid : uids) {
try {
NetworkStatsHistory history = mSession.getHistoryIntervalForUid(mTemplate, uid,
@@ -581,7 +583,7 @@
Log.w(TAG, "Error while getting history of uid " + uid, e);
}
}
- mUids = filteredUids.toArray();
+ mUids = CollectionUtils.toIntArray(filteredUids);
mUidOrUidIndex = -1;
stepHistory();
}
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
index ca83309..a316b8a 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
@@ -47,7 +47,6 @@
import android.os.RemoteException;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
-import android.util.DataUnit;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -119,7 +118,7 @@
* is reached.
* @hide
*/
- public static final long MIN_THRESHOLD_BYTES = DataUnit.MEBIBYTES.toBytes(2);
+ public static final long MIN_THRESHOLD_BYTES = 2 * 1_048_576L; // 2MiB
private final Context mContext;
private final INetworkStatsService mService;
@@ -139,6 +138,7 @@
mContext = context;
mService = service;
setPollOnOpen(true);
+ setAugmentWithSubscriptionPlan(true);
}
/** @hide */
@@ -170,16 +170,44 @@
}
}
- /** @hide */
- public Bucket querySummaryForDevice(NetworkTemplate template,
- long startTime, long endTime) throws SecurityException, RemoteException {
- Bucket bucket = null;
- NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime,
- mService);
- bucket = stats.getDeviceSummaryForNetwork();
-
- stats.close();
- return bucket;
+ /**
+ * Query network usage statistics summaries.
+ *
+ * Result is summarised data usage for the whole
+ * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and
+ * roaming. This means the bucket's start and end timestamp will be the same as the
+ * 'startTime' and 'endTime' arguments. State is going to be
+ * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL},
+ * tag {@link NetworkStats.Bucket#TAG_NONE},
+ * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
+ * metered {@link NetworkStats.Bucket#METERED_ALL},
+ * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}.
+ * This may take a long time, and apps should avoid calling this on their main thread.
+ *
+ * @param template Template used to match networks. See {@link NetworkTemplate}.
+ * @param startTime Start of period, in milliseconds since the Unix epoch, see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period, in milliseconds since the Unix epoch, see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @return Bucket Summarised data usage.
+ *
+ * @hide
+ */
+ @NonNull
+ @WorkerThread
+ // @SystemApi(client = MODULE_LIBRARIES)
+ public Bucket querySummaryForDevice(@NonNull NetworkTemplate template,
+ long startTime, long endTime) {
+ try {
+ NetworkStats stats =
+ new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
+ Bucket bucket = stats.getDeviceSummaryForNetwork();
+ stats.close();
+ return bucket;
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return null; // To make the compiler happy.
}
/**
@@ -323,14 +351,37 @@
return querySummary(template, startTime, endTime);
}
- /** @hide */
- public NetworkStats querySummary(NetworkTemplate template, long startTime,
- long endTime) throws SecurityException, RemoteException {
- NetworkStats result;
- result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
- result.startSummaryEnumeration();
-
- return result;
+ /**
+ * Query network usage statistics summaries.
+ *
+ * The results will only include traffic made by UIDs belonging to the calling user profile.
+ * The results are aggregated over time, so that all buckets will have the same start and
+ * end timestamps as the passed arguments. Not aggregated over state, uid, default network,
+ * metered, or roaming.
+ * This may take a long time, and apps should avoid calling this on their main thread.
+ *
+ * @param template Template used to match networks. See {@link NetworkTemplate}.
+ * @param startTime Start of period, in milliseconds since the Unix epoch, see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period, in milliseconds since the Unix epoch, see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @return Statistics which is described above.
+ * @hide
+ */
+ @Nullable
+ // @SystemApi(client = MODULE_LIBRARIES)
+ @WorkerThread
+ public NetworkStats querySummary(@NonNull NetworkTemplate template, long startTime,
+ long endTime) throws SecurityException {
+ try {
+ NetworkStats result =
+ new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
+ result.startSummaryEnumeration();
+ return result;
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return null; // To make the compiler happy.
}
/**
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
index 7cd63ef..ece54df 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
@@ -16,7 +16,9 @@
package android.net;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -32,6 +34,7 @@
import java.util.ArrayList;
import java.util.Objects;
import java.util.concurrent.Executor;
+import java.util.function.BiConsumer;
/**
* A class representing the IP configuration of the Ethernet network.
@@ -315,4 +318,83 @@
}
return new TetheredInterfaceRequest(mService, cbInternal);
}
+
+ private static final class InternalNetworkManagementListener
+ extends IInternalNetworkManagementListener.Stub {
+ @NonNull
+ private final Executor mExecutor;
+ @NonNull
+ private final BiConsumer<Network, InternalNetworkManagementException> mListener;
+
+ InternalNetworkManagementListener(
+ @NonNull final Executor executor,
+ @NonNull final BiConsumer<Network, InternalNetworkManagementException> listener) {
+ Objects.requireNonNull(executor, "Pass a non-null executor");
+ Objects.requireNonNull(listener, "Pass a non-null listener");
+ mExecutor = executor;
+ mListener = listener;
+ }
+
+ @Override
+ public void onComplete(
+ @Nullable final Network network,
+ @Nullable final InternalNetworkManagementException e) {
+ mExecutor.execute(() -> mListener.accept(network, e));
+ }
+ }
+
+ private InternalNetworkManagementListener getInternalNetworkManagementListener(
+ @Nullable final Executor executor,
+ @Nullable final BiConsumer<Network, InternalNetworkManagementException> listener) {
+ if (null != listener) {
+ Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener");
+ }
+ final InternalNetworkManagementListener proxy;
+ if (null == listener) {
+ proxy = null;
+ } else {
+ proxy = new InternalNetworkManagementListener(executor, listener);
+ }
+ return proxy;
+ }
+
+ private void updateConfiguration(
+ @NonNull String iface,
+ @NonNull InternalNetworkUpdateRequest request,
+ @Nullable @CallbackExecutor Executor executor,
+ @Nullable BiConsumer<Network, InternalNetworkManagementException> listener) {
+ final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
+ executor, listener);
+ try {
+ mService.updateConfiguration(iface, request, proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private void connectNetwork(
+ @NonNull String iface,
+ @Nullable @CallbackExecutor Executor executor,
+ @Nullable BiConsumer<Network, InternalNetworkManagementException> listener) {
+ final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
+ executor, listener);
+ try {
+ mService.connectNetwork(iface, proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private void disconnectNetwork(
+ @NonNull String iface,
+ @Nullable @CallbackExecutor Executor executor,
+ @Nullable BiConsumer<Network, InternalNetworkManagementException> listener) {
+ final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
+ executor, listener);
+ try {
+ mService.disconnectNetwork(iface, proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
index e058e5a..e688bea 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
@@ -18,6 +18,8 @@
import android.net.IpConfiguration;
import android.net.IEthernetServiceListener;
+import android.net.IInternalNetworkManagementListener;
+import android.net.InternalNetworkUpdateRequest;
import android.net.ITetheredInterfaceCallback;
/**
@@ -36,4 +38,8 @@
void setIncludeTestInterfaces(boolean include);
void requestTetheredInterface(in ITetheredInterfaceCallback callback);
void releaseTetheredInterface(in ITetheredInterfaceCallback callback);
+ void updateConfiguration(String iface, in InternalNetworkUpdateRequest request,
+ in IInternalNetworkManagementListener listener);
+ void connectNetwork(String iface, in IInternalNetworkManagementListener listener);
+ void disconnectNetwork(String iface, in IInternalNetworkManagementListener listener);
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
index 0b266b2..0d15dff 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
@@ -17,8 +17,6 @@
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
import android.annotation.NonNull;
import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
@@ -46,6 +44,7 @@
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
+import java.util.Objects;
/**
* This class contains methods for managing IPsec sessions. Once configured, the kernel will apply
@@ -989,7 +988,7 @@
*/
public IpSecManager(Context ctx, IIpSecService service) {
mContext = ctx;
- mService = checkNotNull(service, "missing service");
+ mService = Objects.requireNonNull(service, "missing service");
}
private static void maybeHandleServiceSpecificException(ServiceSpecificException sse) {
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java
index b48c1fd..36199a0 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java
@@ -33,7 +33,6 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
import dalvik.system.CloseGuard;
@@ -41,6 +40,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.InetAddress;
+import java.util.Objects;
/**
* This class represents a transform, which roughly corresponds to an IPsec Security Association.
@@ -255,7 +255,7 @@
@NonNull
public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) {
// TODO: throw IllegalArgumentException if algo is not an encryption algorithm.
- Preconditions.checkNotNull(algo);
+ Objects.requireNonNull(algo);
mConfig.setEncryption(algo);
return this;
}
@@ -270,7 +270,7 @@
@NonNull
public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) {
// TODO: throw IllegalArgumentException if algo is not an authentication algorithm.
- Preconditions.checkNotNull(algo);
+ Objects.requireNonNull(algo);
mConfig.setAuthentication(algo);
return this;
}
@@ -290,7 +290,7 @@
*/
@NonNull
public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) {
- Preconditions.checkNotNull(algo);
+ Objects.requireNonNull(algo);
mConfig.setAuthenticatedEncryption(algo);
return this;
}
@@ -311,7 +311,7 @@
@NonNull
public IpSecTransform.Builder setIpv4Encapsulation(
@NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
- Preconditions.checkNotNull(localSocket);
+ Objects.requireNonNull(localSocket);
mConfig.setEncapType(ENCAP_ESPINUDP);
if (localSocket.getResourceId() == INVALID_RESOURCE_ID) {
throw new IllegalArgumentException("Invalid UdpEncapsulationSocket");
@@ -348,8 +348,8 @@
@NonNull IpSecManager.SecurityParameterIndex spi)
throws IpSecManager.ResourceUnavailableException,
IpSecManager.SpiUnavailableException, IOException {
- Preconditions.checkNotNull(sourceAddress);
- Preconditions.checkNotNull(spi);
+ Objects.requireNonNull(sourceAddress);
+ Objects.requireNonNull(spi);
if (spi.getResourceId() == INVALID_RESOURCE_ID) {
throw new IllegalArgumentException("Invalid SecurityParameterIndex");
}
@@ -387,8 +387,8 @@
@NonNull IpSecManager.SecurityParameterIndex spi)
throws IpSecManager.ResourceUnavailableException,
IpSecManager.SpiUnavailableException, IOException {
- Preconditions.checkNotNull(sourceAddress);
- Preconditions.checkNotNull(spi);
+ Objects.requireNonNull(sourceAddress);
+ Objects.requireNonNull(spi);
if (spi.getResourceId() == INVALID_RESOURCE_ID) {
throw new IllegalArgumentException("Invalid SecurityParameterIndex");
}
@@ -404,7 +404,7 @@
* @param context current context
*/
public Builder(@NonNull Context context) {
- Preconditions.checkNotNull(context);
+ Objects.requireNonNull(context);
mContext = context;
mConfig = new IpSecConfig();
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
index eb8f43e..8f1115e 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
@@ -21,7 +21,6 @@
import android.annotation.Nullable;
import android.content.Context;
import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
import android.service.NetworkIdentityProto;
import android.telephony.Annotation.NetworkType;
import android.util.proto.ProtoOutputStream;
@@ -228,11 +227,11 @@
final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities());
if (legacyType == TYPE_WIFI) {
- networkId = snapshot.getNetworkCapabilities().getSsid();
- if (networkId == null) {
- final WifiManager wifi = context.getSystemService(WifiManager.class);
- final WifiInfo info = wifi.getConnectionInfo();
- networkId = info != null ? info.getSSID() : null;
+ final TransportInfo transportInfo = snapshot.getNetworkCapabilities()
+ .getTransportInfo();
+ if (transportInfo instanceof WifiInfo) {
+ final WifiInfo info = (WifiInfo) transportInfo;
+ networkId = info != null ? info.getCurrentNetworkKey() : null;
}
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
index 1986b83..181a594 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
@@ -31,7 +31,7 @@
import android.util.SparseBooleanArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
+import com.android.net.module.util.CollectionUtils;
import libcore.util.EmptyArray;
@@ -1185,7 +1185,7 @@
* @hide
*/
public void removeUids(int[] uids) {
- filter(e -> !ArrayUtils.contains(uids, e.uid));
+ filter(e -> !CollectionUtils.contains(uids, e.uid));
}
/**
@@ -1218,7 +1218,7 @@
filter(e -> (limitUid == UID_ALL || limitUid == e.uid)
&& (limitTag == TAG_ALL || limitTag == e.tag)
&& (limitIfaces == INTERFACES_ALL
- || ArrayUtils.contains(limitIfaces, e.iface)));
+ || CollectionUtils.contains(limitIfaces, e.iface)));
}
/**
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java
index 3885a9e..b64fbdb 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java
@@ -17,6 +17,7 @@
package android.net;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_REMOVED;
import static android.net.TrafficStats.UID_TETHERING;
@@ -24,7 +25,7 @@
import android.Manifest;
import android.annotation.IntDef;
import android.app.AppOpsManager;
-import android.app.admin.DevicePolicyManagerInternal;
+import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
@@ -32,8 +33,6 @@
import android.os.UserHandle;
import android.telephony.TelephonyManager;
-import com.android.server.LocalServices;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -108,9 +107,8 @@
/** Returns the {@link NetworkStatsAccess.Level} for the given caller. */
public static @NetworkStatsAccess.Level int checkAccessLevel(
- Context context, int callingUid, String callingPackage) {
- final DevicePolicyManagerInternal dpmi = LocalServices.getService(
- DevicePolicyManagerInternal.class);
+ Context context, int callingPid, int callingUid, String callingPackage) {
+ final DevicePolicyManager mDpm = context.getSystemService(DevicePolicyManager.class);
final TelephonyManager tm = (TelephonyManager)
context.getSystemService(Context.TELEPHONY_SERVICE);
boolean hasCarrierPrivileges;
@@ -123,10 +121,15 @@
Binder.restoreCallingIdentity(token);
}
- final boolean isDeviceOwner = dpmi != null && dpmi.isActiveDeviceOwner(callingUid);
+ final boolean isDeviceOwner = mDpm != null && mDpm.isDeviceOwnerApp(callingPackage);
final int appId = UserHandle.getAppId(callingUid);
+
+ final boolean isNetworkStack = context.checkPermission(
+ android.Manifest.permission.NETWORK_STACK, callingPid, callingUid)
+ == PERMISSION_GRANTED;
+
if (hasCarrierPrivileges || isDeviceOwner
- || appId == Process.SYSTEM_UID || appId == Process.NETWORK_STACK_UID) {
+ || appId == Process.SYSTEM_UID || isNetworkStack) {
// Carrier-privileged apps and device owners, and the system (including the
// network stack) can access data usage for all apps on the device.
return NetworkStatsAccess.Level.DEVICE;
@@ -139,8 +142,8 @@
}
//TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode.
- boolean isProfileOwner = dpmi != null && (dpmi.isActiveProfileOwner(callingUid)
- || dpmi.isActiveDeviceOwner(callingUid));
+ boolean isProfileOwner = mDpm != null && (mDpm.isProfileOwnerApp(callingPackage)
+ || mDpm.isDeviceOwnerApp(callingPackage));
if (isProfileOwner) {
// Apps with the AppOps permission, profile owners, and apps with the privileged
// permission can access data usage for all apps in this user/profile.
@@ -157,6 +160,8 @@
*/
public static boolean isAccessibleToUser(int uid, int callerUid,
@NetworkStatsAccess.Level int accessLevel) {
+ final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+ final int callerUserId = UserHandle.getUserHandleForUid(callerUid).getIdentifier();
switch (accessLevel) {
case NetworkStatsAccess.Level.DEVICE:
// Device-level access - can access usage for any uid.
@@ -167,13 +172,13 @@
// anonymized uids
return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED
|| uid == UID_TETHERING || uid == UID_ALL
- || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
+ || userId == callerUserId;
case NetworkStatsAccess.Level.USER:
// User-level access - can access usage for any app running in the same user, along
// with some special uids (system, removed, or tethering).
return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED
|| uid == UID_TETHERING
- || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
+ || userId == callerUserId;
case NetworkStatsAccess.Level.DEFAULT:
default:
// Default access level - can only access one's own usage.
@@ -187,8 +192,8 @@
AppOpsManager appOps = (AppOpsManager) context.getSystemService(
Context.APP_OPS_SERVICE);
- final int mode = appOps.noteOp(AppOpsManager.OP_GET_USAGE_STATS,
- callingUid, callingPackage);
+ final int mode = appOps.noteOp(AppOpsManager.OPSTR_GET_USAGE_STATS,
+ callingUid, callingPackage, null /* attributionTag */, null /* message */);
if (mode == AppOpsManager.MODE_DEFAULT) {
// The default behavior here is to check if PackageManager has given the app
// permission.
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
index 8d1347e..7935d28 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
@@ -40,21 +40,17 @@
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.AtomicFile;
-import android.util.IntArray;
-import android.util.MathUtils;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
import android.util.Range;
-import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastDataInput;
import com.android.internal.util.FastDataOutput;
import com.android.internal.util.FileRotator;
-import com.android.internal.util.IndentingPrintWriter;
-
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
+import com.android.net.module.util.CollectionUtils;
+import com.android.net.module.util.NetworkStatsUtils;
import libcore.io.IoUtils;
@@ -196,11 +192,11 @@
public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel,
final int callerUid) {
- IntArray uids = new IntArray();
+ final ArrayList<Integer> uids = new ArrayList<>();
for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i);
if (NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel)) {
- int j = uids.binarySearch(key.uid);
+ int j = Collections.binarySearch(uids, new Integer(key.uid));
if (j < 0) {
j = ~j;
@@ -208,7 +204,7 @@
}
}
}
- return uids.toArray();
+ return CollectionUtils.toIntArray(uids);
}
/**
@@ -225,7 +221,8 @@
// 180 days of history should be enough for anyone; if we end up needing
// more, we'll dynamically grow the history object.
- final int bucketEstimate = (int) MathUtils.constrain(((end - start) / mBucketDuration), 0,
+ final int bucketEstimate = (int) NetworkStatsUtils.constrain(
+ ((end - start) / mBucketDuration), 0,
(180 * DateUtils.DAY_IN_MILLIS) / mBucketDuration);
final NetworkStatsHistory combined = new NetworkStatsHistory(
mBucketDuration, bucketEstimate, fields);
@@ -316,7 +313,7 @@
final long deltaTotal = combined.getTotalBytes() - beforeTotal;
if (deltaTotal != 0) {
- Slog.d(TAG, "Augmented network usage by " + deltaTotal + " bytes");
+ Log.d(TAG, "Augmented network usage by " + deltaTotal + " bytes");
}
// Finally we can slice data as originally requested
@@ -489,11 +486,11 @@
private void write(DataOutput out) throws IOException {
// cluster key lists grouped by ident
- final HashMap<NetworkIdentitySet, ArrayList<Key>> keysByIdent = Maps.newHashMap();
+ final HashMap<NetworkIdentitySet, ArrayList<Key>> keysByIdent = new HashMap<>();
for (Key key : mStats.keySet()) {
ArrayList<Key> keys = keysByIdent.get(key.ident);
if (keys == null) {
- keys = Lists.newArrayList();
+ keys = new ArrayList<>();
keysByIdent.put(key.ident, keys);
}
keys.add(key);
@@ -640,12 +637,12 @@
* {@link TrafficStats#UID_REMOVED}.
*/
public void removeUids(int[] uids) {
- final ArrayList<Key> knownKeys = Lists.newArrayList();
+ final ArrayList<Key> knownKeys = new ArrayList<>();
knownKeys.addAll(mStats.keySet());
// migrate all UID stats into special "removed" bucket
for (Key key : knownKeys) {
- if (ArrayUtils.contains(uids, key.uid)) {
+ if (CollectionUtils.contains(uids, key.uid)) {
// only migrate combined TAG_NONE history
if (key.tag == TAG_NONE) {
final NetworkStatsHistory uidHistory = mStats.get(key);
@@ -672,7 +669,7 @@
}
private ArrayList<Key> getSortedKeys() {
- final ArrayList<Key> keys = Lists.newArrayList();
+ final ArrayList<Key> keys = new ArrayList<>();
keys.addAll(mStats.keySet());
Collections.sort(keys);
return keys;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
index 3eef4ee..428bc6d 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
@@ -28,7 +28,6 @@
import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-import static com.android.internal.util.ArrayUtils.total;
import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational;
import android.compat.annotation.UnsupportedAppUsage;
@@ -37,10 +36,11 @@
import android.os.Parcelable;
import android.service.NetworkStatsHistoryBucketProto;
import android.service.NetworkStatsHistoryProto;
-import android.util.MathUtils;
+import android.util.IndentingPrintWriter;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.CollectionUtils;
+import com.android.net.module.util.NetworkStatsUtils;
import libcore.util.EmptyArray;
@@ -174,7 +174,7 @@
txPackets = new long[bucketStart.length];
operations = new long[bucketStart.length];
bucketCount = bucketStart.length;
- totalBytes = total(rxBytes) + total(txBytes);
+ totalBytes = CollectionUtils.total(rxBytes) + CollectionUtils.total(txBytes);
break;
}
case VERSION_ADD_PACKETS:
@@ -189,7 +189,7 @@
txPackets = readVarLongArray(in);
operations = readVarLongArray(in);
bucketCount = bucketStart.length;
- totalBytes = total(rxBytes) + total(txBytes);
+ totalBytes = CollectionUtils.total(rxBytes) + CollectionUtils.total(txBytes);
break;
}
default: {
@@ -267,7 +267,7 @@
} else {
index -= 1;
}
- return MathUtils.constrain(index, 0, bucketCount - 1);
+ return NetworkStatsUtils.constrain(index, 0, bucketCount - 1);
}
/**
@@ -281,7 +281,7 @@
} else {
index += 1;
}
- return MathUtils.constrain(index, 0, bucketCount - 1);
+ return NetworkStatsUtils.constrain(index, 0, bucketCount - 1);
}
/**
@@ -349,6 +349,9 @@
// create any buckets needed by this range
ensureBuckets(start, end);
+ // Return fast if there is still no entry. This would typically happen when the start,
+ // end or duration are not valid values, e.g. start > end, negative duration value, etc.
+ if (bucketCount == 0) return;
// distribute data usage into buckets
long duration = end - start;
@@ -560,6 +563,9 @@
entry.txPackets = txPackets != null ? 0 : UNKNOWN;
entry.operations = operations != null ? 0 : UNKNOWN;
+ // Return fast if there is no entry.
+ if (bucketCount == 0) return entry;
+
final int startIndex = getIndexAfter(end);
for (int i = startIndex; i >= 0; i--) {
final long curStart = bucketStart[i];
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
index 7dd04c5..659ad06 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
@@ -35,7 +35,6 @@
import static android.net.NetworkStats.ROAMING_ALL;
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.ROAMING_YES;
-import static android.net.wifi.WifiInfo.sanitizeSsid;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -49,13 +48,15 @@
import android.text.TextUtils;
import android.util.ArraySet;
-import com.android.internal.util.ArrayUtils;
+import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.NetworkIdentityUtils;
+import com.android.net.module.util.NetworkStatsUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
@@ -114,27 +115,6 @@
*/
public static final int MATCH_CARRIER = 10;
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "SUBSCRIBER_ID_MATCH_RULE_" }, value = {
- SUBSCRIBER_ID_MATCH_RULE_EXACT,
- SUBSCRIBER_ID_MATCH_RULE_ALL
- })
- public @interface SubscriberIdMatchRule{}
- /**
- * Value of the match rule of the subscriberId to match networks with specific subscriberId.
- *
- * @hide
- */
- public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0;
- /**
- * Value of the match rule of the subscriberId to match networks with any subscriberId which
- * includes null and non-null.
- *
- * @hide
- */
- public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1;
-
// TODO: Remove this and replace all callers with WIFI_NETWORK_KEY_ALL.
/** @hide */
public static final String WIFI_NETWORKID_ALL = null;
@@ -233,13 +213,16 @@
public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId,
@NetworkType int ratType, int metered) {
if (TextUtils.isEmpty(subscriberId)) {
- return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null,
- metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null /* subscriberId */,
+ null /* matchSubscriberIds */,
+ new String[0] /* matchWifiNetworkKeys */, metered, ROAMING_ALL,
+ DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
+ NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
- return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null,
+ return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[] { subscriberId },
+ new String[0] /* matchWifiNetworkKeys */,
metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
/**
@@ -255,7 +238,7 @@
/**
* Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks,
- * regardless of SSID.
+ * regardless of key of the wifi network.
*
* @hide
*/
@@ -275,34 +258,41 @@
/**
* Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the
- * given SSID.
+ * given key of the wifi network.
*
+ * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()}
+ * to know details about the key.
* @hide
*/
- public static NetworkTemplate buildTemplateWifi(@NonNull String networkId) {
- Objects.requireNonNull(networkId);
+ public static NetworkTemplate buildTemplateWifi(@NonNull String wifiNetworkKey) {
+ Objects.requireNonNull(wifiNetworkKey);
return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */,
new String[] { null } /* matchSubscriberIds */,
- networkId, METERED_ALL, ROAMING_ALL,
+ new String[] { wifiNetworkKey }, METERED_ALL, ROAMING_ALL,
DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
- SUBSCRIBER_ID_MATCH_RULE_ALL);
+ NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL);
}
/**
- * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given SSID,
- * and IMSI.
+ * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given
+ * key of the wifi network and IMSI.
*
- * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code networkId} to get result regardless
- * of SSID.
+ * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code wifiNetworkKey} to get result regardless
+ * of key of the wifi network.
+ *
+ * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()}
+ * to know details about the key.
+ * @param subscriberId the IMSI associated to this wifi network.
*
* @hide
*/
- public static NetworkTemplate buildTemplateWifi(@Nullable String networkId,
+ public static NetworkTemplate buildTemplateWifi(@Nullable String wifiNetworkKey,
@Nullable String subscriberId) {
return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId },
- networkId, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ wifiNetworkKey != null
+ ? new String[] { wifiNetworkKey } : new String[0],
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
+ NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
/**
@@ -344,9 +334,11 @@
public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) {
Objects.requireNonNull(subscriberId);
return new NetworkTemplate(MATCH_CARRIER, subscriberId,
- new String[] { subscriberId }, null /* networkId */, METERED_YES, ROAMING_ALL,
+ new String[] { subscriberId },
+ new String[0] /* matchWifiNetworkKeys */,
+ METERED_YES, ROAMING_ALL,
DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
private final int mMatchRule;
@@ -362,8 +354,8 @@
*/
private final String[] mMatchSubscriberIds;
- // TODO: Change variable name to match the Api surface.
- private final String mNetworkId;
+ @NonNull
+ private final String[] mMatchWifiNetworkKeys;
// Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*.
private final int mMetered;
@@ -384,7 +376,7 @@
case MATCH_MOBILE:
case MATCH_CARRIER:
// MOBILE and CARRIER templates must always specify a subscriber ID.
- if (subscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) {
+ if (subscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL) {
throw new IllegalArgumentException("Invalid SubscriberIdMatchRule "
+ "on match rule: " + getMatchRuleName(matchRule));
}
@@ -397,42 +389,46 @@
/** @hide */
// TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S)
@UnsupportedAppUsage
- public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
- this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
+ public NetworkTemplate(int matchRule, String subscriberId, String wifiNetworkKey) {
+ this(matchRule, subscriberId, new String[] { subscriberId }, wifiNetworkKey);
}
/** @hide */
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
- String networkId) {
+ String wifiNetworkKey) {
// Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates
// to metered networks. It is now possible to match mobile with any meteredness, but
// in order to preserve backward compatibility of @UnsupportedAppUsage methods, this
//constructor passes METERED_YES for these types.
- this(matchRule, subscriberId, matchSubscriberIds, networkId,
+ this(matchRule, subscriberId, matchSubscriberIds,
+ wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0],
(matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES
: METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
- OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
/** @hide */
// TODO: Remove it after updating all of the caller.
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
- String networkId, int metered, int roaming, int defaultNetwork, int subType,
+ String wifiNetworkKey, int metered, int roaming, int defaultNetwork, int subType,
int oemManaged) {
- this(matchRule, subscriberId, matchSubscriberIds, networkId, metered, roaming,
- defaultNetwork, subType, oemManaged, SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ this(matchRule, subscriberId, matchSubscriberIds,
+ wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0],
+ metered, roaming, defaultNetwork, subType, oemManaged,
+ NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
/** @hide */
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
- String networkId, int metered, int roaming, int defaultNetwork, int subType,
- int oemManaged, int subscriberIdMatchRule) {
+ String[] matchWifiNetworkKeys, int metered, int roaming,
+ int defaultNetwork, int subType, int oemManaged, int subscriberIdMatchRule) {
+ Objects.requireNonNull(matchWifiNetworkKeys);
mMatchRule = matchRule;
mSubscriberId = subscriberId;
// TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when
// mSubscriberId is null
mMatchSubscriberIds = matchSubscriberIds;
- mNetworkId = networkId;
+ mMatchWifiNetworkKeys = matchWifiNetworkKeys;
mMetered = metered;
mRoaming = roaming;
mDefaultNetwork = defaultNetwork;
@@ -450,7 +446,7 @@
mMatchRule = in.readInt();
mSubscriberId = in.readString();
mMatchSubscriberIds = in.createStringArray();
- mNetworkId = in.readString();
+ mMatchWifiNetworkKeys = in.createStringArray();
mMetered = in.readInt();
mRoaming = in.readInt();
mDefaultNetwork = in.readInt();
@@ -464,7 +460,7 @@
dest.writeInt(mMatchRule);
dest.writeString(mSubscriberId);
dest.writeStringArray(mMatchSubscriberIds);
- dest.writeString(mNetworkId);
+ dest.writeStringArray(mMatchWifiNetworkKeys);
dest.writeInt(mMetered);
dest.writeInt(mRoaming);
dest.writeInt(mDefaultNetwork);
@@ -490,9 +486,7 @@
builder.append(", matchSubscriberIds=").append(
Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds)));
}
- if (mNetworkId != null) {
- builder.append(", networkId=").append(mNetworkId);
- }
+ builder.append(", matchWifiNetworkKeys=").append(Arrays.toString(mMatchWifiNetworkKeys));
if (mMetered != METERED_ALL) {
builder.append(", metered=").append(NetworkStats.meteredToString(mMetered));
}
@@ -516,8 +510,8 @@
@Override
public int hashCode() {
- return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming,
- mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule);
+ return Objects.hash(mMatchRule, mSubscriberId, Arrays.hashCode(mMatchWifiNetworkKeys),
+ mMetered, mRoaming, mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule);
}
@Override
@@ -526,22 +520,22 @@
final NetworkTemplate other = (NetworkTemplate) obj;
return mMatchRule == other.mMatchRule
&& Objects.equals(mSubscriberId, other.mSubscriberId)
- && Objects.equals(mNetworkId, other.mNetworkId)
&& mMetered == other.mMetered
&& mRoaming == other.mRoaming
&& mDefaultNetwork == other.mDefaultNetwork
&& mSubType == other.mSubType
&& mOemManaged == other.mOemManaged
- && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule;
+ && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule
+ && Arrays.equals(mMatchWifiNetworkKeys, other.mMatchWifiNetworkKeys);
}
return false;
}
private static String subscriberIdMatchRuleToString(int rule) {
switch (rule) {
- case SUBSCRIBER_ID_MATCH_RULE_EXACT:
+ case NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT:
return "EXACT_MATCH";
- case SUBSCRIBER_ID_MATCH_RULE_ALL:
+ case NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL:
return "ALL";
default:
return "Unknown rule " + rule;
@@ -560,30 +554,6 @@
}
/**
- * Check if the template can be persisted into disk.
- *
- * @hide
- */
- // TODO: Move to the NetworkPolicy.
- public boolean isPersistable() {
- switch (mMatchRule) {
- case MATCH_MOBILE_WILDCARD:
- case MATCH_WIFI_WILDCARD:
- return false;
- case MATCH_CARRIER:
- return mSubscriberId != null;
- case MATCH_WIFI:
- if (Objects.equals(mNetworkId, WIFI_NETWORK_KEY_ALL)
- && mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) {
- return false;
- }
- return true;
- default:
- return true;
- }
- }
-
- /**
* Get match rule of the template. See {@code MATCH_*}.
*/
@UnsupportedAppUsage
@@ -622,23 +592,22 @@
*/
@Nullable
public String getWifiNetworkKey() {
- return mNetworkId;
+ return CollectionUtils.isEmpty(mMatchWifiNetworkKeys) ? null : mMatchWifiNetworkKeys[0];
+ }
+
+ /**
+ * Get set of Wifi Network Keys of the template.
+ */
+ @Nullable
+ public Set<String> getWifiNetworkKeys() {
+ return new ArraySet<>(Arrays.asList(mMatchWifiNetworkKeys));
}
/** @hide */
// TODO: Remove this and replace all callers with {@link #getWifiNetworkKey()}.
@Nullable
public String getNetworkId() {
- return mNetworkId;
- }
-
- /**
- * Get Subscriber Id Match Rule of the template.
- *
- * @hide
- */
- public int getSubscriberIdMatchRule() {
- return mSubscriberIdMatchRule;
+ return getWifiNetworkKey();
}
/**
@@ -754,29 +723,34 @@
* @hide
*/
public boolean matchesSubscriberId(@Nullable String subscriberId) {
- return mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL
- || ArrayUtils.contains(mMatchSubscriberIds, subscriberId);
+ return mSubscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL
+ || CollectionUtils.contains(mMatchSubscriberIds, subscriberId);
}
/**
- * Check if network with matching SSID. Returns true when the SSID matches, or when
- * {@code mNetworkId} is {@code WIFI_NETWORK_KEY_ALL}.
+ * Check if network matches key of the wifi network.
+ * Returns true when the key matches, or when {@code mMatchWifiNetworkKeys} is
+ * empty.
+ *
+ * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()}
+ * to know details about the key.
*/
- private boolean matchesWifiNetworkId(@Nullable String networkId) {
- return Objects.equals(mNetworkId, WIFI_NETWORK_KEY_ALL)
- || Objects.equals(sanitizeSsid(mNetworkId), sanitizeSsid(networkId));
+ private boolean matchesWifiNetworkKey(@NonNull String wifiNetworkKey) {
+ Objects.requireNonNull(wifiNetworkKey);
+ return CollectionUtils.isEmpty(mMatchWifiNetworkKeys)
+ || CollectionUtils.contains(mMatchWifiNetworkKeys, wifiNetworkKey);
}
/**
- * Check if mobile network with matching IMSI.
+ * Check if mobile network matches IMSI.
*/
private boolean matchesMobile(NetworkIdentity ident) {
if (ident.mType == TYPE_WIMAX) {
// TODO: consider matching against WiMAX subscriber identity
return true;
} else {
- return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds)
- && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
+ return ident.mType == TYPE_MOBILE && !CollectionUtils.isEmpty(mMatchSubscriberIds)
+ && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
&& matchesCollapsedRatType(ident);
}
}
@@ -866,7 +840,7 @@
switch (ident.mType) {
case TYPE_WIFI:
return matchesSubscriberId(ident.mSubscriberId)
- && matchesWifiNetworkId(ident.mNetworkId);
+ && matchesWifiNetworkKey(ident.mNetworkId);
default:
return false;
}
@@ -887,8 +861,8 @@
*/
private boolean matchesCarrier(NetworkIdentity ident) {
return ident.mSubscriberId != null
- && !ArrayUtils.isEmpty(mMatchSubscriberIds)
- && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
+ && !CollectionUtils.isEmpty(mMatchSubscriberIds)
+ && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
}
private boolean matchesMobileWildcard(NetworkIdentity ident) {
@@ -1005,11 +979,13 @@
if (template.mSubscriberId == null) return template;
for (String[] merged : mergedList) {
- if (ArrayUtils.contains(merged, template.mSubscriberId)) {
+ if (CollectionUtils.contains(merged, template.mSubscriberId)) {
// Requested template subscriber is part of the merge group; return
// a template that matches all merged subscribers.
+ final String[] matchWifiNetworkKeys = template.mMatchWifiNetworkKeys;
return new NetworkTemplate(template.mMatchRule, merged[0], merged,
- template.mNetworkId);
+ CollectionUtils.isEmpty(matchWifiNetworkKeys)
+ ? null : matchWifiNetworkKeys[0]);
}
}
@@ -1036,9 +1012,10 @@
private final int mMatchRule;
// Use a SortedSet to provide a deterministic order when fetching the first one.
@NonNull
- private final SortedSet<String> mMatchSubscriberIds = new TreeSet<>();
- @Nullable
- private String mWifiNetworkKey;
+ private final SortedSet<String> mMatchSubscriberIds =
+ new TreeSet<>(Comparator.nullsFirst(Comparator.naturalOrder()));
+ @NonNull
+ private final SortedSet<String> mMatchWifiNetworkKeys = new TreeSet<>();
// Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*.
private int mMetered;
@@ -1058,7 +1035,6 @@
assertRequestableMatchRule(matchRule);
// Initialize members with default values.
mMatchRule = matchRule;
- mWifiNetworkKey = WIFI_NETWORK_KEY_ALL;
mMetered = METERED_ALL;
mRoaming = ROAMING_ALL;
mDefaultNetwork = DEFAULT_NETWORK_ALL;
@@ -1082,15 +1058,28 @@
}
/**
- * Set the Wifi Network Key.
+ * Set the Wifi Network Keys. Calling this function with an empty set represents
+ * the intention of matching any Wifi Network Key.
*
- * @param wifiNetworkKey the Wifi Network Key, see {@link WifiInfo#getCurrentNetworkKey()}.
- * Or null to match all networks.
+ * @param wifiNetworkKeys the list of Wifi Network Key,
+ * see {@link WifiInfo#getCurrentNetworkKey()}.
+ * Or an empty list to match all networks.
+ * Note that {@code getCurrentNetworkKey()} might get null key
+ * when wifi disconnects. However, the caller should never invoke
+ * this function with a null Wifi Network Key since such statistics
+ * never exists.
* @return this builder.
*/
@NonNull
- public Builder setWifiNetworkKey(@Nullable String wifiNetworkKey) {
- mWifiNetworkKey = wifiNetworkKey;
+ public Builder setWifiNetworkKeys(@NonNull Set<String> wifiNetworkKeys) {
+ Objects.requireNonNull(wifiNetworkKeys);
+ for (String key : wifiNetworkKeys) {
+ if (key == null) {
+ throw new IllegalArgumentException("Null is not a valid key");
+ }
+ }
+ mMatchWifiNetworkKeys.clear();
+ mMatchWifiNetworkKeys.addAll(wifiNetworkKeys);
return this;
}
@@ -1174,9 +1163,17 @@
}
private void assertRequestableParameters() {
+ validateWifiNetworkKeys();
// TODO: Check all the input are legitimate.
}
+ private void validateWifiNetworkKeys() {
+ if (mMatchRule != MATCH_WIFI && !mMatchWifiNetworkKeys.isEmpty()) {
+ throw new IllegalArgumentException("Trying to build non wifi match rule: "
+ + mMatchRule + " with wifi network keys");
+ }
+ }
+
/**
* For backward compatibility, deduce match rule to a wildcard match rule
* if the Subscriber Ids are empty.
@@ -1185,7 +1182,7 @@
if (mMatchRule == MATCH_MOBILE && mMatchSubscriberIds.isEmpty()) {
return MATCH_MOBILE_WILDCARD;
} else if (mMatchRule == MATCH_WIFI && mMatchSubscriberIds.isEmpty()
- && mWifiNetworkKey == WIFI_NETWORK_KEY_ALL) {
+ && mMatchWifiNetworkKeys.isEmpty()) {
return MATCH_WIFI_WILDCARD;
}
return mMatchRule;
@@ -1200,12 +1197,13 @@
public NetworkTemplate build() {
assertRequestableParameters();
final int subscriberIdMatchRule = mMatchSubscriberIds.isEmpty()
- ? SUBSCRIBER_ID_MATCH_RULE_ALL : SUBSCRIBER_ID_MATCH_RULE_EXACT;
+ ? NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL
+ : NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT;
return new NetworkTemplate(getWildcardDeducedMatchRule(),
mMatchSubscriberIds.isEmpty() ? null : mMatchSubscriberIds.iterator().next(),
mMatchSubscriberIds.toArray(new String[0]),
- mWifiNetworkKey, mMetered, mRoaming, mDefaultNetwork, mRatType, mOemManaged,
- subscriberIdMatchRule);
+ mMatchWifiNetworkKeys.toArray(new String[0]), mMetered, mRoaming,
+ mDefaultNetwork, mRatType, mOemManaged, subscriberIdMatchRule);
}
}
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
index fa65061..d8feb88 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
@@ -29,7 +29,6 @@
import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.util.DataUnit;
import com.android.server.NetworkManagementSocketTagger;
@@ -59,19 +58,19 @@
*/
public final static int UNSUPPORTED = -1;
- /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */
+ /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
@Deprecated
public static final long KB_IN_BYTES = 1024;
- /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */
+ /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
@Deprecated
public static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
- /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */
+ /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
@Deprecated
public static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
- /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */
+ /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
@Deprecated
public static final long TB_IN_BYTES = GB_IN_BYTES * 1024;
- /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */
+ /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */
@Deprecated
public static final long PB_IN_BYTES = TB_IN_BYTES * 1024;
diff --git a/packages/ConnectivityT/service/Android.bp b/packages/ConnectivityT/service/Android.bp
index 97dfb64..b261e16 100644
--- a/packages/ConnectivityT/service/Android.bp
+++ b/packages/ConnectivityT/service/Android.bp
@@ -82,8 +82,18 @@
":services.connectivity-ethernet-sources",
":services.connectivity-ipsec-sources",
":services.connectivity-netstats-sources",
- ":services.connectivity-nsd-sources",
],
path: "src",
visibility: ["//frameworks/base/services/core"],
}
+
+filegroup {
+ name: "services.connectivity-tiramisu-updatable-sources",
+ srcs: [
+ ":services.connectivity-nsd-sources",
+ ],
+ path: "src",
+ visibility: [
+ "//packages/modules/Connectivity:__subpackages__",
+ ],
+}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
index e6433db..c7c8893 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
@@ -35,8 +35,8 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ProcFileReader;
+import com.android.net.module.util.CollectionUtils;
import libcore.io.IoUtils;
@@ -434,7 +434,7 @@
entry.txBytes = reader.nextLong();
entry.txPackets = reader.nextLong();
- if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface))
+ if ((limitIfaces == null || CollectionUtils.contains(limitIfaces, entry.iface))
&& (limitUid == UID_ALL || limitUid == entry.uid)
&& (limitTag == TAG_ALL || limitTag == entry.tag)) {
stats.insertEntry(entry);
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java
index 1a0866d..b57a4f9 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java
@@ -18,8 +18,6 @@
import static android.app.usage.NetworkStatsManager.MIN_THRESHOLD_BYTES;
-import static com.android.internal.util.Preconditions.checkArgument;
-
import android.app.usage.NetworkStatsManager;
import android.net.DataUsageRequest;
import android.net.NetworkIdentitySet;
@@ -38,7 +36,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.util.ArrayMap;
-import android.util.Slog;
+import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
@@ -83,7 +81,7 @@
RequestInfo requestInfo = buildRequestInfo(request, messenger, binder, callingUid,
accessLevel);
- if (LOGV) Slog.v(TAG, "Registering observer for " + request);
+ if (LOGV) Log.v(TAG, "Registering observer for " + request);
getHandler().sendMessage(mHandler.obtainMessage(MSG_REGISTER, requestInfo));
return request;
}
@@ -116,7 +114,7 @@
if (mHandler == null) {
synchronized (this) {
if (mHandler == null) {
- if (LOGV) Slog.v(TAG, "Creating handler");
+ if (LOGV) Log.v(TAG, "Creating handler");
mHandler = new Handler(getHandlerLooperLocked(), mHandlerCallback);
}
}
@@ -172,15 +170,15 @@
RequestInfo requestInfo;
requestInfo = mDataUsageRequests.get(request.requestId);
if (requestInfo == null) {
- if (LOGV) Slog.v(TAG, "Trying to unregister unknown request " + request);
+ if (LOGV) Log.v(TAG, "Trying to unregister unknown request " + request);
return;
}
if (Process.SYSTEM_UID != callingUid && requestInfo.mCallingUid != callingUid) {
- Slog.w(TAG, "Caller uid " + callingUid + " is not owner of " + request);
+ Log.w(TAG, "Caller uid " + callingUid + " is not owner of " + request);
return;
}
- if (LOGV) Slog.v(TAG, "Unregistering " + request);
+ if (LOGV) Log.v(TAG, "Unregistering " + request);
mDataUsageRequests.remove(request.requestId);
requestInfo.unlinkDeathRecipient();
requestInfo.callCallback(NetworkStatsManager.CALLBACK_RELEASED);
@@ -201,7 +199,7 @@
// Cap the minimum threshold to a safe default to avoid too many callbacks
long thresholdInBytes = Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes);
if (thresholdInBytes < request.thresholdInBytes) {
- Slog.w(TAG, "Threshold was too low for " + request
+ Log.w(TAG, "Threshold was too low for " + request
+ ". Overriding to a safer default of " + thresholdInBytes + " bytes");
}
return new DataUsageRequest(mNextDataUsageRequestId.incrementAndGet(),
@@ -216,7 +214,10 @@
accessLevel);
} else {
// Safety check in case a new access level is added and we forgot to update this
- checkArgument(accessLevel >= NetworkStatsAccess.Level.DEVICESUMMARY);
+ if (accessLevel < NetworkStatsAccess.Level.DEVICESUMMARY) {
+ throw new IllegalArgumentException(
+ "accessLevel " + accessLevel + " is less than DEVICESUMMARY.");
+ }
return new NetworkUsageRequestInfo(this, request, messenger, binder, callingUid,
accessLevel);
}
@@ -255,8 +256,9 @@
@Override
public void binderDied() {
- if (LOGV) Slog.v(TAG, "RequestInfo binderDied("
- + mRequest + ", " + mBinder + ")");
+ if (LOGV) {
+ Log.v(TAG, "RequestInfo binderDied(" + mRequest + ", " + mBinder + ")");
+ }
mStatsObserver.unregister(mRequest, Process.SYSTEM_UID);
callCallback(NetworkStatsManager.CALLBACK_RELEASED);
}
@@ -299,13 +301,13 @@
msg.setData(bundle);
try {
if (LOGV) {
- Slog.v(TAG, "sending notification " + callbackTypeToName(callbackType)
+ Log.v(TAG, "sending notification " + callbackTypeToName(callbackType)
+ " for " + mRequest);
}
mMessenger.send(msg);
} catch (RemoteException e) {
// May occur naturally in the race of binder death.
- Slog.w(TAG, "RemoteException caught trying to send a callback msg for " + mRequest);
+ Log.w(TAG, "RemoteException caught trying to send a callback msg for " + mRequest);
}
}
@@ -341,7 +343,7 @@
protected boolean checkStats() {
long bytesSoFar = getTotalBytesForNetwork(mRequest.template);
if (LOGV) {
- Slog.v(TAG, bytesSoFar + " bytes so far since notification for "
+ Log.v(TAG, bytesSoFar + " bytes so far since notification for "
+ mRequest.template);
}
if (bytesSoFar > mRequest.thresholdInBytes) {
@@ -416,7 +418,7 @@
return history.getTotalBytes();
} catch (SecurityException e) {
if (LOGV) {
- Slog.w(TAG, "CallerUid " + mCallingUid + " may have lost access to uid "
+ Log.w(TAG, "CallerUid " + mCallingUid + " may have lost access to uid "
+ uid);
}
return 0;
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
index 5e27c77..c371f08 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
@@ -32,15 +32,12 @@
import android.os.Binder;
import android.os.DropBoxManager;
import android.service.NetworkStatsRecorderProto;
+import android.util.IndentingPrintWriter;
import android.util.Log;
-import android.util.MathUtils;
-import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.util.FileRotator;
-import com.android.internal.util.IndentingPrintWriter;
-
-import com.google.android.collect.Sets;
+import com.android.net.module.util.NetworkStatsUtils;
import libcore.io.IoUtils;
@@ -132,8 +129,8 @@
}
public void setPersistThreshold(long thresholdBytes) {
- if (LOGV) Slog.v(TAG, "setPersistThreshold() with " + thresholdBytes);
- mPersistThresholdBytes = MathUtils.constrain(
+ if (LOGV) Log.v(TAG, "setPersistThreshold() with " + thresholdBytes);
+ mPersistThresholdBytes = NetworkStatsUtils.constrain(
thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES);
}
@@ -185,7 +182,7 @@
}
private NetworkStatsCollection loadLocked(long start, long end) {
- if (LOGD) Slog.d(TAG, "loadLocked() reading from disk for " + mCookie);
+ if (LOGD) Log.d(TAG, "loadLocked() reading from disk for " + mCookie);
final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration);
try {
mRotator.readMatching(res, start, end);
@@ -207,7 +204,7 @@
*/
public void recordSnapshotLocked(NetworkStats snapshot,
Map<String, NetworkIdentitySet> ifaceIdent, long currentTimeMillis) {
- final HashSet<String> unknownIfaces = Sets.newHashSet();
+ final HashSet<String> unknownIfaces = new HashSet<>();
// skip recording when snapshot missing
if (snapshot == null) return;
@@ -272,7 +269,7 @@
mLastSnapshot = snapshot;
if (LOGV && unknownIfaces.size() > 0) {
- Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats");
+ Log.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats");
}
}
@@ -296,7 +293,7 @@
public void forcePersistLocked(long currentTimeMillis) {
Objects.requireNonNull(mRotator, "missing FileRotator");
if (mPending.isDirty()) {
- if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
+ if (LOGD) Log.d(TAG, "forcePersistLocked() writing for " + mCookie);
try {
mRotator.rewriteActive(mPendingRewriter, currentTimeMillis);
mRotator.maybeRotate(currentTimeMillis);
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
index 2beca73..a3de9e4 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
@@ -25,7 +25,6 @@
import static android.content.Intent.EXTRA_UID;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.NetworkIdentity.SUBTYPE_COMBINED;
-import static android.net.NetworkStack.checkNetworkStackPermission;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.IFACE_VT;
@@ -141,28 +140,29 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
+import android.util.IndentingPrintWriter;
import android.util.Log;
-import android.util.MathUtils;
-import android.util.Slog;
import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.DumpUtils;
import com.android.internal.util.FileRotator;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.net.module.util.BinderUtils;
+import com.android.net.module.util.CollectionUtils;
+import com.android.net.module.util.NetworkStatsUtils;
+import com.android.net.module.util.PermissionUtils;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.time.Clock;
import java.time.ZoneOffset;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -646,7 +646,7 @@
try {
mNetworkManager.setGlobalAlert(mGlobalAlertBytes);
} catch (IllegalStateException e) {
- Slog.w(TAG, "problem registering for global alert: " + e);
+ Log.w(TAG, "problem registering for global alert: " + e);
} catch (RemoteException e) {
// ignored; service lives in system_server
}
@@ -655,8 +655,6 @@
@Override
public INetworkStatsSession openSession() {
- // NOTE: if callers want to get non-augmented data, they should go
- // through the public API
return openSessionInternal(NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, null);
}
@@ -766,7 +764,7 @@
return stats;
} catch (NullPointerException e) {
// TODO: Track down and fix the cause of this crash and remove this catch block.
- Slog.wtf(TAG, "NullPointerException in getSummaryForAllUid", e);
+ Log.wtf(TAG, "NullPointerException in getSummaryForAllUid", e);
throw e;
}
}
@@ -811,7 +809,7 @@
private @NetworkStatsAccess.Level int checkAccessLevel(String callingPackage) {
return NetworkStatsAccess.checkAccessLevel(
- mContext, Binder.getCallingUid(), callingPackage);
+ mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage);
}
/**
@@ -823,7 +821,7 @@
SubscriptionPlan plan = null;
if ((flags & NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN) != 0
&& mSettings.getAugmentEnabled()) {
- if (LOGD) Slog.d(TAG, "Resolving plan for " + template);
+ if (LOGD) Log.d(TAG, "Resolving plan for " + template);
final long token = Binder.clearCallingIdentity();
try {
plan = LocalServices.getService(NetworkPolicyManagerInternal.class)
@@ -831,7 +829,7 @@
} finally {
Binder.restoreCallingIdentity(token);
}
- if (LOGD) Slog.d(TAG, "Resolved to plan " + plan);
+ if (LOGD) Log.d(TAG, "Resolved to plan " + plan);
}
return plan;
}
@@ -876,8 +874,6 @@
private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
assertSystemReady();
- // NOTE: if callers want to get non-augmented data, they should go
- // through the public API
return internalGetSummaryForNetwork(template,
NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, start, end,
NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotalBytes();
@@ -936,7 +932,7 @@
@Override
public String[] getMobileIfaces() {
// TODO (b/192758557): Remove debug log.
- if (ArrayUtils.contains(mMobileIfaces, null)) {
+ if (CollectionUtils.contains(mMobileIfaces, null)) {
throw new NullPointerException(
"null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces));
}
@@ -985,7 +981,7 @@
@NonNull NetworkStateSnapshot[] networkStates,
@Nullable String activeIface,
@NonNull UnderlyingNetworkInfo[] underlyingNetworkInfos) {
- checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
final long token = Binder.clearCallingIdentity();
try {
@@ -1014,9 +1010,10 @@
private void advisePersistThreshold(long thresholdBytes) {
// clamp threshold into safe range
- mPersistThreshold = MathUtils.constrain(thresholdBytes, 128 * KB_IN_BYTES, 2 * MB_IN_BYTES);
+ mPersistThreshold = NetworkStatsUtils.constrain(thresholdBytes,
+ 128 * KB_IN_BYTES, 2 * MB_IN_BYTES);
if (LOGV) {
- Slog.v(TAG, "advisePersistThreshold() given " + thresholdBytes + ", clamped to "
+ Log.v(TAG, "advisePersistThreshold() given " + thresholdBytes + ", clamped to "
+ mPersistThreshold);
}
@@ -1200,13 +1197,13 @@
// On background handler thread, and USER_REMOVED is protected
// broadcast.
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (userId == -1) return;
+ final UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER);
+ if (userHandle == null) return;
synchronized (mStatsLock) {
mWakeLock.acquire();
try {
- removeUserLocked(userId);
+ removeUserLocked(userHandle);
} finally {
mWakeLock.release();
}
@@ -1231,7 +1228,7 @@
@Override
public void limitReached(String limitName, String iface) {
// only someone like NMS should be calling us
- NetworkStack.checkNetworkStackPermission(mContext);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
if (LIMIT_GLOBAL_ALERT.equals(limitName)) {
// kick off background poll to collect network stats unless there is already
@@ -1279,7 +1276,7 @@
private void handleNotifyNetworkStatusLocked(@NonNull Network[] defaultNetworks,
@NonNull NetworkStateSnapshot[] snapshots) {
if (!mSystemReady) return;
- if (LOGV) Slog.v(TAG, "handleNotifyNetworkStatusLocked()");
+ if (LOGV) Log.v(TAG, "handleNotifyNetworkStatusLocked()");
// take one last stats snapshot before updating iface mapping. this
// isn't perfect, since the kernel may already be counting traffic from
@@ -1303,7 +1300,8 @@
final int displayTransport =
getDisplayTransport(snapshot.getNetworkCapabilities().getTransportTypes());
final boolean isMobile = (NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport);
- final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.getNetwork());
+ final boolean isDefault = CollectionUtils.contains(
+ mDefaultNetworks, snapshot.getNetwork());
final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED
: getSubTypeForStateSnapshot(snapshot);
final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot,
@@ -1386,7 +1384,7 @@
mMobileIfaces = mobileIfaces.toArray(new String[0]);
// TODO (b/192758557): Remove debug log.
- if (ArrayUtils.contains(mMobileIfaces, null)) {
+ if (CollectionUtils.contains(mMobileIfaces, null)) {
throw new NullPointerException(
"null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces));
}
@@ -1401,7 +1399,7 @@
if (spec instanceof TelephonyNetworkSpecifier) {
return ((TelephonyNetworkSpecifier) spec).getSubscriptionId();
} else {
- Slog.wtf(TAG, "getSubIdForState invalid NetworkSpecifier");
+ Log.wtf(TAG, "getSubIdForState invalid NetworkSpecifier");
return INVALID_SUBSCRIPTION_ID;
}
}
@@ -1485,7 +1483,7 @@
try {
recordSnapshotLocked(currentTime);
} catch (IllegalStateException e) {
- Slog.w(TAG, "problem reading network stats: " + e);
+ Log.w(TAG, "problem reading network stats: " + e);
} catch (RemoteException e) {
// ignored; service lives in system_server
}
@@ -1510,7 +1508,7 @@
@GuardedBy("mStatsLock")
private void performPollLocked(int flags) {
if (!mSystemReady) return;
- if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
+ if (LOGV) Log.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
Trace.traceBegin(TRACE_TAG_NETWORK, "performPollLocked");
final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0;
@@ -1632,7 +1630,7 @@
*/
@GuardedBy("mStatsLock")
private void removeUidsLocked(int... uids) {
- if (LOGV) Slog.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids));
+ if (LOGV) Log.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids));
// Perform one last poll before removing
performPollLocked(FLAG_PERSIST_ALL);
@@ -1650,20 +1648,20 @@
* Clean up {@link #mUidRecorder} after user is removed.
*/
@GuardedBy("mStatsLock")
- private void removeUserLocked(int userId) {
- if (LOGV) Slog.v(TAG, "removeUserLocked() for userId=" + userId);
+ private void removeUserLocked(@NonNull UserHandle userHandle) {
+ if (LOGV) Log.v(TAG, "removeUserLocked() for UserHandle=" + userHandle);
// Build list of UIDs that we should clean up
- int[] uids = new int[0];
+ final ArrayList<Integer> uids = new ArrayList<>();
final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
PackageManager.MATCH_ANY_USER
| PackageManager.MATCH_DISABLED_COMPONENTS);
for (ApplicationInfo app : apps) {
- final int uid = UserHandle.getUid(userId, app.uid);
- uids = ArrayUtils.appendInt(uids, uid);
+ final int uid = userHandle.getUid(app.uid);
+ uids.add(uid);
}
- removeUidsLocked(uids);
+ removeUidsLocked(CollectionUtils.toIntArray(uids));
}
private class NetworkStatsManagerInternalImpl extends NetworkStatsManagerInternal {
@@ -1706,7 +1704,7 @@
public void setStatsProviderWarningAndLimitAsync(
@NonNull String iface, long warning, long limit) {
if (LOGV) {
- Slog.v(TAG, "setStatsProviderWarningAndLimitAsync("
+ Log.v(TAG, "setStatsProviderWarningAndLimitAsync("
+ iface + "," + warning + "," + limit + ")");
}
invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface,
@@ -1716,7 +1714,7 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter rawWriter, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, rawWriter)) return;
+ if (!PermissionUtils.checkDumpPermission(mContext, TAG, rawWriter)) return;
long duration = DateUtils.DAY_IN_MILLIS;
final HashSet<String> argSet = new HashSet<String>();
@@ -1777,15 +1775,15 @@
pw.println("Configs:");
pw.increaseIndent();
- pw.printPair(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled());
+ pw.print(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled());
pw.println();
pw.decreaseIndent();
pw.println("Active interfaces:");
pw.increaseIndent();
for (int i = 0; i < mActiveIfaces.size(); i++) {
- pw.printPair("iface", mActiveIfaces.keyAt(i));
- pw.printPair("ident", mActiveIfaces.valueAt(i));
+ pw.print("iface", mActiveIfaces.keyAt(i));
+ pw.print("ident", mActiveIfaces.valueAt(i));
pw.println();
}
pw.decreaseIndent();
@@ -1793,8 +1791,8 @@
pw.println("Active UID interfaces:");
pw.increaseIndent();
for (int i = 0; i < mActiveUidIfaces.size(); i++) {
- pw.printPair("iface", mActiveUidIfaces.keyAt(i));
- pw.printPair("ident", mActiveUidIfaces.valueAt(i));
+ pw.print("iface", mActiveUidIfaces.keyAt(i));
+ pw.print("ident", mActiveUidIfaces.valueAt(i));
pw.println();
}
pw.decreaseIndent();
@@ -1867,7 +1865,7 @@
@GuardedBy("mStatsLock")
private void dumpProtoLocked(FileDescriptor fd) {
- final ProtoOutputStream proto = new ProtoOutputStream(fd);
+ final ProtoOutputStream proto = new ProtoOutputStream(new FileOutputStream(fd));
// TODO Right now it writes all history. Should it limit to the "since-boot" log?
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
index 5646c75..93d0ae7 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
@@ -33,7 +33,7 @@
import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.CollectionUtils;
+import com.android.net.module.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
@@ -99,18 +99,19 @@
// prevent binder call to telephony when querying RAT. Keep listener registration with empty
// IMSI is meaningless since the RAT type changed is ambiguous for multi-SIM if reported
// with empty IMSI. So filter the subs w/o a valid IMSI to prevent such registration.
- final List<Pair<Integer, String>> filteredNewSubs =
- CollectionUtils.mapNotNull(newSubs, subId -> {
- final String subscriberId = mTeleManager.getSubscriberId(subId);
- return TextUtils.isEmpty(subscriberId) ? null : new Pair(subId, subscriberId);
- });
+ final List<Pair<Integer, String>> filteredNewSubs = new ArrayList<>();
+ for (final int subId : newSubs) {
+ final String subscriberId = mTeleManager.getSubscriberId(subId);
+ if (!TextUtils.isEmpty(subscriberId)) {
+ filteredNewSubs.add(new Pair(subId, subscriberId));
+ }
+ }
for (final Pair<Integer, String> sub : filteredNewSubs) {
// Fully match listener with subId and IMSI, since in some rare cases, IMSI might be
// suddenly change regardless of subId, such as switch IMSI feature in modem side.
// If that happens, register new listener with new IMSI and remove old one later.
- if (CollectionUtils.find(mRatListeners,
- it -> it.equalsKey(sub.first, sub.second)) != null) {
+ if (CollectionUtils.any(mRatListeners, it -> it.equalsKey(sub.first, sub.second))) {
continue;
}
@@ -126,8 +127,8 @@
for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) {
// If there is no subId and IMSI matched the listener, removes it.
- if (CollectionUtils.find(filteredNewSubs,
- it -> listener.equalsKey(it.first, it.second)) == null) {
+ if (!CollectionUtils.any(filteredNewSubs,
+ it -> listener.equalsKey(it.first, it.second))) {
handleRemoveRatTypeListener(listener);
}
}
@@ -148,9 +149,10 @@
* @return collapsed RatType for the given subscriberId
*/
public int getRatTypeForSubscriberId(@NonNull String subscriberId) {
- final RatTypeListener match = CollectionUtils.find(mRatListeners,
+ final int index = CollectionUtils.indexOf(mRatListeners,
it -> TextUtils.equals(subscriberId, it.mSubscriberId));
- return match != null ? match.mLastCollapsedRatType : TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ return index != -1 ? mRatListeners.get(index).mLastCollapsedRatType
+ : TelephonyManager.NETWORK_TYPE_UNKNOWN;
}
/**
diff --git a/packages/InputDevices/res/values-it/strings.xml b/packages/InputDevices/res/values-it/strings.xml
index ed1ec55..a992b86 100644
--- a/packages/InputDevices/res/values-it/strings.xml
+++ b/packages/InputDevices/res/values-it/strings.xml
@@ -4,11 +4,11 @@
<string name="app_label" msgid="8016145283189546017">"Dispositivi di immissione"</string>
<string name="keyboard_layouts_label" msgid="6688773268302087545">"Tastiera Android"</string>
<string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"Inglese (UK)"</string>
- <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"Inglese (USA)"</string>
- <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglese (USA), stile internazionale"</string>
- <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglese (USA), stile Colemak"</string>
- <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglese (USA), stile Dvorak"</string>
- <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inglese (USA), stile Workman"</string>
+ <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"Inglese (US)"</string>
+ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglese (US), stile internazionale"</string>
+ <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglese (US), stile Colemak"</string>
+ <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglese (US), stile Dvorak"</string>
+ <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inglese (US), stile Workman"</string>
<string name="keyboard_layout_german_label" msgid="8451565865467909999">"Tedesco"</string>
<string name="keyboard_layout_french_label" msgid="813450119589383723">"Francese"</string>
<string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francese (Canada)"</string>
diff --git a/packages/InputDevices/res/values-pl/strings.xml b/packages/InputDevices/res/values-pl/strings.xml
index 25a3a90..4d18215 100644
--- a/packages/InputDevices/res/values-pl/strings.xml
+++ b/packages/InputDevices/res/values-pl/strings.xml
@@ -3,51 +3,51 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="8016145283189546017">"Urządzenia wejściowe"</string>
<string name="keyboard_layouts_label" msgid="6688773268302087545">"Klawiatura Android"</string>
- <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"Angielski (Wielka Brytania)"</string>
- <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"Angielski (USA)"</string>
- <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Angielski (USA), międzynarodowy"</string>
- <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Angielski (USA), Colemak"</string>
- <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Angielski (USA), Dvorak"</string>
- <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Angielski (USA), Workman"</string>
- <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Niemiecki"</string>
- <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francuski"</string>
- <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francuski (Kanada)"</string>
- <string name="keyboard_layout_russian_label" msgid="8724879775815042968">"Rosyjski"</string>
- <string name="keyboard_layout_russian_mac_label" msgid="3795866869038264796">"Rosyjski, Mac"</string>
- <string name="keyboard_layout_spanish_label" msgid="7091555148131908240">"Hiszpański"</string>
- <string name="keyboard_layout_swiss_french_label" msgid="4659191025396371684">"Francuski (Szwajcaria)"</string>
- <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Niemiecki (Szwajcaria)"</string>
- <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgijski"</string>
- <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bułgarski"</string>
- <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bułgarski (znaki fonetyczne)"</string>
- <string name="keyboard_layout_italian" msgid="6497079660449781213">"Włoski"</string>
- <string name="keyboard_layout_danish" msgid="8036432066627127851">"Duński"</string>
- <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norweski"</string>
- <string name="keyboard_layout_swedish" msgid="732959109088479351">"Szwedzki"</string>
- <string name="keyboard_layout_finnish" msgid="5585659438924315466">"Fiński"</string>
- <string name="keyboard_layout_croatian" msgid="4172229471079281138">"Chorwacki"</string>
- <string name="keyboard_layout_czech" msgid="1349256901452975343">"Czeski"</string>
- <string name="keyboard_layout_czech_qwerty" msgid="3331402534128515501">"Styl czeskiej klawiatury QWERTY"</string>
- <string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estoński"</string>
- <string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Węgierski"</string>
- <string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Islandzki"</string>
- <string name="keyboard_layout_brazilian" msgid="5117896443147781939">"Brazylijski"</string>
- <string name="keyboard_layout_portuguese" msgid="2888198587329660305">"Portugalski"</string>
- <string name="keyboard_layout_slovak" msgid="2469379934672837296">"Słowacki"</string>
- <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Słoweński"</string>
- <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turecki"</string>
- <string name="keyboard_layout_turkish_f" msgid="9130320856010776018">"Turecka F"</string>
- <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraiński"</string>
+ <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"angielski (Wielka Brytania)"</string>
+ <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"angielski (USA)"</string>
+ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"angielski (USA), międzynarodowy"</string>
+ <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"angielski (USA), Colemak"</string>
+ <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"angielski (USA), Dvorak"</string>
+ <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"angielski (USA), Workman"</string>
+ <string name="keyboard_layout_german_label" msgid="8451565865467909999">"niemiecki"</string>
+ <string name="keyboard_layout_french_label" msgid="813450119589383723">"francuski"</string>
+ <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"francuski (Kanada)"</string>
+ <string name="keyboard_layout_russian_label" msgid="8724879775815042968">"rosyjski"</string>
+ <string name="keyboard_layout_russian_mac_label" msgid="3795866869038264796">"rosyjski, Mac"</string>
+ <string name="keyboard_layout_spanish_label" msgid="7091555148131908240">"hiszpański"</string>
+ <string name="keyboard_layout_swiss_french_label" msgid="4659191025396371684">"francuski (Szwajcaria)"</string>
+ <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"niemiecki (Szwajcaria)"</string>
+ <string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgijski"</string>
+ <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bułgarski"</string>
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"bułgarski (znaki fonetyczne)"</string>
+ <string name="keyboard_layout_italian" msgid="6497079660449781213">"włoski"</string>
+ <string name="keyboard_layout_danish" msgid="8036432066627127851">"duński"</string>
+ <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norweski"</string>
+ <string name="keyboard_layout_swedish" msgid="732959109088479351">"szwedzki"</string>
+ <string name="keyboard_layout_finnish" msgid="5585659438924315466">"fiński"</string>
+ <string name="keyboard_layout_croatian" msgid="4172229471079281138">"chorwacki"</string>
+ <string name="keyboard_layout_czech" msgid="1349256901452975343">"czeski"</string>
+ <string name="keyboard_layout_czech_qwerty" msgid="3331402534128515501">"czeski, QWERTY"</string>
+ <string name="keyboard_layout_estonian" msgid="8775830985185665274">"estoński"</string>
+ <string name="keyboard_layout_hungarian" msgid="4154963661406035109">"węgierski"</string>
+ <string name="keyboard_layout_icelandic" msgid="5836645650912489642">"islandzki"</string>
+ <string name="keyboard_layout_brazilian" msgid="5117896443147781939">"brazylijski"</string>
+ <string name="keyboard_layout_portuguese" msgid="2888198587329660305">"portugalski"</string>
+ <string name="keyboard_layout_slovak" msgid="2469379934672837296">"słowacki"</string>
+ <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"słoweński"</string>
+ <string name="keyboard_layout_turkish" msgid="7736163250907964898">"turecki"</string>
+ <string name="keyboard_layout_turkish_f" msgid="9130320856010776018">"turecki F"</string>
+ <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukraiński"</string>
<string name="keyboard_layout_arabic" msgid="5671970465174968712">"arabski"</string>
<string name="keyboard_layout_greek" msgid="7289253560162386040">"grecki"</string>
<string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrajski"</string>
<string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litewski"</string>
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"hiszpański (Ameryka Łacińska)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"łotewski"</string>
- <string name="keyboard_layout_persian" msgid="3920643161015888527">"Perski"</string>
- <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"Azerski"</string>
- <string name="keyboard_layout_polish" msgid="1121588624094925325">"Polski"</string>
- <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Białoruski"</string>
- <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolski"</string>
- <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Gruziński"</string>
+ <string name="keyboard_layout_persian" msgid="3920643161015888527">"perski"</string>
+ <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"azerski"</string>
+ <string name="keyboard_layout_polish" msgid="1121588624094925325">"polski"</string>
+ <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"białoruski"</string>
+ <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"mongolski"</string>
+ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"gruziński"</string>
</resources>
diff --git a/packages/PackageInstaller/res/values-af/strings.xml b/packages/PackageInstaller/res/values-af/strings.xml
index 48cf339..a6dcd5d 100644
--- a/packages/PackageInstaller/res/values-af/strings.xml
+++ b/packages/PackageInstaller/res/values-af/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Wil jy hierdie program deïnstalleer?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Wil jy hierdie program vir "<b>"alle"</b>" gebruikers deïnstalleer? Die program en sy data sal van "<b>"alle"</b>" gebruikers op hierdie toestel verwyder word."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Wil jy hierdie program vir die gebruiker <xliff:g id="USERNAME">%1$s</xliff:g> deïnstalleer?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Wil jy hierdie program op jou werkprofiel deïnstalleer?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Vervang hierdie program met die fabriekweergawe? Alle data sal verwyder word."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Vervang hierdie program met die fabriekweergawe? Alle data sal verwyder word. Dit beïnvloed alle gebruikers van hierdie toestel, insluitend dié met werkprofiele."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Hou <xliff:g id="SIZE">%1$s</xliff:g> se programdata."</string>
diff --git a/packages/PackageInstaller/res/values-am/strings.xml b/packages/PackageInstaller/res/values-am/strings.xml
index 26d108c..e58923a 100644
--- a/packages/PackageInstaller/res/values-am/strings.xml
+++ b/packages/PackageInstaller/res/values-am/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"ይህን መተግበሪያ ማራገፍ ይፈልጋሉ?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"ይህን መተግበሪያ "<b>"ለሁሉም"</b>" ተጠቃሚዎች መጫን ይፈልጋሉ? መተግበሪያው እና ውሂቡ በመሣሪያው ላይ ካሉ "<b>"ሁሉም"</b>" ተጠቃሚዎች ይሰረዛሉ።"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"ይህን መተግበሪያ ለተጠቃሚ <xliff:g id="USERNAME">%1$s</xliff:g> ማራገፍ ይፈልጋሉ?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ይህን መተግበሪያ ከስራ መገለጫዎ ማራገፍ ይፈልጋሉ?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"ይህ መተግበሪያ በፋብሪካው ስሪት ይተካ? ሁሉም ውሂብ ይወገዳል።"</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ይህ መተግበሪያ በፋብሪካው ስሪት ይተካ? ሁሉም ውሂብ ይወገዳል። እነዚያን የሥራ መገለጫዎች ያላቸውን ጨምሮ ሁሉንም በዚህ መሣሪያ ላይ ባሉ ተጠቃሚዎች ላይ ተጽዕኖ ያሳርፍባቸዋል።"</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"ከመተግበሪያ ውሂብ <xliff:g id="SIZE">%1$s</xliff:g> አቆይ።"</string>
diff --git a/packages/PackageInstaller/res/values-ar/strings.xml b/packages/PackageInstaller/res/values-ar/strings.xml
index af2e19e..2d6fca6 100644
--- a/packages/PackageInstaller/res/values-ar/strings.xml
+++ b/packages/PackageInstaller/res/values-ar/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"هل تريد إزالة هذا التطبيق؟"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"هل تريد إزالة هذا التطبيق "<b>"لكل"</b>" المستخدمين؟ ستتم إزالة التطبيق وبياناته من "<b>"كل"</b>" المستخدمين على هذا الجهاز."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"هل تريد إزالة هذا التطبيق للمستخدم <xliff:g id="USERNAME">%1$s</xliff:g>؟"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"هل تريد إزالة تثبيت هذا التطبيق من ملفك الشخصي للعمل؟"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"هل تريد استبدال هذا التطبيق بإصدار المصنع؟ ستتم إزالة جميع البيانات."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"هل تريد إعادة ضبط هذا التطبيق على الإعدادات الأصلية؟ سؤدي ذلك إلى إزالة جميع البيانات، كما سيؤثر على جميع مستخدمي هذا الجهاز، بما في ذلك من لديهم ملفات شخصية للعمل."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"الاحتفاظ بالحجم <xliff:g id="SIZE">%1$s</xliff:g> من بيانات التطبيق."</string>
diff --git a/packages/PackageInstaller/res/values-as/strings.xml b/packages/PackageInstaller/res/values-as/strings.xml
index 5224101..bde9394 100644
--- a/packages/PackageInstaller/res/values-as/strings.xml
+++ b/packages/PackageInstaller/res/values-as/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"আপুনি এই এপটো আনইনষ্টল কৰিব বিচাৰেনে?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"আপুনি "<b>"সকলো"</b>" ব্যৱহাৰকাৰীৰ বাবে এই এপটো আনইনষ্টল কৰিব বিচাৰেনে? এপ্লিকেশ্বন আৰু ইয়াৰ ডেটা ডিভাইচটোত থকা "<b>"সকলো"</b>" ব্যৱহাৰকাৰীৰ পৰা আঁতৰোৱা হ\'ব৷"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"আপুনি ব্যৱহাৰকাৰীৰ <xliff:g id="USERNAME">%1$s</xliff:g> বাবে এই এপটো আনইনষ্টল কৰিব বিচাৰেনে?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"আপুনি নিজৰ কৰ্মস্থানৰ প্ৰ’ফাইলৰ পৰা এই এপ্টো আনইনষ্টল কৰিব বিচাৰেনে?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"এই এপ্টোৰ ফেক্টৰী সংস্কৰণ ব্যৱহাৰ কৰিব বিচাৰেনে? আটাইবোৰ ডেটা মচা হ\'ব।"</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"এই এপটোৰ ফেক্টৰী সংস্কৰণ ব্যৱহাৰ কৰিব বিচাৰেনে? সকলো ডেটা মচা হ\'ব। কর্মস্থানৰ প্ৰফাইল থকা ব্যৱহাৰকাৰীৰ লগতে ডিভাইচটোৰ সকলো ব্যৱহাৰকাৰীৰ ওপৰত ইয়াৰ প্ৰভাৱ পৰিব।"</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"এপৰ ডেটাৰ <xliff:g id="SIZE">%1$s</xliff:g> ৰাখক"</string>
diff --git a/packages/PackageInstaller/res/values-az/strings.xml b/packages/PackageInstaller/res/values-az/strings.xml
index cbe8783..e4f8541 100644
--- a/packages/PackageInstaller/res/values-az/strings.xml
+++ b/packages/PackageInstaller/res/values-az/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Bu tətbiqi sistemdən silmək istəyirsiniz?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Bu tətbiqi "<b>"bütün"</b>" istifadəçilər üçün silmək istəyirsiz? Tətbiq və onun datası cihazdakı "<b>"bütün"</b>" istifadəçilər üçün silinəcək."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> adlı istifadəçi üçün bu tətbiqi sistemdən silmək istəyirsiniz?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Bu tətbiqi iş profilinizdən silmək istəyirsiniz?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Tətbiq zavod versiyası ilə əvəz olunsun? Bütün data silinəcək."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Tətbiq zavod versiyası ilə əvəz olunsun? Bütün data silinəcək. Bu, iş profilləri daxil olmaqla bu cihazın bütün istifadəçilərinə təsir edir."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Tətbiq datasının <xliff:g id="SIZE">%1$s</xliff:g> hissəsini saxlayın."</string>
diff --git a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
index 31c8bac..4ac089d 100644
--- a/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
+++ b/packages/PackageInstaller/res/values-b+sr+Latn/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Želite li da deinstalirate ovu aplikaciju?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Da li želite da deinstalirate ovu aplikaciju za "<b>"sve"</b>" korisnike? Aplikacija i podaci uz nje biće uklonjeni za "<b>"sve"</b>" korisnike ovog uređaja."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Želite li da deinstalirate ovu aplikaciju za korisnika <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Da li želite da deinstalirate ovu aplikaciju sa poslovnog profila?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Želite li da zamenite ovu aplikaciju fabričkom verzijom? Svi podaci će biti uklonjeni."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Želite li da zamenite ovu aplikaciju fabričkom verzijom? Svi podaci će biti uklonjeni. Ovo utiče na sve korisnike ovog uređaja, uključujući i one sa poslovnim profilima."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Zadrži <xliff:g id="SIZE">%1$s</xliff:g> podataka aplikacije."</string>
diff --git a/packages/PackageInstaller/res/values-be/strings.xml b/packages/PackageInstaller/res/values-be/strings.xml
index 670fad4..8a3fd9f 100644
--- a/packages/PackageInstaller/res/values-be/strings.xml
+++ b/packages/PackageInstaller/res/values-be/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Выдаліць гэту праграму?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Выдаліць гэту праграму для "<b>"ўсіх"</b>" карыстальнікаў? Праграма і яе даныя будуць выдалены для "<b>"ўсіх"</b>" карыстальнікаў прылады."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Хочаце выдаліць гэту праграму для карыстальніка <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Хочаце выдаліць гэту праграму з працоўнага профілю?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Замяніць гэту праграму заводскай версіяй? Усе даныя будуць выдалены."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Замяніць гэту праграму заводскай версіяй? Усе даныя будуць выдалены. Гэта паўплывае на ўсіх карыстальнікаў гэтай прылады, уключаючы карыстальнікаў з працоўнымі профілямі."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Захаваць даныя праграмы (<xliff:g id="SIZE">%1$s</xliff:g>)."</string>
diff --git a/packages/PackageInstaller/res/values-bg/strings.xml b/packages/PackageInstaller/res/values-bg/strings.xml
index 99dfc6d..9bd36e4 100644
--- a/packages/PackageInstaller/res/values-bg/strings.xml
+++ b/packages/PackageInstaller/res/values-bg/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Искате ли да деинсталирате това приложение?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Искате ли да деинсталирате това приложение за "<b>"всички"</b>" потребители? Приложението и данните му ще бъдат премахнати от "<b>"всички"</b>" потребители на устройството."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Искате ли да деинсталирате това приложение за потребителя <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Искате ли да деинсталирате това приложение от служебния си потребителски профил?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Това приложение да се замени ли с фабричната версия? Всички данни ще бъдат премахнати."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Това приложение да се замени ли с фабричната версия? Всички данни ще бъдат премахнати. Промяната ще засегне всеки потребител на устройството, включително тези със служебни потребителски профили."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Запазване на <xliff:g id="SIZE">%1$s</xliff:g> данни от приложението."</string>
diff --git a/packages/PackageInstaller/res/values-bn/strings.xml b/packages/PackageInstaller/res/values-bn/strings.xml
index 0c0dd69..0edb6d6 100644
--- a/packages/PackageInstaller/res/values-bn/strings.xml
+++ b/packages/PackageInstaller/res/values-bn/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"আপনি কি এই অ্যাপটি আনইনস্টল করতে চান?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"আপনি কি "<b>"সব"</b>" ব্যবহারকারীর জন্য এই অ্যাপটিকে আনইনস্টল করতে চান? এই ডিভাইসের "<b>"সব"</b>" ব্যবহারকারীর ডেটা সহ এই অ্যাপ্লিকেশনটি সরিয়ে দেওয়া হবে।"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"আপনি কি <xliff:g id="USERNAME">%1$s</xliff:g>-এর জন্য এই অ্যাপটি আনইনস্টল করতে চান?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"আপনার অফিস প্রোফাইল থেকে এই অ্যাপ আনইনস্টল করতে চান?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"ফ্যাক্টরি ভার্সন দিয়ে এই অ্যাপটিকে বদলাতে চান? সব ডেটা মুছে যাবে।"</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ফ্যাক্টরি ভার্সন দিয়ে এই অ্যাপটিকে বদলাতে চান? সব ডেটা মুছে যাবে। এই ডিভাইসে কাজের প্রোফাইল আছে এমন ব্যবহারকারী সহ সবাই এর দ্বারা প্রভাবিত হবেন।"</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"অ্যাপ ডেটার মধ্যে <xliff:g id="SIZE">%1$s</xliff:g> রেখে দিন।"</string>
diff --git a/packages/PackageInstaller/res/values-bs/strings.xml b/packages/PackageInstaller/res/values-bs/strings.xml
index dc07c02..8602185 100644
--- a/packages/PackageInstaller/res/values-bs/strings.xml
+++ b/packages/PackageInstaller/res/values-bs/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Želite li deinstalirati ovu aplikaciju?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Želite li deinstalirati ovu aplikaciju za "<b>" sve "</b>" korisnike? Aplikacija i njeni podaci će biti uklonjeni iz "<b>" svih "</b>" korisničkih računa na uređaju."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Želite li deinstalirati ovu aplikaciju za korisnika <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Želite li deinstalirati ovu aplikaciju s radnog profila?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Želite li ovu aplikaciju zamijeniti s fabričkom verzijom? Svi podaci će biti uklonjeni."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Želite li ovu aplikaciju zamijeniti s fabričkom verzijom? Svi podaci će biti uklonjeni. To će uticati na sve korisnike uređaja, uključujući i one s radnim profilima."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Zadržati <xliff:g id="SIZE">%1$s</xliff:g> podataka aplikacije."</string>
diff --git a/packages/PackageInstaller/res/values-ca/strings.xml b/packages/PackageInstaller/res/values-ca/strings.xml
index 5efee3c..577ae27 100644
--- a/packages/PackageInstaller/res/values-ca/strings.xml
+++ b/packages/PackageInstaller/res/values-ca/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Vols desinstal·lar aquesta aplicació?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vols desinstal·lar aquesta aplicació per a "<b>"tots"</b>" els usuaris? L\'aplicació i les seves dades se suprimiran per a "<b>"tots"</b>" els usuaris del dispositiu."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Vols desinstal·lar aquesta aplicació per a l\'usuari <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vols desinstal·lar aquesta aplicació del teu perfil de treball?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Vols substituir aquesta aplicació per la versió de fàbrica? Se suprimiran totes les dades."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Vols substituir aquesta aplicació per la versió de fàbrica? Se suprimiran totes les dades. Això afectarà tots els usuaris d\'aquest dispositiu, inclosos els que tinguin un perfil de treball."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Conserva <xliff:g id="SIZE">%1$s</xliff:g> de dades de l\'aplicació."</string>
diff --git a/packages/PackageInstaller/res/values-cs/strings.xml b/packages/PackageInstaller/res/values-cs/strings.xml
index 4bf63c9..bd18421 100644
--- a/packages/PackageInstaller/res/values-cs/strings.xml
+++ b/packages/PackageInstaller/res/values-cs/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Chcete tuto aplikaci odinstalovat?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Chcete tuto aplikaci odinstalovat "<b>"všem"</b>" uživatelům? Aplikace a její údaje budou odstraněny "<b>"všem"</b>" uživatelům tohoto zařízení."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Chcete tuto aplikaci pro uživatele <xliff:g id="USERNAME">%1$s</xliff:g> odinstalovat?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Chcete tuto aplikaci odinstalovat ze svého pracovního profilu?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Chcete tuto aplikaci nahradit tovární verzí? Všechna data budou odstraněna."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Chcete tuto aplikaci nahradit tovární verzí? Všechna data budou odstraněna. Tato akce ovlivní všechny uživatele zařízení, včetně uživatelů s pracovním profilem."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Ponechat data aplikace o velikosti <xliff:g id="SIZE">%1$s</xliff:g>."</string>
diff --git a/packages/PackageInstaller/res/values-da/strings.xml b/packages/PackageInstaller/res/values-da/strings.xml
index 9b711e4..32355ca 100644
--- a/packages/PackageInstaller/res/values-da/strings.xml
+++ b/packages/PackageInstaller/res/values-da/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Vil du afinstallere denne app?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vil du afinstallere denne app for "<b>"alle"</b>" brugere? Appen og dens data fjernes fra "<b>"alle"</b>" brugere på denne enhed."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Vil du afinstallere denne app for brugeren <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vil du afinstallere denne app fra din arbejdsprofil?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Vil du erstatte denne app med fabriksversionen? Alle data fjernes."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Vil du erstatte denne app med fabriksversionen? Alle data fjernes. Dette påvirker alle brugere af denne enhed, bl.a. brugere med arbejdsprofiler."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Behold <xliff:g id="SIZE">%1$s</xliff:g> appdata."</string>
diff --git a/packages/PackageInstaller/res/values-de/strings.xml b/packages/PackageInstaller/res/values-de/strings.xml
index a782fd2..6dc81d0 100644
--- a/packages/PackageInstaller/res/values-de/strings.xml
+++ b/packages/PackageInstaller/res/values-de/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Möchtest du diese App deinstallieren?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Möchtest du diese App für "<b>"alle"</b>" Nutzer entfernen? Die App und alle zugehörigen Daten werden für "<b>"alle"</b>" Nutzer des Geräts entfernt."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Möchtest du diese App für den Nutzer <xliff:g id="USERNAME">%1$s</xliff:g> deinstallieren?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Möchtest du diese App aus deinem Arbeitsprofil deinstallieren?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Diese App durch die Werksversion ersetzen? Alle Daten werden entfernt."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Diese App durch die Werksversion ersetzen? Alle Daten werden entfernt. Dies betrifft alle Nutzer des Geräts, einschließlich Arbeitsprofilen."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> an App-Daten behalten."</string>
diff --git a/packages/PackageInstaller/res/values-el/strings.xml b/packages/PackageInstaller/res/values-el/strings.xml
index 3fd87d9..c67f6f7 100644
--- a/packages/PackageInstaller/res/values-el/strings.xml
+++ b/packages/PackageInstaller/res/values-el/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Θέλετε να απεγκαταστήσετε αυτήν την εφαρμογή;"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Θέλετε να απεγκαταστήσετε αυτήν την εφαρμογή για "<b>"όλους"</b>" τους χρήστες; Η εφαρμογή και τα δεδομένα της θα καταργηθούν από "<b>"όλους"</b>" τους χρήστες στη συσκευή."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Θέλετε να απεγκαταστήσετε αυτήν την εφαρμογή για τον χρήστη <xliff:g id="USERNAME">%1$s</xliff:g>;"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Θέλετε να καταργήσετε την εγκατάσταση αυτής της εφαρμογής από το προφίλ εργασίας σας;"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Να αντικατασταθεί αυτή η εφαρμογή με την εργοστασιακή έκδοση; Όλα τα δεδομένα θα καταργηθούν."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Να αντικατασταθεί αυτή η εφαρμογή με την εργοστασιακή έκδοση; Όλα τα δεδομένα θα καταργηθούν. Αυτό επηρεάζει όλους τους χρήστες της συσκευής, συμπεριλαμβανομένων και των κατόχων προφίλ εργασίας."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Διατήρηση <xliff:g id="SIZE">%1$s</xliff:g> δεδομένων εφαρμογών."</string>
diff --git a/packages/PackageInstaller/res/values-en-rAU/strings.xml b/packages/PackageInstaller/res/values-en-rAU/strings.xml
index a91c882..f09f7bb 100644
--- a/packages/PackageInstaller/res/values-en-rAU/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rAU/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Do you want to uninstall this app?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Do you want to uninstall this app for "<b>"all"</b>" users? The application and its data will be removed from "<b>"all"</b>" users on the device."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Do you want to uninstall this app for the user <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Do you want to uninstall this app from your work profile?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Replace this app with the factory version? All data will be removed."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Replace this app with the factory version? All data will be removed. This affects all users of this device, including those with work profiles."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Keep <xliff:g id="SIZE">%1$s</xliff:g> of app data."</string>
diff --git a/packages/PackageInstaller/res/values-en-rCA/strings.xml b/packages/PackageInstaller/res/values-en-rCA/strings.xml
index a91c882..f09f7bb 100644
--- a/packages/PackageInstaller/res/values-en-rCA/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rCA/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Do you want to uninstall this app?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Do you want to uninstall this app for "<b>"all"</b>" users? The application and its data will be removed from "<b>"all"</b>" users on the device."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Do you want to uninstall this app for the user <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Do you want to uninstall this app from your work profile?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Replace this app with the factory version? All data will be removed."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Replace this app with the factory version? All data will be removed. This affects all users of this device, including those with work profiles."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Keep <xliff:g id="SIZE">%1$s</xliff:g> of app data."</string>
diff --git a/packages/PackageInstaller/res/values-en-rGB/strings.xml b/packages/PackageInstaller/res/values-en-rGB/strings.xml
index a91c882..f09f7bb 100644
--- a/packages/PackageInstaller/res/values-en-rGB/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rGB/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Do you want to uninstall this app?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Do you want to uninstall this app for "<b>"all"</b>" users? The application and its data will be removed from "<b>"all"</b>" users on the device."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Do you want to uninstall this app for the user <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Do you want to uninstall this app from your work profile?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Replace this app with the factory version? All data will be removed."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Replace this app with the factory version? All data will be removed. This affects all users of this device, including those with work profiles."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Keep <xliff:g id="SIZE">%1$s</xliff:g> of app data."</string>
diff --git a/packages/PackageInstaller/res/values-en-rIN/strings.xml b/packages/PackageInstaller/res/values-en-rIN/strings.xml
index a91c882..f09f7bb 100644
--- a/packages/PackageInstaller/res/values-en-rIN/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rIN/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Do you want to uninstall this app?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Do you want to uninstall this app for "<b>"all"</b>" users? The application and its data will be removed from "<b>"all"</b>" users on the device."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Do you want to uninstall this app for the user <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Do you want to uninstall this app from your work profile?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Replace this app with the factory version? All data will be removed."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Replace this app with the factory version? All data will be removed. This affects all users of this device, including those with work profiles."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Keep <xliff:g id="SIZE">%1$s</xliff:g> of app data."</string>
diff --git a/packages/PackageInstaller/res/values-en-rXC/strings.xml b/packages/PackageInstaller/res/values-en-rXC/strings.xml
index 6a7bddc..fddc164 100644
--- a/packages/PackageInstaller/res/values-en-rXC/strings.xml
+++ b/packages/PackageInstaller/res/values-en-rXC/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Do you want to uninstall this app?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Do you want to uninstall this app for "<b>"all"</b>" users? The application and its data will be removed from "<b>"all"</b>" users on the device."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Do you want to uninstall this app for the user <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Do you want to uninstall this app from your work profile?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Replace this app with the factory version? All data will be removed."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Replace this app with the factory version? All data will be removed. This affects all users of this device, including those with work profiles."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Keep <xliff:g id="SIZE">%1$s</xliff:g> of app data."</string>
diff --git a/packages/PackageInstaller/res/values-es-rUS/strings.xml b/packages/PackageInstaller/res/values-es-rUS/strings.xml
index bdacb64..6641e11 100644
--- a/packages/PackageInstaller/res/values-es-rUS/strings.xml
+++ b/packages/PackageInstaller/res/values-es-rUS/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"¿Quieres desinstalar esta app?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"¿Quieres desinstalar esta app para "<b>"todos"</b>" los usuarios? Se quitarán la aplicación y sus datos de "<b>"todos"</b>" los usuarios del dispositivo."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"¿Quieres desinstalar esta app para el usuario <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"¿Deseas desinstalar esta app de tu perfil de trabajo?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"¿Deseas reemplazar esta app con la versión de fábrica? Se quitarán todos los datos."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"¿Deseas reemplazar esta app con la versión de fábrica? Se quitarán todos los datos. Esta acción afectará a todos los usuarios de este dispositivo, incluidos los que tengan perfiles de trabajo."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Guardar <xliff:g id="SIZE">%1$s</xliff:g> en datos de apps"</string>
diff --git a/packages/PackageInstaller/res/values-es/strings.xml b/packages/PackageInstaller/res/values-es/strings.xml
index 7431241..1b000c2 100644
--- a/packages/PackageInstaller/res/values-es/strings.xml
+++ b/packages/PackageInstaller/res/values-es/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"¿Quieres desinstalar esta aplicación?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"¿Quieres desinstalar esta aplicación para "<b>"todos"</b>" los usuarios? La aplicación y sus datos se borrarán de "<b>"todos"</b>" los usuarios del dispositivo."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"¿Quieres desinstalar esta aplicación para el usuario <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"¿Quieres desinstalar esta aplicación de tu perfil de trabajo?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"¿Quieres reemplazar esta aplicación con la versión de fábrica? Ten en cuenta que se borrarán todos los datos."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"¿Quieres reemplazar esta aplicación con la versión de fábrica? Ten en cuenta que se borrarán todos los datos. Esto afecta a todos los usuarios del dispositivo, incluidos los que tienen perfiles de trabajo."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Mantener <xliff:g id="SIZE">%1$s</xliff:g> de datos de aplicaciones."</string>
diff --git a/packages/PackageInstaller/res/values-et/strings.xml b/packages/PackageInstaller/res/values-et/strings.xml
index 2225d3b..0138219 100644
--- a/packages/PackageInstaller/res/values-et/strings.xml
+++ b/packages/PackageInstaller/res/values-et/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Kas soovite selle rakenduse desinstallida?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Kas soovite selle rakenduse "<b>"kõikide"</b>" kasutajate kontodelt desinstallida? Rakendus ja selle andmed eemaldatakse "<b>"kõikide"</b>" seadme kasutajate kontodelt."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Kas soovite selle rakenduse kasutaja <xliff:g id="USERNAME">%1$s</xliff:g> kontolt desinstallida?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Kas soovite selle rakenduse oma tööprofiililt desinstallida?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Kas asendada see rakendus tehaseversiooniga? Kõik andmed eemaldatakse."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Kas asendada see rakendus tehaseversiooniga? Kõik andmed eemaldatakse. See mõjutab kõiki seadme kasutajaid, sh neid, kellel on tööprofiilid."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Säilita rakenduse andmete hulk <xliff:g id="SIZE">%1$s</xliff:g>."</string>
diff --git a/packages/PackageInstaller/res/values-eu/strings.xml b/packages/PackageInstaller/res/values-eu/strings.xml
index f5ad2be..aa21b4f 100644
--- a/packages/PackageInstaller/res/values-eu/strings.xml
+++ b/packages/PackageInstaller/res/values-eu/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Aplikazioa desinstalatu nahi duzu?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Erabiltzaile "<b>"guztiei"</b>" desinstalatu nahi diezu aplikazioa? Aplikazioa eta haren datu guztiak ezabatuko zaizkie gailuko erabiltzaile "<b>"guztiei"</b>"."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> erabiltzaileari desinstalatu nahi diozu aplikazioa?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Aplikazioa laneko profiletik desinstalatu nahi duzu?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Aplikazio hau jatorrizko bertsioarekin ordeztu nahi duzu? Datu guztiak ezabatuko dira."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Aplikazio hau jatorrizko bertsioarekin ordeztu nahi duzu? Datu guztiak ezabatuko dira. Gailuaren erabiltzaile guztiengan izango du eragina, laneko profilak dituztenak barne."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Mantendu aplikazioetako datuen <xliff:g id="SIZE">%1$s</xliff:g>."</string>
diff --git a/packages/PackageInstaller/res/values-fa/strings.xml b/packages/PackageInstaller/res/values-fa/strings.xml
index 0ec6acf..b05a087 100644
--- a/packages/PackageInstaller/res/values-fa/strings.xml
+++ b/packages/PackageInstaller/res/values-fa/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"میخواهید این برنامه را حذف نصب کنید؟"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"آیا میخواهید این برنامه را برای "<b>"همه"</b>" کاربران حذف کنید؟ این برنامه و دادههای آن برای "<b>"همه"</b>" کاربران این دستگاه حذف خواهد شد."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"آیا میخواهید این برنامه را برای این کاربر <xliff:g id="USERNAME">%1$s</xliff:g> حذف نصب کنید؟"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"میخواهید این برنامه را از نمایه کاریتان حذف نصب کنید؟"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"این برنامه با نسخه کارخانه جایگزین شود؟ همه دادهها پاک میشود."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"این برنامه با نسخه کارخانه جایگزین شود؟ همه دادهها پاک میشود. این کار همه کاربران این دستگاه (ازجمله کاربرانی که نمایه کاری دارند) را تحت تأثیر قرار خواهد داد."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> از دادههای برنامه را نگهدارید."</string>
diff --git a/packages/PackageInstaller/res/values-fi/strings.xml b/packages/PackageInstaller/res/values-fi/strings.xml
index 8a52d21..a8048e2 100644
--- a/packages/PackageInstaller/res/values-fi/strings.xml
+++ b/packages/PackageInstaller/res/values-fi/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Haluatko poistaa tämän sovelluksen?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Haluatko poistaa tämän sovelluksen "<b>"kaikilta"</b>" käyttäjiltä? Sovellus ja sen data poistetaan "<b>"kaikilta"</b>" laitteen käyttäjiltä."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Haluatko poistaa tämän sovelluksen käyttäjältä <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Haluatko poistaa sovelluksen työprofiilistasi?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Haluatko korvata tämän sovelluksen tehdasversiolla? Kaikki data poistetaan."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Haluatko korvata tämän sovelluksen tehdasversiolla? Kaikki data poistetaan. Tämä vaikuttaa kaikkiin laitteen käyttäjiin, myös työprofiileihin."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Säilytä <xliff:g id="SIZE">%1$s</xliff:g> sovellusdataa"</string>
diff --git a/packages/PackageInstaller/res/values-fr-rCA/strings.xml b/packages/PackageInstaller/res/values-fr-rCA/strings.xml
index 4f2a37e..d11336f 100644
--- a/packages/PackageInstaller/res/values-fr-rCA/strings.xml
+++ b/packages/PackageInstaller/res/values-fr-rCA/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Voulez-vous désinstaller cette application?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Voulez-vous désinstaller cette application pour "<b>"tous"</b>" les utilisateurs? L\'application et ses données seront supprimées pour "<b>"tous"</b>" les utilisateurs de l\'appareil."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Voulez-vous désinstaller cette application pour l\'utilisateur <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Voulez-vous désinstaller cette application de votre profil professionnel?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Remplacer cette application par la version d\'usine? Toutes les données seront supprimées."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Remplacer cette application par la version d\'usine? Toutes les données seront supprimées. Cela touchera tous les utilisateurs de cet appareil, y compris ceux qui utilisent un profil professionnel."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Garder <xliff:g id="SIZE">%1$s</xliff:g> de données d\'application."</string>
diff --git a/packages/PackageInstaller/res/values-fr/strings.xml b/packages/PackageInstaller/res/values-fr/strings.xml
index 3a04a8f..50ca29d 100644
--- a/packages/PackageInstaller/res/values-fr/strings.xml
+++ b/packages/PackageInstaller/res/values-fr/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Voulez-vous désinstaller cette application ?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Voulez-vous désinstaller cette application pour "<b>"tous"</b>" les utilisateurs ? L\'application et ses données seront supprimées pour "<b>"tous"</b>" les utilisateurs de l\'appareil."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Voulez-vous désinstaller cette application pour l\'utilisateur <xliff:g id="USERNAME">%1$s</xliff:g> ?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Voulez-vous désinstaller cette appli de votre profil professionnel ?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Remplacer cette application par la version d\'usine ? Toutes les données seront supprimées."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Remplacer cette application par la version d\'usine ? Toutes les données seront supprimées. Tous les utilisateurs de cet appareil seront affectés, y compris ceux qui ont un profil professionnel."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Conserver <xliff:g id="SIZE">%1$s</xliff:g> de données d\'application."</string>
diff --git a/packages/PackageInstaller/res/values-gl/strings.xml b/packages/PackageInstaller/res/values-gl/strings.xml
index ac1f6ac..720a3cb 100644
--- a/packages/PackageInstaller/res/values-gl/strings.xml
+++ b/packages/PackageInstaller/res/values-gl/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Queres desinstalar esta aplicación?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Queres desinstalar esta aplicación para "<b>"todos"</b>" os usuarios? A aplicación e os seus datos quitaranse de "<b>"todos"</b>" os usuarios do dispositivo."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Queres desinstalar esta aplicación para o usuario que se chama <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Queres desinstalar esta aplicación do perfil de traballo?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Queres substituír esta aplicación pola versión que viña de fábrica? Quitaranse todos os datos."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Queres substituír esta aplicación pola versión que viña de fábrica? Quitaranse todos os datos. Isto afectará a todos os usuarios do dispositivo, incluídos os que teñan perfís de traballo."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Conservar os datos da aplicación, que ocupan <xliff:g id="SIZE">%1$s</xliff:g>."</string>
diff --git a/packages/PackageInstaller/res/values-gu/strings.xml b/packages/PackageInstaller/res/values-gu/strings.xml
index 4c7d02d..4dc7f0b 100644
--- a/packages/PackageInstaller/res/values-gu/strings.xml
+++ b/packages/PackageInstaller/res/values-gu/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"શું તમે આ ઍપ્લિકેશનને અનઇન્સ્ટૉલ કરવા માંગો છો?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"શું તમે "<b>"બધા"</b>" વપરાશકર્તાઓ માટે આ ઍપ્લિકેશનને અનઇન્સ્ટૉલ કરવા માગો છો? ડિવાઇસ પરના "<b>"બધા"</b>" વપરાશકર્તાઓની ઍપ્લિકેશન અને તેનો ડેટા કાઢી નાખવામાં આવશે."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"શું તમે <xliff:g id="USERNAME">%1$s</xliff:g> વપરાશકર્તા માટે આ ઍપ્લિકેશનને અનઇન્સ્ટૉલ કરવા માગો છો?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"શું તમે તમારી ઑફિસની પ્રોફાઇલમાંથી આ ઍપને અનઇન્સ્ટૉલ કરવા માગો છો?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"આ ઍપ્લિકેશનને ફેક્ટરી વર્ઝનથી બદલીએ? બધો ડેટા કાઢી નાખવામાં આવશે."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"આ ઍપ્લિકેશનને ફેક્ટરી વર્ઝનથી બદલીએ? બધો ડેટા કાઢી નાખવામાં આવશે. આનાથી કાર્યાલયની પ્રોફાઇલ ધરાવનારા વપરાશકર્તાઓ સહિત આ ડિવાઇસના બધા વપરાશકર્તાઓ પ્રભાવિત થશે."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g>નો ઍપ ડેટા રાખો."</string>
diff --git a/packages/PackageInstaller/res/values-hi/strings.xml b/packages/PackageInstaller/res/values-hi/strings.xml
index 5d59c87..382278e 100644
--- a/packages/PackageInstaller/res/values-hi/strings.xml
+++ b/packages/PackageInstaller/res/values-hi/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"क्या आप इस ऐप्लिकेशन को अनइंस्टॉल करना चाहते हैं?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"क्या आप इस ऐप्लिकेशन को "<b>"सभी"</b>" उपयोगकर्ताओं के लिए अनइंस्टॉल करना चाहते हैं? ऐप्लिकेशन और उसके डेटा को डिवाइस पर "<b>"सभी"</b>" उपयोगकर्ताओं से हटा दिया जाएगा."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"क्या आप उपयोगकर्ता <xliff:g id="USERNAME">%1$s</xliff:g> के लिए इस ऐप्लिकेशन को अनइंस्टॉल करना चाहते हैं?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"क्या अपनी वर्क प्रोफ़ाइल से इस ऐप्लिकेशन को अनइंस्टॉल करना है?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"इस ऐप्लिकेशन को फ़ैक्ट्री वर्शन से बदलें? सभी डेटा हटा दिया जाएगा."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"इस ऐप्लिकेशन को फ़ैक्ट्री वर्शन से बदलें? पूरा डेटा हटा दिया जाएगा. इसका असर इस डिवाइस के सभी उपयोगकर्ताओं पर पड़ेगा, जिनमें काम की प्रोफ़ाइलों वाले उपयोगकर्ता शामिल हैं."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> ऐप्लिकेशन डेटा रखें."</string>
diff --git a/packages/PackageInstaller/res/values-hr/strings.xml b/packages/PackageInstaller/res/values-hr/strings.xml
index a11cc27..707eb4e 100644
--- a/packages/PackageInstaller/res/values-hr/strings.xml
+++ b/packages/PackageInstaller/res/values-hr/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Želite li deinstalirati ovu aplikaciju?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Želite li deinstalirati tu aplikaciju za "<b>"sve"</b>" korisnike? Aplikacija i njezini podaci bit će uklonjeni sa "<b>"svih"</b>" korisnika na uređaju."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Želite li deinstalirati tu aplikaciju za korisnika <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Želite li deinstalirati tu aplikaciju s poslovnog profila?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Želite li tu aplikaciju zamijeniti tvorničkom verzijom? Izgubit ćete sve podatke."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Želite li tu aplikaciju zamijeniti tvorničkom verzijom? Izgubit ćete sve podatke. To se odnosi na sve korisnike uređaja, uključujući one s radnim profilima."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Zadrži <xliff:g id="SIZE">%1$s</xliff:g> podataka aplikacije."</string>
diff --git a/packages/PackageInstaller/res/values-hu/strings.xml b/packages/PackageInstaller/res/values-hu/strings.xml
index 6b37633..70ebadb 100644
--- a/packages/PackageInstaller/res/values-hu/strings.xml
+++ b/packages/PackageInstaller/res/values-hu/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Eltávolítja ezt az alkalmazást?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Szeretné eltávolítani ezt az alkalmazást "<b>"minden"</b>" felhasználónál? Az alkalmazást és adatait az eszköz "<b>"minden"</b>" felhasználójánál töröljük."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Eltávolítja ezt az alkalmazást <xliff:g id="USERNAME">%1$s</xliff:g> felhasználó esetében?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Biztosan eltávolítja ezt az alkalmazást a munkaprofiljából?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Lecseréli az alkalmazást a gyári verzióra? Minden adat törlődik."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Lecseréli az alkalmazást a gyári verzióra? Minden adat törlődik. Ez az eszköz összes felhasználóját érinti, így a munkaprofilokkal rendelkezőket is."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> alkalmazásadat megtartása."</string>
diff --git a/packages/PackageInstaller/res/values-hy/strings.xml b/packages/PackageInstaller/res/values-hy/strings.xml
index 4c2b0ad..288c9b1 100644
--- a/packages/PackageInstaller/res/values-hy/strings.xml
+++ b/packages/PackageInstaller/res/values-hy/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Ուզո՞ւմ եք ապատեղադրել այս հավելվածը։"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Ապատեղադրե՞լ այս հավելվածը "<b>"բոլոր"</b>" օգտատերերի համար: Հավելվածը և դրա տվյալները կհեռացվեն սարքի "<b>"բոլոր"</b>" օգտատերերից:"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Ապատեղադրե՞լ այս հավելվածը <xliff:g id="USERNAME">%1$s</xliff:g> օգտատիրոջ համար:"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Հեռացնե՞լ այս հավելվածը ձեր աշխատանքային պրոֆիլից"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Փոխարինե՞լ այս հավելվածը գործարանային տարբերակով: Բոլոր տվյալները կհեռացվեն:"</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Փոխարինե՞լ այս հավելվածը գործարանային տարբերակով: Բոլոր տվյալները կհեռացվեն: Դա վերաբերում է այս սարքի բոլոր օգտատերերին, այդ թվում նաև աշխատանքային պրոֆիլներ ունեցողներին:"</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Չհեռացնել հավելվածների տվյալները (<xliff:g id="SIZE">%1$s</xliff:g>):"</string>
diff --git a/packages/PackageInstaller/res/values-in/strings.xml b/packages/PackageInstaller/res/values-in/strings.xml
index bc368e7..e3e5606 100644
--- a/packages/PackageInstaller/res/values-in/strings.xml
+++ b/packages/PackageInstaller/res/values-in/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Apakah Anda ingin meng-uninstal aplikasi ini?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Apakah Anda ingin meng-uninstal aplikasi ini untuk "<b>"semua"</b>" pengguna? Aplikasi dan datanya akan dihapus dari "<b>"semua"</b>" pengguna pada perangkat."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Apakah Anda ingin meng-uninstal aplikasi ini untuk pengguna <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Ingin meng-uninstal aplikasi ini dari profil kerja Anda?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Ganti aplikasi ini dengan versi setelan pabrik? Semua data akan dihapus."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Ganti aplikasi ini dengan versi setelan pabrik? Semua data akan dihapus. Tindakan ini memengaruhi semua pengguna perangkat ini, termasuk yang memiliki profil kerja."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Pertahankan data aplikasi sebesar <xliff:g id="SIZE">%1$s</xliff:g>."</string>
diff --git a/packages/PackageInstaller/res/values-is/strings.xml b/packages/PackageInstaller/res/values-is/strings.xml
index 2b2e215..7f0ee04 100644
--- a/packages/PackageInstaller/res/values-is/strings.xml
+++ b/packages/PackageInstaller/res/values-is/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Viltu fjarlægja þetta forrit?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Viltu fjarlægja þetta forrit hjá "<b>"öllum"</b>" notendum? Forritið og gögn þess verða fjarlægð hjá "<b>"öllum"</b>" notendum tækisins."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Viltu fjarlægja þetta forrit fyrir notandann <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Viltu fjarlægja þetta forrit af vinnuprófílnum þínum?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Viltu skipta þessu forriti út fyrir verksmiðjuútgáfuna? Öll gögn verða fjarlægð."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Viltu skipta þessu forriti út fyrir verksmiðjuútgáfuna? Öll gögn verða fjarlægð. Þetta hefur áhrif á alla notendur tækisins, þar á meðal þá sem eru með vinnusnið."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Halda <xliff:g id="SIZE">%1$s</xliff:g> af forritagögnum."</string>
diff --git a/packages/PackageInstaller/res/values-it/strings.xml b/packages/PackageInstaller/res/values-it/strings.xml
index c554aab..979de60 100644
--- a/packages/PackageInstaller/res/values-it/strings.xml
+++ b/packages/PackageInstaller/res/values-it/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Vuoi disinstallare questa app?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vuoi disinstallare questa applicazione per "<b>"tutti"</b>" gli utenti? L\'applicazione e i relativi dati verranno rimossi da "<b>"tutti"</b>" gli utenti configurati sul dispositivo."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Disinstallare l\'app per l\'utente <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vuoi disinstallare questa app dal tuo profilo di lavoro?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Sostituire questa app con la versione di fabbrica? Tutti i dati verranno rimossi."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Sostituire questa app con la versione di fabbrica? Tutti i dati verranno rimossi. Saranno interessati tutti gli utenti del dispositivo, inclusi quelli che hanno profili di lavoro."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Mantieni <xliff:g id="SIZE">%1$s</xliff:g> di dati delle app."</string>
diff --git a/packages/PackageInstaller/res/values-iw/strings.xml b/packages/PackageInstaller/res/values-iw/strings.xml
index 0351c45..2d7c988 100644
--- a/packages/PackageInstaller/res/values-iw/strings.xml
+++ b/packages/PackageInstaller/res/values-iw/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"להסיר את ההתקנה של האפליקציה הזו?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"להסיר את האפליקציה הזו עבור "<b>"כל"</b>" המשתמשים? האפליקציה והנתונים שלה יוסרו עבור "<b>"כל"</b>" המשתמשים במכשיר."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"להסיר את ההתקנה של האפליקציה הזו עבור <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"רוצה להסיר את האפליקציה הזו מפרופיל העבודה?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"להחליף את האפליקציה הזאת בגרסת היצרן? כל הנתונים יוסרו."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"האם להחליף את האפליקציה הזאת בגרסת היצרן? כל הנתונים יוסרו. הפעולה תשפיע על כל משתמשי המכשיר, כולל משתמשים בעלי פרופיל עבודה."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"שמירת <xliff:g id="SIZE">%1$s</xliff:g> מנתוני האפליקציה."</string>
diff --git a/packages/PackageInstaller/res/values-ja/strings.xml b/packages/PackageInstaller/res/values-ja/strings.xml
index 880ff86..8ddc87c 100644
--- a/packages/PackageInstaller/res/values-ja/strings.xml
+++ b/packages/PackageInstaller/res/values-ja/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"このアプリをアンインストールしますか?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"このアプリを"<b>"すべての"</b>"ユーザーからアンインストールしますか?このアプリとそのデータはデバイスの"<b>"すべての"</b>"ユーザーから削除されます。"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> さんのアプリをアンインストールしますか?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"このアプリを仕事用プロファイルからアンインストールしますか?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"このアプリを出荷時の状態に戻しますか?データがすべて削除されます。"</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"このアプリを出荷時の状態に戻しますか?データがすべて削除されます。これは、仕事用プロファイルを設定しているユーザーも含めて、このデバイスを使用するすべてのユーザーが対象となります。"</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"アプリのデータ(<xliff:g id="SIZE">%1$s</xliff:g>)を保持"</string>
diff --git a/packages/PackageInstaller/res/values-ka/strings.xml b/packages/PackageInstaller/res/values-ka/strings.xml
index 4d83332..ea6d45e 100644
--- a/packages/PackageInstaller/res/values-ka/strings.xml
+++ b/packages/PackageInstaller/res/values-ka/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"გსურთ ამ აპის დეინსტალაცია?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"გსურთ ამ აპის დეინსტალაცია "<b>"ყველა"</b>" მომხმარებლისთვის? აპლიკაცია და მისი მონაცემები ამოიშლება "<b>"ყველა"</b>" მომხმარებლის პროფილიდან მოწყობილობაზე."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"გსურთ ამ აპის დეინსტალაცია <xliff:g id="USERNAME">%1$s</xliff:g>-ისთვის?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"გსურთ ამ აპის დეინსტალაცია თქვენი სამსახურის პროფილიდან?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"გსურთ ამ აპის ჩანაცვლება ქარხნული ვერსიით? მონაცემები მთლიანად ამოიშლება."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"გსურთ ამ აპის ჩანაცვლება ქარხნული ვერსიით? მონაცემები მთლიანად ამოიშლება. ეს ქმედება აისახება ამ მოწყობილობის ყველა მომხმარებელზე, მათ შორის, სამსახურის პროფილებით მოსარგებლეებზეც."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"შენარჩუნდეს აპების მონაცემების <xliff:g id="SIZE">%1$s</xliff:g>."</string>
diff --git a/packages/PackageInstaller/res/values-kk/strings.xml b/packages/PackageInstaller/res/values-kk/strings.xml
index 964e2c3..20eed5b 100644
--- a/packages/PackageInstaller/res/values-kk/strings.xml
+++ b/packages/PackageInstaller/res/values-kk/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Осы қолданба жойылсын ба?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Бұл қолданба "<b>"барлық"</b>" пайдаланушылар үшін жойылсын ба? Қолданба және оның деректері құрылғыдағы "<b>"барлық"</b>" пайдаланушылардан өшіріледі."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> үшін осы қолданба жойылсын ба?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Бұл қолданба жұмыс профиліңізден жойылсын ба?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Осы қолданбаны зауыттық нұсқамен ауыстыру керек пе? Барлық деректер жойылады."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Осы қолданбаны зауыттық нұсқамен ауыстыру керек пе? Барлық деректер жойылады. Бұл осы құрылғының барлық пайдаланушыларына, соның ішінде жұмыс профильдері бар пайдаланушыларға әсер етеді."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Қолданба деректерін (<xliff:g id="SIZE">%1$s</xliff:g>) сақтау."</string>
diff --git a/packages/PackageInstaller/res/values-km/strings.xml b/packages/PackageInstaller/res/values-km/strings.xml
index 0ca4c12..525e0ef 100644
--- a/packages/PackageInstaller/res/values-km/strings.xml
+++ b/packages/PackageInstaller/res/values-km/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"តើអ្នកចង់លុបកម្មវិធីនេះដែរទេ?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"តើអ្នកចង់លុបកម្មវិធីនេះសម្រាប់អ្នកប្រើប្រាស់"<b>"ទាំងអស់"</b>"ដែរទេ? កម្មវិធីនេះ និងទិន្នន័យរបស់វានឹងត្រូវបានលុបចេញពីអ្នកប្រើប្រាស់"<b>"ទាំងអស់"</b>"នៅលើឧបករណ៍នេះ។"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"តើអ្នកចង់លុបកម្មវិធីនេះសម្រាប់អ្នកប្រើប្រាស់ <xliff:g id="USERNAME">%1$s</xliff:g> ដែរទេ?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"តើអ្នកចង់លុបកម្មវិធីនេះពីកម្រងព័ត៌មានការងាររបស់អ្នកដែរទេ?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"ជំនួសកម្មវិធីនេះដោយប្រើកំណែរោងចក្រ? ទិន្នន័យទាំងអស់នឹងត្រូវបានលុប។"</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ជំនួសកម្មវិធីនេះដោយប្រើកំណែរោងចក្រ? ទិន្នន័យទាំងអស់នឹងត្រូវបានលុប។ សកម្មភាពនេះប៉ះពាល់ដល់អ្នកប្រើប្រាស់ទាំងអស់របស់ឧបករណ៍នេះ រួមទាំងអ្នកប្រើប្រាស់ដែលមានកម្រងព័ត៌មានការងារផងដែរ។"</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"រក្សាទុកទិន្នន័យកម្មវិធីទំហំ <xliff:g id="SIZE">%1$s</xliff:g>។"</string>
diff --git a/packages/PackageInstaller/res/values-kn/strings.xml b/packages/PackageInstaller/res/values-kn/strings.xml
index 045c481..4c6b2ff 100644
--- a/packages/PackageInstaller/res/values-kn/strings.xml
+++ b/packages/PackageInstaller/res/values-kn/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"ನೀವು ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ಬಯಸುವಿರಾ?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"ನೀವು "<b>"ಎಲ್ಲಾ"</b>" ಬಳಕೆದಾರರಿಗೂ ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ಬಯಸುವಿರಾ? ಸಾಧನದಲ್ಲಿನ "<b>"ಎಲ್ಲಾ"</b>" ಬಳಕೆದಾರರಿಂದ ಆ್ಯಪ್ ಮತ್ತು ಅದರ ಡೇಟಾವನ್ನು ತೆಗೆದುಹಾಕಲಾಗುವುದು."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> ಬಳಕೆದಾರರಿಗೆ ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ನೀವು ಬಯಸುವಿರಾ?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ನಿಮ್ಮ ಉದ್ಯೋಗದ ಪ್ರೊಫೈಲ್ನಿಂದ ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ನೀವು ಬಯಸುವಿರಾ?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"ಈ ಆ್ಯಪ್ ಬದಲಿಗೆ ಫ್ಯಾಕ್ಟರಿ ಆವೃತ್ತಿಯನ್ನು ಬದಲಾಯಿಸುವುದೇ? ಎಲ್ಲಾ ಡೇಟಾ ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ಈ ಆ್ಯಪ್ ಬದಲಿಗೆ ಫ್ಯಾಕ್ಟರಿ ಆವೃತ್ತಿಯನ್ನು ಬದಲಾಯಿಸುವುದೇ? ಎಲ್ಲಾ ಡೇಟಾ ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ. ಕೆಲಸದ ಪ್ರೊಫೈಲ್ಗಳನ್ನು ಹೊಂದಿರುವವುಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ಈ ಸಾಧನದ ಎಲ್ಲಾ ಬಳಕೆದಾರರಿಗೆ ಇದು ಪರಿಣಾಮ ಬೀರುತ್ತದೆ."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"ಆ್ಯಪ್ ಡೇಟಾದಲ್ಲಿ <xliff:g id="SIZE">%1$s</xliff:g> ಇರಿಸಿಕೊಳ್ಳಿ."</string>
diff --git a/packages/PackageInstaller/res/values-ko/strings.xml b/packages/PackageInstaller/res/values-ko/strings.xml
index 1afdc34..02e65ab9 100644
--- a/packages/PackageInstaller/res/values-ko/strings.xml
+++ b/packages/PackageInstaller/res/values-ko/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"이 앱을 제거하시겠습니까?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119"><b>"모든"</b>" 사용자에 대해 이 앱을 제거하시겠습니까? 기기를 사용하는 "<b>"모든"</b>" 사용자에 대해 애플리케이션 및 데이터가 삭제됩니다."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g>님의 기기에 설치된 앱을 제거하시겠습니까?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"직장 프로필에서 이 앱을 제거하시겠습니까?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"이 앱을 초기 버전으로 바꾸시겠습니까? 모든 데이터가 삭제됩니다."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"이 앱을 초기 버전으로 바꾸시겠습니까? 모든 데이터가 삭제되며 직장 프로필 사용자를 포함해 이 기기의 모든 사용자에게 영향을 미칩니다."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"앱 데이터 크기를 <xliff:g id="SIZE">%1$s</xliff:g>로 유지합니다."</string>
diff --git a/packages/PackageInstaller/res/values-ky/strings.xml b/packages/PackageInstaller/res/values-ky/strings.xml
index b9ceb08..5adfd2b 100644
--- a/packages/PackageInstaller/res/values-ky/strings.xml
+++ b/packages/PackageInstaller/res/values-ky/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Бул колдонмону чыгарып саласызбы?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Бул колдонмо "<b>"бардык"</b>" колдонуучулардан алынып салынсынбы? Бул колдонмо жана анын дайындары бул түзмөктүн "<b>"бардык"</b>" колдонуучуларынан өчүрүлөт."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Бул колдонмону <xliff:g id="USERNAME">%1$s</xliff:g> үчүн чыгарып саласызбы?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Бул колдонмону жумуш профилиңизден чыгарып саласызбы?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Бул колдонмонун баштапкы версиясы орнотулсунбу? Бардык дайындар өчүп калат."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Бул колдонмонун баштапкы версиясы орнотулсунбу? Түзмөктөгү бардык профилдердин, ошондой эле жумушчу профилдердин дайындары өчүп калат."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Колдонмонун <xliff:g id="SIZE">%1$s</xliff:g> дайындарын сактоо."</string>
diff --git a/packages/PackageInstaller/res/values-lo/strings.xml b/packages/PackageInstaller/res/values-lo/strings.xml
index 52c8b46..868c35d 100644
--- a/packages/PackageInstaller/res/values-lo/strings.xml
+++ b/packages/PackageInstaller/res/values-lo/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"ທ່ານຕ້ອງການຖອນການຕິດຕັ້ງແອັບນີ້ບໍ່?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"ທ່ານຕ້ອງການທີ່ຈະຖອນການຕິດຕັ້ງແອັບນີ້ສຳລັງຜູ້ໃຊ້"<b>"ທຸກຄົນ"</b>"ບໍ່? ແອັບພລິເຄຊັນ ແລະ ຂໍ້ມູນຂອງມັນຈະຖືກລຶບອອກຈາກຜູ້ໃຊ້"<b>"ທັງໝົດ"</b>"ໃນອຸປະກອນນີ້."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"ທ່ານຕ້ອງການຖອນການຕິດຕັ້ງແອັບນີ້ສຳລັບຜູ້ໃຊ້ <xliff:g id="USERNAME">%1$s</xliff:g> ບໍ່?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ທ່ານຕ້ອງການຖອນການຕິດຕັ້ງແອັບນີ້ຈາກໂປຣໄຟລ໌ບ່ອນເຮັດວຽກບໍ?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"ແທນທີ່ແອັບນີ້ດ້ວຍເວີຊັນທີ່ມາຈາກໂຮງງານບໍ? ຂໍ້ມູນທັງໝົດຈະຖືກລຶບອອກ."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ແທນທີ່ແອັບນີ້ດ້ວຍເວີຊັນທີ່ມາຈາກໂຮງງານບໍ? ຂໍ້ມູນທັງໝົດຈະຖືກລຶບອອກ ເຊິ່ງມີຜົນກັບຜູ້ໃຊ້ອຸປະກອນນີ້ທຸກຄົນ ຮວມທັງຄົນທີ່ມີໂປຣໄຟລ໌ບ່ອນເຮັດວຽກນຳ."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"ຮັກສາຂະໜາດຂໍ້ມູນແອັບ <xliff:g id="SIZE">%1$s</xliff:g> ໄວ້."</string>
diff --git a/packages/PackageInstaller/res/values-lt/strings.xml b/packages/PackageInstaller/res/values-lt/strings.xml
index 5d57b03..4dfbb27 100644
--- a/packages/PackageInstaller/res/values-lt/strings.xml
+++ b/packages/PackageInstaller/res/values-lt/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Ar norite pašalinti šią programą?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Ar norite pašalinti šią programą "<b>"visiems"</b>" naudotojams? Programa ir jos duomenys bus pašalinti "<b>"visiems"</b>" įrenginio naudotojams."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Ar norite pašalinti šią naudotojo <xliff:g id="USERNAME">%1$s</xliff:g> programą?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Ar norite pašalinti šią programą iš savo darbo profilio?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Pakeisti šios programos versiją į gamyklinę? Visi duomenys bus pašalinti."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Pakeisti šios programos versiją į gamyklinę? Visi duomenys bus pašalinti. Tai paveiks visus šio įrenginio naudotojus, įskaitant turinčius darbo profilius."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Palikti <xliff:g id="SIZE">%1$s</xliff:g> programų duomenų."</string>
diff --git a/packages/PackageInstaller/res/values-lv/strings.xml b/packages/PackageInstaller/res/values-lv/strings.xml
index c58b293..2a5507f 100644
--- a/packages/PackageInstaller/res/values-lv/strings.xml
+++ b/packages/PackageInstaller/res/values-lv/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Vai vēlaties atinstalēt šo lietotni?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vai vēlaties atinstalēt šo lietotni "<b>"visiem"</b>" lietotājiem? Šī lietojumprogramma un tās dati tiks noņemti no "<b>"visiem"</b>" ierīces lietotāju kontiem."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Vai vēlaties atinstalēt šo lietotni lietotājam <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vai vēlaties atinstalēt šo lietotni no sava darba profila?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Vai aizstāt šo lietotni ar rūpnīcas versiju? Visi dati tiks noņemti."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Vai aizstāt šo lietotni ar rūpnīcas versiju? Visi dati tiks noņemti. Tas ietekmēs visu šīs ierīces lietotāju datus, pat ja viņiem ir darba profili."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Iegūstiet <xliff:g id="SIZE">%1$s</xliff:g> (lietotnes dati)."</string>
diff --git a/packages/PackageInstaller/res/values-mk/strings.xml b/packages/PackageInstaller/res/values-mk/strings.xml
index 4ebe101..732df62 100644
--- a/packages/PackageInstaller/res/values-mk/strings.xml
+++ b/packages/PackageInstaller/res/values-mk/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Дали сакате да ја деинсталирате оваа апликација?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Дали сакате да ја деинсталирате оваа апликација за "<b>"сите"</b>" корисници? Апликацијата и нејзините податоци ќе се отстранат од "<b>"сите"</b>" корисници на уредот."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Дали сакате да ја деинсталирате апликацијава за корисникот <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Дали сакате да ја деинсталирате апликацијава од работниот профил?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Сакате да ја замените оваа апликација со фабричката верзија? Сите податоци ќе се отстранат."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Сакате да ја замените оваа апликација со фабричката верзија? Сите податоци ќе се отстранат. Тоа важи за сите корисници на овој уред, вклучувајќи ги и тие со работни профили."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Задржи <xliff:g id="SIZE">%1$s</xliff:g> податоци на апликацијата."</string>
diff --git a/packages/PackageInstaller/res/values-ml/strings.xml b/packages/PackageInstaller/res/values-ml/strings.xml
index 0d24f87..66de3f1 100644
--- a/packages/PackageInstaller/res/values-ml/strings.xml
+++ b/packages/PackageInstaller/res/values-ml/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"ഈ ആപ്പ് അൺ ഇൻസ്റ്റാൾ ചെയ്യണോ?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"ഈ അപ്പ് "<b>"എല്ലാ"</b>" ഉപയോക്താക്കൾക്കുമായി അൺ ഇൻസ്റ്റാൾ ചെയ്യണോ? ഉപകരണത്തിലെ "<b>"എല്ലാ"</b>" ഉപയോക്താക്കളിൽ നിന്നും ആപ്പും അതിന്റെ ഡാറ്റയും നീക്കം ചെയ്യപ്പെടും."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> എന്ന ഉപയോക്താവിനായി ഈ ആപ്പ് അൺ ഇൻസ്റ്റാൾ ചെയ്യണോ?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലിൽ നിന്ന് ഈ ആപ്പ് അൺ ഇൻസ്റ്റാൾ ചെയ്യണോ?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"ഫാക്ടറി പതിപ്പ് ഉപയോഗിച്ച് ഈ ആപ്പിന് പകരം വയ്ക്കണോ? എല്ലാ ഡാറ്റയും നീക്കം ചെയ്യപ്പെടും."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ഫാക്ടറി പതിപ്പ് ഉപയോഗിച്ച് ഈ ആപ്പിന് പകരം വയ്ക്കണോ? എല്ലാ ഡാറ്റയും നീക്കം ചെയ്യപ്പെടും. ഔദ്യോഗിക പ്രൊഫൈലുകൾ ഉള്ളവർ ഉൾപ്പെടെ, ഈ ഉപകരണത്തിന്റെ എല്ലാ ഉപയോക്താക്കളെയും ഇത് ബാധിക്കും."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> ആപ്പ് ഡാറ്റ വയ്ക്കുക."</string>
diff --git a/packages/PackageInstaller/res/values-mn/strings.xml b/packages/PackageInstaller/res/values-mn/strings.xml
index 3f49e8c..5eb0e6c 100644
--- a/packages/PackageInstaller/res/values-mn/strings.xml
+++ b/packages/PackageInstaller/res/values-mn/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Та энэ аппыг устгахыг хүсэж байна уу?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Та энэ аппыг "<b>"бүх"</b>" хэрэглэгчээс устгахыг хүсэж байна уу? Апп болон доторх өгөгдлийг төхөөрөмж дээрх "<b>"бүх"</b>" хэрэглэгчээс устгана."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Та энэ аппыг <xliff:g id="USERNAME">%1$s</xliff:g> хэрэглэгчийн өмнөөс устгахыг хүсэж байна уу?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Та энэ аппыг ажлын профайлаасаа устгахыг хүсэж байна уу?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Энэ аппыг үйлдвэрээс ирсэн хувилбараар солих уу? Бүх өгөгдөл устах болно."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Энэ аппыг үйлдвэрээс ирсэн хувилбараар солих уу? Бүх өгөгдөл устах болно. Энэ нь эдгээр ажлын профайлтай бүхий энэ төхөөрөмжийн бүх хэрэглэгчид нөлөөлнө."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Аппын өгөгдлийн <xliff:g id="SIZE">%1$s</xliff:g>-г үлдээнэ үү."</string>
diff --git a/packages/PackageInstaller/res/values-mr/strings.xml b/packages/PackageInstaller/res/values-mr/strings.xml
index e5adc8a..42a9676 100644
--- a/packages/PackageInstaller/res/values-mr/strings.xml
+++ b/packages/PackageInstaller/res/values-mr/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"तुम्हाला हे अॅप अनइंस्टॉल करायचे आहे का?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"तुम्हाला हे अॅप "<b>"सर्व"</b>" वापरकर्त्यांसाठी अनइंस्टॉल करायचे आहे का? अॅप्लिकेशन आणि त्याचा डेटा डिव्हाइसवरील "<b>"सर्व"</b>" वापरकर्त्यांकडून काढला जाईल."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"तुम्हाला <xliff:g id="USERNAME">%1$s</xliff:g> वापरकर्त्यासाठी हे अॅप अनइंस्टॉल करायचे आहे का?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"तुम्हाला तुमच्या कार्य प्रोफाइलमधून हे ॲप अनइंस्टॉल करायचे आहे का?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"फॅक्टरी आवृत्तीसह हे अॅप बदलायचे का? सर्व डेटा काढला जाईल."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"फॅक्टरी आवृत्तीसह हे अॅप बदलायचे? सर्व डेटा काढला जाईल. हे कार्य प्रोफाइल असलेल्यांसह या डिव्हाइसच्या सर्व वापरकर्त्यांना प्रभावित करते."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"ॲप डेटा पैकी <xliff:g id="SIZE">%1$s</xliff:g> ठेवा."</string>
diff --git a/packages/PackageInstaller/res/values-ms/strings.xml b/packages/PackageInstaller/res/values-ms/strings.xml
index 3adfe88..09ed820 100644
--- a/packages/PackageInstaller/res/values-ms/strings.xml
+++ b/packages/PackageInstaller/res/values-ms/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Adakah anda mahu menyahpasang apl ini?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Adakah anda mahu menyahpasang apl ini untuk "<b>"semua"</b>" pengguna? Aplikasi dan datanya akan dialih keluar daripada "<b>"semua"</b>" pengguna pada peranti."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Adakah anda ingin menyahpasang apl ini untuk pengguna <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Adakah anda mahu menyahpasang apl ini daripada profil kerja anda?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Gantikan apl ini dengan versi kilang? Semua data akan dialih keluar."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Gantikan apl ini dengan versi kilang? Semua data akan dialih keluar. Tindakan ini melibatkan semua pengguna peranti ini, termasuk mereka yang mempunyai profil kerja."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Simpan <xliff:g id="SIZE">%1$s</xliff:g> data apl."</string>
diff --git a/packages/PackageInstaller/res/values-my/strings.xml b/packages/PackageInstaller/res/values-my/strings.xml
index e0fa952..d6e72d6 100644
--- a/packages/PackageInstaller/res/values-my/strings.xml
+++ b/packages/PackageInstaller/res/values-my/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"ဤအက်ပ်ကို ဖယ်ရှားလိုပါသလား။"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"ဤအပလီကေးရှင်းကို အသုံးပြုသူ "<b>"အားလုံး"</b>" အတွက် ဖယ်ရှားလိုပါသလား။ ဤအပလီကေးရှင်းနှင့် သက်ဆိုင်ရာ အချက်အလက်များ အားလုံးကို "<b>" က "</b>" စက်အသုံးပြုသူများအတွက် ဖယ်ရှားလိုက်ပါမည်။"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"သင်သည် အသုံးပြုသူ <xliff:g id="USERNAME">%1$s</xliff:g> အတွက် ဤအကောင့်ကို ဖယ်ရှားလိုပါသလား။"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"သင့်အလုပ်ပရိုဖိုင်ကနေ ဤအက်ပ်ကို ဖယ်ရှားလိုတာ သေချာပါသလား။"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"ဤအက်ပ်ကို စက်ရုံထုတ်ဗားရှင်းဖြင့် အစားထိုးလိုပါသလား။ ဒေတာများအားလုံးကို ဖယ်ရှားလိုက်ပါမည်။"</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ဤအက်ပ်ကို စက်ရုံထုတ်ဗားရှင်းဖြင့် အစားထိုးလိုသလား။ ဒေတာများအားလုံးကို ဖယ်ရှားလိုက်ပါမည်။ ၎င်းသည် အလုပ်ပရိုဖိုင်ဖြင့်သုံးသူများအပါအဝင် အသုံးပြုသူများအားလုံးကို အကျိုးသက်ရောက်စေပါမည်။"</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"အက်ပ်ဒေတာများ၏ <xliff:g id="SIZE">%1$s</xliff:g> ကို ထားရှိရန်။"</string>
diff --git a/packages/PackageInstaller/res/values-nb/strings.xml b/packages/PackageInstaller/res/values-nb/strings.xml
index e382620..a0a00b3 100644
--- a/packages/PackageInstaller/res/values-nb/strings.xml
+++ b/packages/PackageInstaller/res/values-nb/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Vil du avinstallere denne appen?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vil du avinstallere denne appen for "<b>"alle"</b>" brukere? Appen og tilhørende data blir fjernet fra "<b>"alle"</b>" brukere på enheten."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Ønsker du å avinstallere denne appen for brukeren <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vil du avinstallere denne appen fra jobbprofilen din?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Vil du erstatte denne appen med den opprinnelige versjonen? Alle dataene fjernes."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Vil du erstatte denne appen med den opprinnelige versjonen? Alle dataene fjernes. Dette påvirker alle som bruker denne enheten – også personer med jobbprofiler."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Behold <xliff:g id="SIZE">%1$s</xliff:g> med appdata."</string>
diff --git a/packages/PackageInstaller/res/values-ne/strings.xml b/packages/PackageInstaller/res/values-ne/strings.xml
index 5509c1c..ec9c60e 100644
--- a/packages/PackageInstaller/res/values-ne/strings.xml
+++ b/packages/PackageInstaller/res/values-ne/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"तपाईं यो एपको स्थापना रद्द गर्न चाहनुहुन्छ?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"तपाईं "<b>"सबै"</b>" प्रयोगकर्ताका लागि यो एपको स्थापना रद्द गर्न चाहनुहुन्छ? डिभाइसका "<b>"सबै"</b>" प्रयोगकर्ताहरूबाट उक्त एप र यसको डेटा हटाइने छ।"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"तपाईं प्रयोगकर्ता <xliff:g id="USERNAME">%1$s</xliff:g> का लागि यो एपको स्थापना रद्द गर्न चाहनुहुन्छ?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"तपाईं आफ्नो कार्य प्रोफाइलबाट यो एप अनइन्स्टल गर्न चाहनुहुन्छ?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"यस एपलाई फ्याक्ट्रीको संस्करणले बदल्ने हो? सबै डेटा हटाइने छ।"</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"यस एपलाई फ्याक्ट्रीको संस्करणले बदल्ने हो? सबै डेटा हटाइने छ। यसले यस डिभाइसका कार्य प्रोफाइल भएका लगायत सबै प्रयोगकर्ताहरूमा असर पार्छ।"</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> एपको डेटा राख्नुहोस्।"</string>
diff --git a/packages/PackageInstaller/res/values-nl/strings.xml b/packages/PackageInstaller/res/values-nl/strings.xml
index ea675b1..8afe5db 100644
--- a/packages/PackageInstaller/res/values-nl/strings.xml
+++ b/packages/PackageInstaller/res/values-nl/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Wil je deze app verwijderen?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Wil je deze app verwijderen voor "<b>"alle"</b>" gebruikers? Deze app en de gegevens ervan worden verwijderd voor "<b>"alle"</b>" gebruikers van het apparaat."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Wil je deze app verwijderen voor de gebruiker <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Wil je deze app verwijderen uit je werkprofiel?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Deze app vervangen door de fabrieksversie? Alle gegevens worden verwijderd."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Deze app vervangen door de fabrieksversie? Alle gegevens worden verwijderd. Dit geldt voor alle gebruikers van het apparaat, dus ook voor gebruikers met een werkprofiel."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> aan app-gegevens behouden."</string>
diff --git a/packages/PackageInstaller/res/values-or/strings.xml b/packages/PackageInstaller/res/values-or/strings.xml
index 3ea1e99..20a3480 100644
--- a/packages/PackageInstaller/res/values-or/strings.xml
+++ b/packages/PackageInstaller/res/values-or/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"ଆପଣ ଏହି ଆପ୍ ଅନଇନଷ୍ଟଲ୍ କରିବାକୁ ଚାହାଁନ୍ତି କି?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"ଆପଣ "<b>"ସମସ୍ତ"</b>" ୟୁଜର୍ଙ୍କ ପାଇଁ ଏହି ଆପ୍କୁ ଅନଷ୍ଟଲ୍ କରିବାକୁ ଚାହୁଁଛନ୍ତି କି? ଡିଭାଇସ୍ରେ ଥିବା "<b>"ସମସ୍ତ"</b>" ୟୁଜର୍ ଆପ୍ଲିକେଶନ୍ ଏବଂ ତାହାର ଡାଟା ବାହାର କରିଦିଆଯିବ।"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"ୟୁଜର୍ <xliff:g id="USERNAME">%1$s</xliff:g>ଙ୍କ ପାଇଁ ଆପଣ ଏହି ଆପ୍ ଇନଷ୍ଟଲ୍ କରିବେ କି?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ଆପଣ ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲରୁ ଏହି ଆପକୁ ଅନଇନଷ୍ଟଲ କରିବାକୁ ଚାହାଁନ୍ତି କି?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"ଏହି ଆପ୍ ଫ୍ୟାକ୍ଟୋରୀ ଭର୍ସନ୍ ସହ ବଦଳାଇବେ? ସମସ୍ତ ଡାଟା କାଢ଼ିଦିଆଯିବ।"</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ଏହି ଆପ୍ ଫ୍ୟାକ୍ଟୋରୀ ଭର୍ସନ୍ ସହ ବଦଳାଇବେ? ସମସ୍ତ ଡାଟା ବାହାର କରିଦିଆଯିବ। ୱର୍କ ପ୍ରୋଫାଇଲ୍ ଥିବା ସମେତ, ଏହାଦ୍ୱାରା ଡିଭାଇସରେ ଥିବା ସମସ୍ତ ୟୁଜର୍ ପ୍ରଭାବିତ ହେବେ।"</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> ଆକାରର ଆପ୍ ଡାଟା ରଖନ୍ତୁୁ।"</string>
diff --git a/packages/PackageInstaller/res/values-pa/strings.xml b/packages/PackageInstaller/res/values-pa/strings.xml
index 0d44440..d5b8573 100644
--- a/packages/PackageInstaller/res/values-pa/strings.xml
+++ b/packages/PackageInstaller/res/values-pa/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ "<b>"ਸਾਰੇ"</b>" ਵਰਤੋਂਕਾਰਾਂ ਲਈ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ? ਐਪਲੀਕੇਸ਼ਨ ਅਤੇ ਇਸਦਾ ਡਾਟਾ ਡੀਵਾਈਸ \'ਤੇ "<b>"ਸਾਰੇ"</b>" ਵਰਤੋਂਕਾਰਾਂ ਵੱਲੋਂ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"ਕੀ ਤੁਸੀਂ ਵਰਤੋਂਕਾਰ <xliff:g id="USERNAME">%1$s</xliff:g> ਲਈ ਇਸ ਐਪ ਨੂੰ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਆਪਣੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਤੋਂ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"ਕੀ ਇਸ ਐਪ ਨੂੰ ਫੈਕਟਰੀ ਵਰਜਨ ਨਾਲ ਬਦਲਣਾ ਹੈ? ਸਾਰਾ ਡਾਟਾ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ਕੀ ਇਸ ਐਪ ਨੂੰ ਫੈਕਟਰੀ ਵਰਜਨ ਨਾਲ ਬਦਲਣਾ ਹੈ? ਸਾਰਾ ਡਾਟਾ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ। ਇਹ ਇਸ ਡੀਵਾਈਸ ਦੇ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਨੂੰ ਪ੍ਰਭਾਵਿਤ ਕਰੇਗਾ, ਜਿਸ ਵਿੱਚ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਾਲੇ ਵਰਤੋਂਕਾਰ ਵੀ ਸ਼ਾਮਲ ਹਨ।"</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> ਐਪ ਡਾਟਾ ਰੱਖੋ।"</string>
diff --git a/packages/PackageInstaller/res/values-pl/strings.xml b/packages/PackageInstaller/res/values-pl/strings.xml
index 9fd3ada..e0b8637 100644
--- a/packages/PackageInstaller/res/values-pl/strings.xml
+++ b/packages/PackageInstaller/res/values-pl/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Odinstalować tę aplikację?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Chcesz odinstalować tę aplikację dla "<b>"wszystkich"</b>" użytkowników? Ta aplikacja i jej dane zostaną usunięte dla "<b>"wszystkich"</b>" użytkowników na urządzeniu."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Chcesz odinstalować tę aplikację dla użytkownika <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Czy chcesz odinstalować tę aplikację z profilu służbowego?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Przywrócić fabryczną wersję tej aplikacji? Wszystkie dane zostaną usunięte."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Przywrócić fabryczną wersję tej aplikacji? Wszystkie dane zostaną usunięte. Dotyczy to wszystkich użytkowników tego urządzenia, również tych korzystających z profilu służbowego."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Zachowaj <xliff:g id="SIZE">%1$s</xliff:g> danych aplikacji."</string>
diff --git a/packages/PackageInstaller/res/values-pt-rBR/strings.xml b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
index 2111b87..098c4b0 100644
--- a/packages/PackageInstaller/res/values-pt-rBR/strings.xml
+++ b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Quer desinstalar este app?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Quer desinstalar este app para "<b>"todos"</b>" os usuários? O aplicativo e os dados dele serão removidos para "<b>"todos"</b>" os usuários do dispositivo."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Quer desinstalar este app para o usuário <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Você quer desinstalar esse app do seu perfil de trabalho?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Substituir este app pela versão de fábrica? Todos os dados serão removidos."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Substituir este app pela versão de fábrica? Todos os dados serão removidos. Isso afeta todos os usuários deste dispositivo, incluindo aqueles com perfis de trabalho."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Manter <xliff:g id="SIZE">%1$s</xliff:g> de dados do app."</string>
diff --git a/packages/PackageInstaller/res/values-pt-rPT/strings.xml b/packages/PackageInstaller/res/values-pt-rPT/strings.xml
index 9689415..9e3b40d 100644
--- a/packages/PackageInstaller/res/values-pt-rPT/strings.xml
+++ b/packages/PackageInstaller/res/values-pt-rPT/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Pretende desinstalar esta app?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Pretende desinstalar esta app para "<b>"todos"</b>" os utilizadores? A app e os respetivos dados serão removidos de "<b>"todos"</b>" os utilizadores do dispositivo."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Pretende desinstalar esta app para o utilizador <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Quer desinstalar esta app do seu perfil de trabalho?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Pretende substituir esta app pela versão de fábrica? Todos os dados são removidos."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Pretende substituir esta app pela versão de fábrica? Todos os dados são removidos. Esta ação afeta todos os utilizadores deste dispositivo, incluindo os que têm perfis de trabalho."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Manter <xliff:g id="SIZE">%1$s</xliff:g> de dados da app."</string>
diff --git a/packages/PackageInstaller/res/values-pt/strings.xml b/packages/PackageInstaller/res/values-pt/strings.xml
index 2111b87..098c4b0 100644
--- a/packages/PackageInstaller/res/values-pt/strings.xml
+++ b/packages/PackageInstaller/res/values-pt/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Quer desinstalar este app?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Quer desinstalar este app para "<b>"todos"</b>" os usuários? O aplicativo e os dados dele serão removidos para "<b>"todos"</b>" os usuários do dispositivo."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Quer desinstalar este app para o usuário <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Você quer desinstalar esse app do seu perfil de trabalho?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Substituir este app pela versão de fábrica? Todos os dados serão removidos."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Substituir este app pela versão de fábrica? Todos os dados serão removidos. Isso afeta todos os usuários deste dispositivo, incluindo aqueles com perfis de trabalho."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Manter <xliff:g id="SIZE">%1$s</xliff:g> de dados do app."</string>
diff --git a/packages/PackageInstaller/res/values-ro/strings.xml b/packages/PackageInstaller/res/values-ro/strings.xml
index 5627c29..03cb145 100644
--- a/packages/PackageInstaller/res/values-ro/strings.xml
+++ b/packages/PackageInstaller/res/values-ro/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Doriți să dezinstalați această aplicație?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Doriți să dezinstalați această aplicație pentru "<b>"toți"</b>" utilizatorii? Aplicația și datele acesteia vor fi eliminate de la "<b>"toți"</b>" utilizatorii de pe acest dispozitiv."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Dezinstalați această aplicație pentru utilizatorul <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Doriți să dezinstalați această aplicație din profilul de serviciu?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Înlocuiți această aplicație cu versiunea din fabrică? Toate datele vor fi eliminate."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Înlocuiți această aplicație cu versiunea din fabrică? Toate datele vor fi eliminate. Această acțiune va afecta toți utilizatorii dispozitivului, inclusiv pe cei cu profiluri de serviciu."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Păstrează <xliff:g id="SIZE">%1$s</xliff:g> din datele aplicației."</string>
diff --git a/packages/PackageInstaller/res/values-ru/strings.xml b/packages/PackageInstaller/res/values-ru/strings.xml
index f277eca..e0cc4ab2 100644
--- a/packages/PackageInstaller/res/values-ru/strings.xml
+++ b/packages/PackageInstaller/res/values-ru/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Удалить приложение?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Удалить это приложение для "<b>"всех"</b>" пользователей устройства? Они потеряют доступ как к приложению, так и к связанным с ним данным."<b></b></string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Удалить это приложение из профиля <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Удалить это приложение из рабочего профиля?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Установить исходную версию приложения? Все его данные будут удалены."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Установить исходную версию приложения? Его данные будут удалены из всех профилей устройства, в том числе рабочих."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Сохранить данные приложения (<xliff:g id="SIZE">%1$s</xliff:g>)"</string>
diff --git a/packages/PackageInstaller/res/values-si/strings.xml b/packages/PackageInstaller/res/values-si/strings.xml
index 4b941bb..fb2344e 100644
--- a/packages/PackageInstaller/res/values-si/strings.xml
+++ b/packages/PackageInstaller/res/values-si/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"ඔබට මෙම යෙදුම අස්ථාපනය කිරීමට අවශ්යද?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119"><b>"සියලු"</b>" පරිශීලකයන් සඳහා මෙම යෙදුම අස්ථාපනය කිරීමට ඔබට අවශ්යද? උපාංගයෙහි "<b>"සියලු"</b>" පරිශීලකයන් සඳහා යෙදුම සහ එහි දත්ත ඉවත්වනු ඇත."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> පරිශීලකයා සඳහා මෙම යෙදුම අස්ථාපනය කිරීමට ඔබට අවශ්යයද?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ඔබට කාර්යාල පැතිකඩ වෙතින් මෙම යෙදුම අස්ථාපනය කිරීමට අවශ්යද?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"මෙම යෙදුම කර්මාන්ත ශාලා අනුවාදයක් සමගින් ප්රතිස්ථාපනය කරන්නද? සියලු දත්ත ඉවත් කරනු ඇත."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"මෙම යෙදුම කර්මාන්ත ශාලා අනුවාදයක් සමගින් ප්රතිස්ථාපනය කරන්නද? සියලු දත්ත ඉවත් කරනු ඇත. මෙය කාර්යාල පැතිකඩවල් සහිත අය ඇතුළුව, මෙම උපාංගයෙහි සියලු පරිශීලකයන් වෙත බලපානු ඇත."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"යෙදුම් දත්තවලින් <xliff:g id="SIZE">%1$s</xliff:g> තබා ගන්න."</string>
diff --git a/packages/PackageInstaller/res/values-sk/strings.xml b/packages/PackageInstaller/res/values-sk/strings.xml
index 10aa411..88ade43 100644
--- a/packages/PackageInstaller/res/values-sk/strings.xml
+++ b/packages/PackageInstaller/res/values-sk/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Chcete túto aplikáciu odinštalovať?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Chcete odinštalovať túto aplikáciu pre "<b>"všetkých"</b>" používateľov? Aplikácia a jej údaje sa odstránia z tohto zariadenia pre "<b>"všetkých"</b>" používateľov."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Chcete túto aplikáciu odinštalovať pre používateľa <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Chcete túto aplikáciu odinštalovať zo svojho pracovného profilu?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Nahradiť túto aplikáciu výrobnou verziou? Všetky údaje sa odstránia."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Nahradiť túto aplikáciu výrobnou verziou? Všetky údaje sa odstránia. Ovplyvní to všetkých používateľov tohto zariadenia vrátane tých s pracovnými profilmi."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Zachovať nasledujúcu veľkosť dát aplikácie: <xliff:g id="SIZE">%1$s</xliff:g>."</string>
diff --git a/packages/PackageInstaller/res/values-sl/strings.xml b/packages/PackageInstaller/res/values-sl/strings.xml
index a1e56fe..6e5c167 100644
--- a/packages/PackageInstaller/res/values-sl/strings.xml
+++ b/packages/PackageInstaller/res/values-sl/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Ali želite odmestiti to aplikacijo?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Ali želite odstraniti aplikacijo za "<b>"vse"</b>" uporabnike? Aplikacija in njeni podatki bodo odstranjeni iz "<b>"vseh"</b>" uporabnikov v napravi."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Ali želite to aplikacijo odstraniti za uporabnika <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Ali želite to aplikacijo odmestiti iz delovnega profila?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Želite to aplikacijo nadomestiti s tovarniško različico? Odstranjeni bodo vsi podatki."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Želite to aplikacijo nadomestiti s tovarniško različico? Odstranjeni bodo vsi podatki. To vpliva na vse uporabnike te naprave, vključno s tistimi z delovnimi profili."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Obdrži <xliff:g id="SIZE">%1$s</xliff:g> podatkov aplikacije."</string>
diff --git a/packages/PackageInstaller/res/values-sq/strings.xml b/packages/PackageInstaller/res/values-sq/strings.xml
index f7dca91..b8ada36 100644
--- a/packages/PackageInstaller/res/values-sq/strings.xml
+++ b/packages/PackageInstaller/res/values-sq/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Dëshiron ta çinstalosh këtë aplikacion?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Dëshiron ta çinstalosh këtë aplikacion për "<b>"të gjithë"</b>" përdoruesit? Aplikacioni dhe të dhënat e tij do të hiqen nga "<b>"të gjithë"</b>" përdoruesit e pajisjes."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Dëshiron ta çinstalosh këtë aplikacion për përdoruesin <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Dëshiron ta çinstalosh këtë aplikacion nga profili yt i punës?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Të zëvendësohet ky aplikacion me versionin e fabrikës? Të gjitha të dhënat do të hiqen."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Të zëvendësohet ky aplikacion me versionin e fabrikës? Të gjitha të dhënat do të hiqen. Kjo ndikon te të gjithë përdoruesit e kësaj pajisjeje, duke përfshirë ata me profile të punës."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Mbaj <xliff:g id="SIZE">%1$s</xliff:g> nga të dhënat e aplikacionit."</string>
diff --git a/packages/PackageInstaller/res/values-sr/strings.xml b/packages/PackageInstaller/res/values-sr/strings.xml
index c6d5279..0f5252a 100644
--- a/packages/PackageInstaller/res/values-sr/strings.xml
+++ b/packages/PackageInstaller/res/values-sr/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Желите ли да деинсталирате ову апликацију?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Да ли желите да деинсталирате ову апликацију за "<b>"све"</b>" кориснике? Апликација и подаци уз ње биће уклоњени за "<b>"све"</b>" кориснике овог уређаја."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Желите ли да деинсталирате ову апликацију за корисника <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Да ли желите да деинсталирате ову апликацију са пословног профила?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Желите ли да замените ову апликацију фабричком верзијом? Сви подаци ће бити уклоњени."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Желите ли да замените ову апликацију фабричком верзијом? Сви подаци ће бити уклоњени. Ово утиче на све кориснике овог уређаја, укључујући и оне са пословним профилима."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Задржи <xliff:g id="SIZE">%1$s</xliff:g> података апликације."</string>
diff --git a/packages/PackageInstaller/res/values-sv/strings.xml b/packages/PackageInstaller/res/values-sv/strings.xml
index c64c02f..231e3e1 100644
--- a/packages/PackageInstaller/res/values-sv/strings.xml
+++ b/packages/PackageInstaller/res/values-sv/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Vill du avinstallera appen?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Vill du avinstallera den här appen för "<b>"alla"</b>" användare? Appen och alla data i den tas bort från "<b>"alla"</b>" användare på enheten."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Vill du avinstallera appen för användaren <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Vill du avinstallera appen från jobbprofilen?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Vill du ersätta den här appen med den version som var installerad när enheten var ny? All information tas bort."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Vill du ersätta den här appen med den version som var installerad när enheten var ny? All information tas bort. Detta påverkar alla som använder enheten, även dem med jobbprofiler."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Behåll <xliff:g id="SIZE">%1$s</xliff:g> appdata."</string>
diff --git a/packages/PackageInstaller/res/values-sw/strings.xml b/packages/PackageInstaller/res/values-sw/strings.xml
index 5c2ec6e..65b785f 100644
--- a/packages/PackageInstaller/res/values-sw/strings.xml
+++ b/packages/PackageInstaller/res/values-sw/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Ungependa kuondoa programu hii?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Je, ungependa kuondoa programu hii kwa watumiaji "<b>"wote"</b>"? Programu na data yake zitaondolewa kutoka kwa watumiaji "<b>"wote"</b>" kwenye kifaa."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Je, ungependa kuondoa programu hii kwa mtumiaji <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Ungependa kuondoa programu hii kwenye wasifu wako wa kazini?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Ungependa kubadilisha programu hii na toleo la kiwandani? Data yote itaondolewa."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Ungependa kubadilisha programu hii na toleo la kiwandani? Data yote itaondolewa. Hatua hii itaathiri watumiaji wote wa kifaa hiki, ikiwa ni pamoja na wale walio na wasifu za kazini."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Dumisha <xliff:g id="SIZE">%1$s</xliff:g> ya data ya programu."</string>
diff --git a/packages/PackageInstaller/res/values-ta/strings.xml b/packages/PackageInstaller/res/values-ta/strings.xml
index 4493a41..62e531a 100644
--- a/packages/PackageInstaller/res/values-ta/strings.xml
+++ b/packages/PackageInstaller/res/values-ta/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"இந்த ஆப்ஸை நிறுவல் நீக்க விரும்புகிறீர்களா?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"இந்த ஆப்ஸை "<b>"அனைத்துப்"</b>" பயனர்களுக்கும் நிறுவல் நீக்க விரும்புகிறீர்களா? ஆப்ஸும் அதன் தரவும் சாதனத்திலுள்ள "<b>"அனைத்துப்"</b>" பயனர்களிடமிருந்தும் அகற்றப்படும்."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> என்ற பயனருக்கு இந்த ஆப்ஸை நிறுவல் நீக்க விரும்புகிறீர்களா?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"உங்கள் பணிக் கணக்கிலிருந்து இந்த ஆப்ஸை நிறுவல் நீக்க விரும்புகிறீர்களா?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"ஆரம்பநிலைப் பதிப்புக்கு இந்த ஆப்ஸை மாற்றியமைக்கவா? அனைத்துத் தரவும் அகற்றப்படும்."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ஆரம்பநிலைப் பதிப்புக்கு இந்த ஆப்ஸை மாற்றியமைக்கவா? அனைத்துத் தரவும் அகற்றப்படும். பணிக் கணக்குகளுடன் உள்ளவர்கள் உட்பட இந்தச் சாதனத்தின் அனைத்துப் பயனர்களையும் இது பாதிக்கும்."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> ஆப்ஸ் தரவை வைத்திரு."</string>
diff --git a/packages/PackageInstaller/res/values-te/strings.xml b/packages/PackageInstaller/res/values-te/strings.xml
index 33543fd..57c2024 100644
--- a/packages/PackageInstaller/res/values-te/strings.xml
+++ b/packages/PackageInstaller/res/values-te/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"మీరు ఈ యాప్ను అన్ఇన్స్టాల్ చేయాలనుకుంటున్నారా?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"మీరు ఈ యాప్ను "<b>"అందరు"</b>" వినియోగదారులకు అన్ఇన్స్టాల్ చేయాలనుకుంటున్నారా? అప్లికేషన్, దాని డేటా పరికరంలోని "<b>"అందరు"</b>" వినియోగదారుల నుండి తీసివేయబడుతుంది."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"మీరు వినియోగదారు <xliff:g id="USERNAME">%1$s</xliff:g> కోసం ఈ యాప్ను అన్ఇన్స్టాల్ చేయాలనుకుంటున్నారా?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"మీ వర్క్ ప్రొఫైల్ నుండి ఈ యాప్ను మీరు అన్ఇన్స్టాల్ చేయాలనుకుంటున్నారా?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"ఈ యాప్ను ఫ్యాక్టరీ వెర్షన్తో భర్తీ చేయాలా? మొత్తం డేటా తీసివేయబడుతుంది."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"ఈ యాప్ను ఫ్యాక్టరీ వెర్షన్తో భర్తీ చేయాలా? మొత్తం డేటా తీసివేయబడుతుంది. దీని ప్రభావం కార్యాలయ ప్రొఫైల్లు కలిగి ఉన్నవారితో సహా ఈ పరికర వినియోగదారులందరిపై ఉంటుంది."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> యాప్ డేటాని ఉంచండి."</string>
diff --git a/packages/PackageInstaller/res/values-th/strings.xml b/packages/PackageInstaller/res/values-th/strings.xml
index 5b15f0b..409672b 100644
--- a/packages/PackageInstaller/res/values-th/strings.xml
+++ b/packages/PackageInstaller/res/values-th/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"ต้องการถอนการติดตั้งแอปนี้ไหม"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"ต้องการถอนการติดตั้งแอปนี้สำหรับผู้ใช้"<b>"ทั้งหมด"</b>"ไหม ระบบจะนำแอปและข้อมูลในแอปออกจากผู้ใช้"<b>"ทั้งหมด"</b>"ที่อยู่ในอุปกรณ์"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"ต้องการถอนการติดตั้งแอปนี้สำหรับผู้ใช้ <xliff:g id="USERNAME">%1$s</xliff:g> ไหม"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"คุณต้องการถอนการติดตั้งแอปนี้จากโปรไฟล์งานใช่ไหม"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"แทนที่แอปนี้ด้วยเวอร์ชันเริ่มต้นไหม ระบบจะนำข้อมูลทั้งหมดออก"</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"แทนที่แอปนี้ด้วยเวอร์ชันเริ่มต้นไหม ระบบจะนำข้อมูลทั้งหมดออก วิธีนี้จะส่งผลต่อผู้ใช้ทุกคนที่ใช้อุปกรณ์เครื่องนี้ รวมทั้งผู้ที่มีโปรไฟล์งาน"</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"เก็บข้อมูลแอปไว้ <xliff:g id="SIZE">%1$s</xliff:g>"</string>
diff --git a/packages/PackageInstaller/res/values-tl/strings.xml b/packages/PackageInstaller/res/values-tl/strings.xml
index 6b992f6..5606eb5 100644
--- a/packages/PackageInstaller/res/values-tl/strings.xml
+++ b/packages/PackageInstaller/res/values-tl/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Gusto mo bang i-uninstall ang app na ito?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Gusto mo bang i-uninstall ang app na ito para sa "<b>"lahat"</b>" ng user? Aalisin ang application at ang data nito sa "<b>"lahat"</b>" ng user sa device."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Gusto mo bang i-uninstall ang app na ito para sa user na si <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Gusto mo bang i-uninstall ang app na ito sa iyong profile sa trabaho?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Gusto mo bang palitan ang app na ito ng factory na bersyon? Maaalis ang lahat ng data."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Gusto mo bang palitan ang app na ito ng factory na bersyon? Maaalis ang lahat ng data. Nakakaapekto ito sa lahat ng user ng device na ito, kabilang ang mga may profile sa trabaho."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Panatilihin ang <xliff:g id="SIZE">%1$s</xliff:g> ng data ng app."</string>
diff --git a/packages/PackageInstaller/res/values-tr/strings.xml b/packages/PackageInstaller/res/values-tr/strings.xml
index 81dc24f..673511c 100644
--- a/packages/PackageInstaller/res/values-tr/strings.xml
+++ b/packages/PackageInstaller/res/values-tr/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Bu uygulamanın yüklemesini kaldırmak istiyor musunuz?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Bu uygulamanın yüklemesini "<b>"tüm"</b>" kullanıcılar için kaldırmak istiyor musunuz? Uygulama ve verileri cihazdan "<b>"tüm"</b>" kullanıcılar için kaldırılacaktır."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"<xliff:g id="USERNAME">%1$s</xliff:g> adlı kullanıcı için bu uygulamanın yüklemesini kaldırmak istiyor musunuz?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Bu uygulamanın iş profilinizdeki yüklemesini kaldırmak istiyor musunuz?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Bu uygulamayı fabrika sürümüyle değiştirmek istiyor musunuz? Tüm veriler silinecektir."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Bu uygulamayı fabrika sürümüyle değiştirmek istiyor musunuz? Tüm veriler silinecektir. Bu, çalışma profilleri olan kullanıcılar da dahil olmak üzere cihazı kullanan tüm kullanıcıları etkiler."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Uygulama verilerinin <xliff:g id="SIZE">%1$s</xliff:g> kadarını sakla."</string>
diff --git a/packages/PackageInstaller/res/values-uk/strings.xml b/packages/PackageInstaller/res/values-uk/strings.xml
index 44a496d..2169b17 100644
--- a/packages/PackageInstaller/res/values-uk/strings.xml
+++ b/packages/PackageInstaller/res/values-uk/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Видалити цей додаток?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Хочете видалити цю програму для "<b>"всіх"</b>" користувачів? Програму та її дані буде видалено для "<b>"всіх"</b>" користувачів цього пристрою."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Видалити цей додаток для користувача <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Видалити цей додаток із вашого робочого профілю?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Відновити заводську версію цього додатка? Усі дані буде видалено."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Відновити заводську версію цього додатка? Усі дані буде видалено. Це вплине на всіх користувачів цього пристрою, зокрема на користувачів із робочими профілями."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Залишити <xliff:g id="SIZE">%1$s</xliff:g> даних додатка."</string>
diff --git a/packages/PackageInstaller/res/values-ur/strings.xml b/packages/PackageInstaller/res/values-ur/strings.xml
index afe46997..57fc568 100644
--- a/packages/PackageInstaller/res/values-ur/strings.xml
+++ b/packages/PackageInstaller/res/values-ur/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"کیا آپ اس ایپ کو اَن انسٹال کرنا چاہتے ہیں؟"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"کیا آپ "<b>"سبھی"</b>" صارفین کیلئے اس ایپ کو اَن انسٹال کرنا چاہتے ہیں؟ ایپلیکیشن اور اس کا ڈیٹا آلہ پر موجود "<b>"سبھی"</b>" صارفین سے ہٹا دیا جائے گا۔"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"کیا آپ اس ایپ کو صارف <xliff:g id="USERNAME">%1$s</xliff:g> کیلئے اَن انسٹال کرنا چاہتے ہیں؟"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"کیا آپ اپنے دفتری پروفائل سے یہ ایپ اَن انسٹال کرنا چاہتے ہیں؟"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"اس ایپ کو فیکٹری ورژن سے تبدیل کریں؟ تمام ڈیٹا ہٹا دیا جائے گا۔"</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"اس ایپ کو فیکٹری ورژن سے تبدیل کریں؟ تمام ڈیٹا ہٹا دیا جائے گا۔ اس سے دفتری پروفائلز کے حاملین سمیت اس آلہ کے تمام صارفین متاثر ہوں گے۔"</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"ایپ ڈیٹا کا <xliff:g id="SIZE">%1$s</xliff:g> رکھیں۔"</string>
diff --git a/packages/PackageInstaller/res/values-uz/strings.xml b/packages/PackageInstaller/res/values-uz/strings.xml
index fc1b916..f3d16b5 100644
--- a/packages/PackageInstaller/res/values-uz/strings.xml
+++ b/packages/PackageInstaller/res/values-uz/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Bu ilovani o‘chirib tashlamoqchimisiz?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Ushbu ilova "<b>"barcha"</b>" foydalanuvchilar uchun o‘chirilsinmi? Ilova va uning axborotlari qurilmadagi "<b>"barcha"</b>" foydalanuvchilardan o‘chib ketadi."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Haqiqatdan ham <xliff:g id="USERNAME">%1$s</xliff:g> foydalanuvchi uchun ushbu ilovani olib tashlamoqchimisiz?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Bu ilova ish profilidan olib tashlansinmi?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Bu ilova boshlang‘ich versiyasi bilan almashtirilsinmi? Barcha axborotlar o‘chirib tashlanadi."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Bu ilova boshlang‘ich versiyasi bilan almashtirilsinmi? Barcha axborotlar o‘chirib tashlanadi. Bu qurilmaning barcha foydalanuvchilariga, jumladan, ularning ishchi profillariga ham ta’sir qiladi."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"<xliff:g id="SIZE">%1$s</xliff:g> hajmdagi ilova axborotlari saqlab qolinsin"</string>
diff --git a/packages/PackageInstaller/res/values-vi/strings.xml b/packages/PackageInstaller/res/values-vi/strings.xml
index 03b381b..eacbe1d 100644
--- a/packages/PackageInstaller/res/values-vi/strings.xml
+++ b/packages/PackageInstaller/res/values-vi/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Bạn có muốn gỡ cài đặt ứng dụng này không?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Bạn có muốn gỡ cài đặt ứng dụng này cho "<b>"tất cả"</b>" người dùng không? Ứng dụng và dữ liệu của ứng dụng sẽ bị xóa khỏi "<b>"tất cả"</b>" người dùng trên thiết bị."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Bạn có muốn gỡ cài đặt ứng dụng này cho người dùng <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Bạn có muốn gỡ cài đặt ứng dụng này khỏi hồ sơ công việc của mình không?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Thay thế ứng dụng này bằng phiên bản gốc? Tất cả dữ liệu sẽ bị xóa."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Thay thế ứng dụng này bằng phiên bản gốc? Tất cả dữ liệu sẽ bị xóa. Điều này ảnh hưởng đến tất cả người dùng thiết bị này, bao gồm cả những người có hồ sơ công việc."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Giữ lại <xliff:g id="SIZE">%1$s</xliff:g> dữ liệu ứng dụng."</string>
diff --git a/packages/PackageInstaller/res/values-zh-rCN/strings.xml b/packages/PackageInstaller/res/values-zh-rCN/strings.xml
index e53dd46..924397f 100644
--- a/packages/PackageInstaller/res/values-zh-rCN/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rCN/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"要卸载此应用吗?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"要为"<b>"所有"</b>"用户卸载此应用吗?系统将为设备上的"<b>"所有"</b>"用户移除此应用及其数据。"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"要为用户<xliff:g id="USERNAME">%1$s</xliff:g>卸载此应用吗?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"您想从您的工作资料中卸载此应用吗?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"要将此应用替换为出厂版本吗?这样会移除所有数据。"</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"要将此应用替换为出厂版本吗?这样会移除所有数据,并会影响此设备的所有用户(包括已设置工作资料的用户)。"</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"保留 <xliff:g id="SIZE">%1$s</xliff:g> 的应用数据。"</string>
diff --git a/packages/PackageInstaller/res/values-zh-rHK/strings.xml b/packages/PackageInstaller/res/values-zh-rHK/strings.xml
index 1d00963..dce8cfe 100644
--- a/packages/PackageInstaller/res/values-zh-rHK/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rHK/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"您要解除安裝此應用程式嗎?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"您要為"<b>"所有"</b>"使用者解除安裝這個應用程式嗎?應用程式及其資料會從裝置上的"<b>"所有"</b>"使用者設定檔中移除。"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"您要為使用者<xliff:g id="USERNAME">%1$s</xliff:g>解除安裝此應用程式嗎?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"要從工作設定檔解除安裝此應用程式嗎?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"要將此應用程式回復至原廠版本嗎?系統會移除所有資料。"</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"要將此應用程式回復至原廠版本嗎?系統會移除所有資料。此裝置的所有使用者 (包括使用工作設定檔的使用者) 亦會受影響。"</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"保留應用程式資料 (<xliff:g id="SIZE">%1$s</xliff:g>)。"</string>
diff --git a/packages/PackageInstaller/res/values-zh-rTW/strings.xml b/packages/PackageInstaller/res/values-zh-rTW/strings.xml
index e54e351..383802e 100644
--- a/packages/PackageInstaller/res/values-zh-rTW/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rTW/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"要解除安裝這個應用程式嗎?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"要為"<b>"所有"</b>"使用者解除安裝這個應用程式嗎?該應用程式及其資料會從裝置上的"<b>"所有"</b>"使用者設定檔移除。"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"要為使用者 <xliff:g id="USERNAME">%1$s</xliff:g> 解除安裝這個應用程式嗎?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"要從工作資料夾解除安裝這個應用程式嗎?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"要將應用程式換成原廠版本嗎?這麼做會移除所有資料。"</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"要將應用程式換成原廠版本嗎?這麼做會移除所有資料。凡是這個裝置的使用者 (包括設置工作資料夾的使用者),皆會受到影響。"</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"保留 <xliff:g id="SIZE">%1$s</xliff:g> 的應用程式資料。"</string>
diff --git a/packages/PackageInstaller/res/values-zu/strings.xml b/packages/PackageInstaller/res/values-zu/strings.xml
index c61b980..ef88552 100644
--- a/packages/PackageInstaller/res/values-zu/strings.xml
+++ b/packages/PackageInstaller/res/values-zu/strings.xml
@@ -56,6 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"Ufuna ukukhipha le app?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Ingabe ufuna ukukhipha lolu hlelo lokusebenza kubo "<b>"bonke"</b>" abasebenzisi? Uhlelo lokusebenza nedatha yalo kuzosuswa kubo "<b>"bonke"</b>" abasebenzisi kudivayisi."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Ingabe ufuna ukukhiphela lolu hlelo lokusebenza kumsebenzisi ongu-<xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
+ <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Ingabe ufuna ukukhipha le app kusukela kuphrofayela yakho yokusebenza?"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Shintshanisa lolu hlelo lokusebenza ngenguqulo yasekuqaleni? Yonke idatha izosuswa."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Shintshanisa lolu hlelo lokusebenza ngenguqulo yasekuqaleni? Yonke idatha izosuswa. Lokhu kuthinta bonke abasebenzisi bale divayisi, abafaka labo abanamaphrofayela wokusebenza."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Gcina u-<xliff:g id="SIZE">%1$s</xliff:g> wedatha yohlelo lokusebenza."</string>
@@ -87,7 +88,7 @@
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Ithebulethi yakho nedatha yomuntu siqu zisengcupheni kakhulu ekuhlaselweni izinhlelo zokusebenza ezingaziwa. Ngokufaka lolu hlelo lokusebenza, uyavuma ukuthi unesibopho sanoma ikuphi ukonakala kuthebulethi yakho noma ukulahleka kwedatha okungabangelwa ukusetshenziswa kwayo."</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Idatha yakho ye-TV neyomuntu siqu isengcupheni kakhulu ekuhlaselweni izinhlelo zokusebenza ezingaziwa. Ngokufaka lolu hlelo lokusebenza, uyavuma ukuthi unesibopho sanoma ikuphi ukonakala ku-TV yakho noma ukulahlekelwa kwedatha okungabangelwa ukusetshenziswa kwayo."</string>
<string name="anonymous_source_continue" msgid="4375745439457209366">"Qhubeka"</string>
- <string name="external_sources_settings" msgid="4046964413071713807">"Izilungiselelo"</string>
+ <string name="external_sources_settings" msgid="4046964413071713807">"Amasethingi"</string>
<string name="wear_app_channel" msgid="1960809674709107850">"Ifaka/ikhipha izinhlelo zokusebenza ze-wear"</string>
<string name="app_installed_notification_channel_description" msgid="2695385797601574123">"Isaziso sokufakwa kohlelo lokusebenza"</string>
<string name="notification_installation_success_message" msgid="6450467996056038442">"Ifakwe ngempumelelo"</string>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java b/packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java
index 7e0490a..063d789 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java
@@ -264,7 +264,8 @@
String action = ACTION_INSTALL_COMMIT + "." + packageName;
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(action);
- mContext.registerReceiver(broadcastReceiver, intentFilter);
+ mContext.registerReceiver(broadcastReceiver, intentFilter,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
// Create a matching PendingIntent and use it to generate the IntentSender
Intent broadcastIntent = new Intent(action);
diff --git a/packages/PrintSpooler/res/values-te/strings.xml b/packages/PrintSpooler/res/values-te/strings.xml
index 50e6f3b..a1ed2ca 100644
--- a/packages/PrintSpooler/res/values-te/strings.xml
+++ b/packages/PrintSpooler/res/values-te/strings.xml
@@ -31,8 +31,8 @@
<string name="template_all_pages" msgid="3322235982020148762">"మొత్తం <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
<string name="template_page_range" msgid="428638530038286328">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g> పరిధి"</string>
<string name="pages_range_example" msgid="8558694453556945172">"ఉదా. 1—5,8,11—13"</string>
- <string name="print_preview" msgid="8010217796057763343">"ముద్రణ పరిదృశ్యం"</string>
- <string name="install_for_print_preview" msgid="6366303997385509332">"పరిదృశ్యం చేయడానికి PDF వ్యూయర్ను ఇన్స్టాల్ చేయండి"</string>
+ <string name="print_preview" msgid="8010217796057763343">"ముద్రణ ప్రివ్యూ"</string>
+ <string name="install_for_print_preview" msgid="6366303997385509332">"ప్రివ్యూ చేయడానికి PDF వ్యూయర్ను ఇన్స్టాల్ చేయండి"</string>
<string name="printing_app_crashed" msgid="854477616686566398">"ముద్రణ యాప్ క్రాష్ అయ్యింది"</string>
<string name="generating_print_job" msgid="3119608742651698916">"ముద్రణ జాబ్ను ఉత్పన్నం చేస్తోంది"</string>
<string name="save_as_pdf" msgid="5718454119847596853">"PDF వలె సేవ్ చేయి"</string>
@@ -106,6 +106,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"క్షమించండి, అది పని చేయలేదు. మళ్లీ ప్రయత్నించండి."</string>
<string name="print_error_retry" msgid="1426421728784259538">"మళ్లీ ప్రయత్నించు"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"ఈ ప్రింటర్ ప్రస్తుతం అందుబాటులో లేదు."</string>
- <string name="print_cannot_load_page" msgid="6179560924492912009">"పరిదృశ్యాన్ని ప్రదర్శించడం సాధ్యపడలేదు"</string>
- <string name="print_preparing_preview" msgid="3939930735671364712">"పరిదృశ్యం సిద్ధమవుతోంది…"</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"ప్రివ్యూను ప్రదర్శించడం సాధ్యపడలేదు"</string>
+ <string name="print_preparing_preview" msgid="3939930735671364712">"ప్రివ్యూ సిద్ధమవుతోంది…"</string>
</resources>
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/BasePreferencesFragment.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/BasePreferencesFragment.java
new file mode 100644
index 0000000..8ebbac3
--- /dev/null
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/BasePreferencesFragment.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.collapsingtoolbar;
+
+import androidx.fragment.app.FragmentActivity;
+import androidx.preference.PreferenceFragmentCompat;
+
+import com.android.settingslib.utils.BuildCompatUtils;
+
+import com.google.android.material.appbar.AppBarLayout;
+
+/**
+ * A base fragment that supports multi-fragments in one activity. The activity likes to switch the
+ * different fragments which extend this base fragment and must use the following code to add the
+ * fragment to stack.
+ *
+ * protected void onCreate(Bundle savedState) {
+ * // omitted…
+ * getFragmentManager()
+ * .beginTransaction()
+ * .add(R.id.content_frame, new Your_Fragment())
+ * // Add root page to back-history
+ * .addToBackStack( null)
+ * .commit();
+ * // omitted
+ * }
+ */
+public abstract class BasePreferencesFragment extends PreferenceFragmentCompat {
+
+ /**
+ * Gets the title which the fragment likes to show on app bar. The child class must implement
+ * this
+ * function.
+ *
+ * @return The title of the fragment will show on app bar.
+ */
+ public abstract CharSequence getTitle();
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ FragmentActivity activity = getActivity();
+ if (activity != null) {
+ activity.setTitle(getTitle());
+
+ if (BuildCompatUtils.isAtLeastS()) {
+ AppBarLayout appBarLayout = (AppBarLayout) activity.findViewById(R.id.app_bar);
+
+ if (appBarLayout != null) {
+ appBarLayout.setExpanded(/* expanded= */ true);
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
index 84a6b36..543a5a0 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
@@ -23,16 +23,13 @@
import android.view.ViewGroup;
import android.widget.Toolbar;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.fragment.app.FragmentActivity;
import com.android.settingslib.utils.BuildCompatUtils;
import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
-import com.google.android.material.resources.TextAppearanceConfig;
/**
* A base Activity that has a collapsing toolbar layout is used for the activities intending to
@@ -40,12 +37,22 @@
*/
public class CollapsingToolbarBaseActivity extends FragmentActivity {
- private static final float TOOLBAR_LINE_SPACING_MULTIPLIER = 1.1f;
+ private class DelegateCallback implements CollapsingToolbarDelegate.HostCallback {
+ @Nullable
+ @Override
+ public ActionBar setActionBar(Toolbar toolbar) {
+ CollapsingToolbarBaseActivity.super.setActionBar(toolbar);
+ return CollapsingToolbarBaseActivity.super.getActionBar();
+ }
- @Nullable
- private CollapsingToolbarLayout mCollapsingToolbarLayout;
- @Nullable
- private AppBarLayout mAppBarLayout;
+ @Override
+ public void setOuterTitle(CharSequence title) {
+ CollapsingToolbarBaseActivity.super.setTitle(title);
+ }
+ }
+
+ private CollapsingToolbarDelegate mToolbardelegate;
+
private int mCustomizeLayoutResId = 0;
@Override
@@ -55,31 +62,16 @@
super.setContentView(mCustomizeLayoutResId);
return;
}
- // Force loading font synchronously for collapsing toolbar layout
- TextAppearanceConfig.setShouldLoadFontSynchronously(true);
- super.setContentView(R.layout.collapsing_toolbar_base_layout);
- mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
- mAppBarLayout = findViewById(R.id.app_bar);
- if (mCollapsingToolbarLayout != null) {
- mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER);
- }
- disableCollapsingToolbarLayoutScrollingBehavior();
- final Toolbar toolbar = findViewById(R.id.action_bar);
- setActionBar(toolbar);
-
- // Enable title and home button by default
- final ActionBar actionBar = getActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setHomeButtonEnabled(true);
- actionBar.setDisplayShowTitleEnabled(true);
- }
+ mToolbardelegate = new CollapsingToolbarDelegate(new DelegateCallback());
+ View view = mToolbardelegate.onCreateView(getLayoutInflater(), null);
+ super.setContentView(view);
}
@Override
public void setContentView(int layoutResID) {
- final ViewGroup parent = findViewById(R.id.content_frame);
+ final ViewGroup parent = (mToolbardelegate == null) ? findViewById(R.id.content_frame)
+ : mToolbardelegate.getContentFrameLayout();
if (parent != null) {
parent.removeAllViews();
}
@@ -88,7 +80,8 @@
@Override
public void setContentView(View view) {
- final ViewGroup parent = findViewById(R.id.content_frame);
+ final ViewGroup parent = (mToolbardelegate == null) ? findViewById(R.id.content_frame)
+ : mToolbardelegate.getContentFrameLayout();
if (parent != null) {
parent.addView(view);
}
@@ -96,7 +89,8 @@
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
- final ViewGroup parent = findViewById(R.id.content_frame);
+ final ViewGroup parent = (mToolbardelegate == null) ? findViewById(R.id.content_frame)
+ : mToolbardelegate.getContentFrameLayout();
if (parent != null) {
parent.addView(view, params);
}
@@ -113,20 +107,12 @@
@Override
public void setTitle(CharSequence title) {
- if (mCollapsingToolbarLayout != null) {
- mCollapsingToolbarLayout.setTitle(title);
- } else {
- super.setTitle(title);
- }
+ mToolbardelegate.setTitle(title);
}
@Override
public void setTitle(int titleId) {
- if (mCollapsingToolbarLayout != null) {
- mCollapsingToolbarLayout.setTitle(getText(titleId));
- } else {
- super.setTitle(titleId);
- }
+ setTitle(getText(titleId));
}
@Override
@@ -142,7 +128,7 @@
*/
@Nullable
public CollapsingToolbarLayout getCollapsingToolbarLayout() {
- return mCollapsingToolbarLayout;
+ return mToolbardelegate.getCollapsingToolbarLayout();
}
/**
@@ -150,23 +136,6 @@
*/
@Nullable
public AppBarLayout getAppBarLayout() {
- return mAppBarLayout;
- }
-
- private void disableCollapsingToolbarLayoutScrollingBehavior() {
- if (mAppBarLayout == null) {
- return;
- }
- final CoordinatorLayout.LayoutParams params =
- (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
- final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
- behavior.setDragCallback(
- new AppBarLayout.Behavior.DragCallback() {
- @Override
- public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
- return false;
- }
- });
- params.setBehavior(behavior);
+ return mToolbardelegate.getAppBarLayout();
}
}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
index eb8b59e..b605074 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
@@ -16,7 +16,8 @@
package com.android.settingslib.collapsingtoolbar;
-import android.os.Build;
+import android.app.ActionBar;
+import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -37,44 +38,33 @@
*/
public abstract class CollapsingToolbarBaseFragment extends Fragment {
- private static final float TOOLBAR_LINE_SPACING_MULTIPLIER = 1.1f;
+ private class DelegateCallback implements CollapsingToolbarDelegate.HostCallback {
+ @Nullable
+ @Override
+ public ActionBar setActionBar(Toolbar toolbar) {
+ requireActivity().setActionBar(toolbar);
+ return null;
+ }
- @Nullable
- private CoordinatorLayout mCoordinatorLayout;
- @Nullable
- private CollapsingToolbarLayout mCollapsingToolbarLayout;
- @Nullable
- private AppBarLayout mAppBarLayout;
- @NonNull
- private Toolbar mToolbar;
- @NonNull
- private FrameLayout mContentFrameLayout;
+ @Override
+ public void setOuterTitle(CharSequence title) {
+ // ignore
+ }
+ }
+
+ private CollapsingToolbarDelegate mToolbardelegate;
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mToolbardelegate = new CollapsingToolbarDelegate(new DelegateCallback());
+ }
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
- final View view = inflater.inflate(R.layout.collapsing_toolbar_base_layout, container,
- false);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- mCoordinatorLayout = view.findViewById(R.id.content_parent);
- }
- mCollapsingToolbarLayout = view.findViewById(R.id.collapsing_toolbar);
- mAppBarLayout = view.findViewById(R.id.app_bar);
- if (mCollapsingToolbarLayout != null) {
- mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER);
- }
- disableCollapsingToolbarLayoutScrollingBehavior();
- mToolbar = view.findViewById(R.id.action_bar);
- mContentFrameLayout = view.findViewById(R.id.content_frame);
- return view;
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
-
- requireActivity().setActionBar(mToolbar);
+ return mToolbardelegate.onCreateView(inflater, container);
}
/**
@@ -82,7 +72,7 @@
*/
@Nullable
public CoordinatorLayout getCoordinatorLayout() {
- return mCoordinatorLayout;
+ return mToolbardelegate.getCoordinatorLayout();
}
/**
@@ -90,7 +80,7 @@
*/
@Nullable
public AppBarLayout getAppBarLayout() {
- return mAppBarLayout;
+ return mToolbardelegate.getAppBarLayout();
}
/**
@@ -98,7 +88,7 @@
*/
@Nullable
public CollapsingToolbarLayout getCollapsingToolbarLayout() {
- return mCollapsingToolbarLayout;
+ return mToolbardelegate.getCollapsingToolbarLayout();
}
/**
@@ -106,23 +96,6 @@
*/
@NonNull
public FrameLayout getContentFrameLayout() {
- return mContentFrameLayout;
- }
-
- private void disableCollapsingToolbarLayoutScrollingBehavior() {
- if (mAppBarLayout == null) {
- return;
- }
- final CoordinatorLayout.LayoutParams params =
- (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
- final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
- behavior.setDragCallback(
- new AppBarLayout.Behavior.DragCallback() {
- @Override
- public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
- return false;
- }
- });
- params.setBehavior(behavior);
+ return mToolbardelegate.getContentFrameLayout();
}
}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarDelegate.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarDelegate.java
new file mode 100644
index 0000000..30e3973
--- /dev/null
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarDelegate.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.collapsingtoolbar;
+
+import android.app.ActionBar;
+import android.os.Build;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.Toolbar;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+
+import com.google.android.material.appbar.AppBarLayout;
+import com.google.android.material.appbar.CollapsingToolbarLayout;
+
+/**
+ * A delegate that allows to use the collapsing toolbar layout in hosts that doesn't want/need to
+ * extend from {@link CollapsingToolbarBaseActivity} or from {@link CollapsingToolbarBaseFragment}.
+ */
+public class CollapsingToolbarDelegate {
+
+ /** Interface to be implemented by the host of the Collapsing Toolbar. */
+ public interface HostCallback {
+ /**
+ * Called when a Toolbar should be set on the host.
+ *
+ * <p>If the host wants action bar to be modified, it should return it.
+ */
+ @Nullable
+ ActionBar setActionBar(Toolbar toolbar);
+
+ /** Sets a title on the host. */
+ void setOuterTitle(CharSequence title);
+ }
+
+ private static final float TOOLBAR_LINE_SPACING_MULTIPLIER = 1.1f;
+
+ @Nullable
+ private CoordinatorLayout mCoordinatorLayout;
+ @Nullable
+ private CollapsingToolbarLayout mCollapsingToolbarLayout;
+ @Nullable
+ private AppBarLayout mAppBarLayout;
+ @NonNull
+ private Toolbar mToolbar;
+ @NonNull
+ private FrameLayout mContentFrameLayout;
+ @NonNull
+ private final HostCallback mHostCallback;
+
+ public CollapsingToolbarDelegate(@NonNull HostCallback hostCallback) {
+ mHostCallback = hostCallback;
+ }
+
+ /** Method to call that creates the root view of the collapsing toolbar. */
+ @SuppressWarnings("RestrictTo")
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container) {
+ final View view =
+ inflater.inflate(R.layout.collapsing_toolbar_base_layout, container, false);
+ if (view instanceof CoordinatorLayout) {
+ mCoordinatorLayout = (CoordinatorLayout) view;
+ }
+ mCollapsingToolbarLayout = view.findViewById(R.id.collapsing_toolbar);
+ mAppBarLayout = view.findViewById(R.id.app_bar);
+ if (mCollapsingToolbarLayout != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ mCollapsingToolbarLayout.setLineSpacingMultiplier(TOOLBAR_LINE_SPACING_MULTIPLIER);
+ }
+ disableCollapsingToolbarLayoutScrollingBehavior();
+ mToolbar = view.findViewById(R.id.action_bar);
+ mContentFrameLayout = view.findViewById(R.id.content_frame);
+ final ActionBar actionBar = mHostCallback.setActionBar(mToolbar);
+
+ // Enable title and home button by default
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setHomeButtonEnabled(true);
+ actionBar.setDisplayShowTitleEnabled(true);
+ }
+ return view;
+ }
+
+ /** Return an instance of CoordinatorLayout. */
+ @Nullable
+ public CoordinatorLayout getCoordinatorLayout() {
+ return mCoordinatorLayout;
+ }
+
+ /** Sets the title on the collapsing layout, delegating to host if needed. */
+ public void setTitle(CharSequence title) {
+ if (mCollapsingToolbarLayout != null) {
+ mCollapsingToolbarLayout.setTitle(title);
+ } else {
+ mHostCallback.setOuterTitle(title);
+ }
+ }
+
+ /** Returns an instance of collapsing toolbar. */
+ @Nullable
+ public CollapsingToolbarLayout getCollapsingToolbarLayout() {
+ return mCollapsingToolbarLayout;
+ }
+
+ /** Return the content frame layout. */
+ @NonNull
+ public FrameLayout getContentFrameLayout() {
+ return mContentFrameLayout;
+ }
+
+ public Toolbar getToolbar() {
+ return mToolbar;
+ }
+
+ /** Return an instance of app bar. */
+ @Nullable
+ public AppBarLayout getAppBarLayout() {
+ return mAppBarLayout;
+ }
+
+ private void disableCollapsingToolbarLayoutScrollingBehavior() {
+ if (mAppBarLayout == null) {
+ return;
+ }
+ final CoordinatorLayout.LayoutParams params =
+ (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
+ final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
+ behavior.setDragCallback(
+ new AppBarLayout.Behavior.DragCallback() {
+ @Override
+ public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
+ return false;
+ }
+ });
+ params.setBehavior(behavior);
+ }
+}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/SettingsTransitionActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/SettingsTransitionActivity.java
index 3a7fe3b..38afd44 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/SettingsTransitionActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/SettingsTransitionActivity.java
@@ -23,7 +23,6 @@
* Settings transition applied.
*/
public abstract class SettingsTransitionActivity extends FragmentActivity {
- private static final String TAG = "SettingsTransitionActivity";
protected boolean isSettingsTransitionEnabled() {
return false;
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_ic_info.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_ic_info.xml
new file mode 100644
index 0000000..c8037c8
--- /dev/null
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_ic_info.xml
@@ -0,0 +1,26 @@
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- copy from frameworks/base/core/res/res/drawable/ic_info.xml-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
index d0c2d0b..59ae122 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
@@ -42,7 +42,7 @@
android:theme="@android:style/Theme.Material"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
- android:src="@android:drawable/ic_info"
+ android:src="@drawable/settingslib_ic_info"
android:visibility="gone"/>
<Switch
@@ -51,6 +51,8 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/settingslib_switchbar_subsettings_margin_end"
+ android:focusable="false"
+ android:clickable="false"
android:theme="@style/SwitchBar.Switch.Settingslib"/>
</LinearLayout>
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
index 6d5615d..383bf8e 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
@@ -30,6 +30,7 @@
import android.widget.TextView;
import androidx.annotation.ColorInt;
+import androidx.annotation.Nullable;
import com.android.settingslib.utils.BuildCompatUtils;
@@ -97,6 +98,10 @@
}
addOnSwitchChangeListener((switchView, isChecked) -> setChecked(isChecked));
+ if (mSwitch.getVisibility() == VISIBLE) {
+ mSwitch.setOnCheckedChangeListener(this);
+ }
+
setChecked(mSwitch.isChecked());
if (attrs != null) {
@@ -118,6 +123,12 @@
}
@Override
+ public void setOnClickListener(@Nullable OnClickListener l) {
+ super.setOnClickListener(l);
+ mSwitch.setOnClickListener(l);
+ }
+
+ @Override
public boolean performClick() {
return mSwitch.performClick();
}
diff --git a/packages/SettingsLib/SearchWidget/res/values-sv/strings.xml b/packages/SettingsLib/SearchWidget/res/values-sv/strings.xml
index 96e0b4e..0dbc0ea 100644
--- a/packages/SettingsLib/SearchWidget/res/values-sv/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-sv/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="search_menu" msgid="1914043873178389845">"Sökinställningar"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Sök i inställningar"</string>
</resources>
diff --git a/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java b/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java
index 8e010fa..4eedab2 100644
--- a/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java
+++ b/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java
@@ -40,7 +40,7 @@
*/
public class UsageProgressBarPreference extends Preference {
- private final Pattern mNumberPattern = Pattern.compile("[\\d]*[\\.,]?[\\d]+");
+ private final Pattern mNumberPattern = Pattern.compile("[\\d]*[\\٫.,]?[\\d]+");
private CharSequence mUsageSummary;
private CharSequence mTotalSummary;
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 662ffdd..6357f3c 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -492,7 +492,7 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"جارٍ الشحن لاسلكيًا"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"لا يتم الشحن"</string>
<string name="battery_info_status_not_charging" msgid="3371084153747234837">"الجهاز متصل بالشاحن، ولا يتم الشحن."</string>
- <string name="battery_info_status_full" msgid="1339002294876531312">"تم الشحن"</string>
+ <string name="battery_info_status_full" msgid="1339002294876531312">"مشحونة"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"إعدادات يتحكم فيها المشرف"</string>
<string name="disabled" msgid="8017887509554714950">"غير مفعّل"</string>
<string name="external_source_trusted" msgid="1146522036773132905">"مسموح به"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index a816f49..d90c08a 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -612,7 +612,7 @@
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"सुरू करा"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"बंद करा"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"वाहक नेटवर्क बदलत आहे"</string>
- <string name="data_connection_3g" msgid="931852552688157407">"३G"</string>
+ <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
<string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
<string name="data_connection_cdma" msgid="9098161966701934334">"१X"</string>
<string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 8e20e02..47b0744 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1334,7 +1334,7 @@
<string name="notice_header" translatable="false"></string>
<!-- Name of the phone device. [CHAR LIMIT=30] -->
- <string name="media_transfer_this_device_name">Phone speaker</string>
+ <string name="media_transfer_this_device_name">This phone</string>
<!-- Name of the phone device with an active remote session. [CHAR LIMIT=30] -->
<string name="media_transfer_this_phone">This phone</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index a901160..290055c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -21,7 +21,6 @@
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHearingAid;
-import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
@@ -1131,9 +1130,18 @@
}
/**
- * @return resource for android auto string that describes the connection state of this device.
+ * See {@link #getCarConnectionSummary(boolean)}
*/
public String getCarConnectionSummary() {
+ return getCarConnectionSummary(false);
+ }
+
+ /**
+ * Returns android auto string that describes the connection state of this device.
+ *
+ * @param shortSummary {@code true} if need to return short version summary
+ */
+ public String getCarConnectionSummary(boolean shortSummary) {
boolean profileConnected = false; // at least one profile is connected
boolean a2dpNotConnected = false; // A2DP is preferred but not connected
boolean hfpNotConnected = false; // HFP is preferred but not connected
@@ -1151,6 +1159,10 @@
BluetoothUtils.getConnectionStateSummary(connectionStatus));
case BluetoothProfile.STATE_CONNECTED:
+ if (shortSummary) {
+ return mContext.getString(BluetoothUtils.getConnectionStateSummary(
+ connectionStatus), /* formatArgs= */ "");
+ }
profileConnected = true;
break;
@@ -1248,7 +1260,8 @@
}
return getBondState() == BluetoothDevice.BOND_BONDING ?
- mContext.getString(R.string.bluetooth_pairing) : null;
+ mContext.getString(R.string.bluetooth_pairing) :
+ mContext.getString(R.string.bluetooth_disconnected);
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index bbf0a02..4da47fd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -38,6 +38,8 @@
public static final String CATEGORY_SECURITY = "com.android.settings.category.ia.security";
public static final String CATEGORY_SECURITY_LOCKSCREEN =
"com.android.settings.category.ia.lockscreen";
+ public static final String CATEGORY_SECURITY_ADVANCED_SETTINGS =
+ "com.android.settings.category.ia.advanced_security";
public static final String CATEGORY_ACCOUNT = "com.android.settings.category.ia.accounts";
public static final String CATEGORY_ACCOUNT_DETAIL =
"com.android.settings.category.ia.account_detail";
diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSettingValuesWrapper.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSettingValuesWrapper.java
index 39e6dce..5860bda 100644
--- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSettingValuesWrapper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSettingValuesWrapper.java
@@ -27,6 +27,7 @@
import android.view.inputmethod.InputMethodManager;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.inputmethod.DirectBootAwareness;
import java.util.ArrayList;
import java.util.HashMap;
@@ -88,7 +89,8 @@
public void refreshAllInputMethodAndSubtypes() {
mMethodList.clear();
- mMethodList.addAll(mImm.getInputMethodListAsUser(mContentResolver.getUserId()));
+ mMethodList.addAll(mImm.getInputMethodListAsUser(
+ mContentResolver.getUserId(), DirectBootAwareness.ANY));
}
public List<InputMethodInfo> getInputMethodList() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
index 18c38c5..011ca0b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
@@ -32,7 +32,6 @@
import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
import android.net.NetworkTemplate;
-import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -172,7 +171,7 @@
return bucket.getRxBytes() + bucket.getTxBytes();
}
Log.w(TAG, "Failed to get data usage, no entry data");
- } catch (RemoteException e) {
+ } catch (RuntimeException e) {
Log.w(TAG, "Failed to get data usage, remote call failed");
}
return -1L;
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java
index 787dc55..42e7100 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkCycleChartDataLoader.java
@@ -18,7 +18,6 @@
import android.app.usage.NetworkStats;
import android.content.Context;
-import android.os.RemoteException;
import android.util.Log;
import java.util.ArrayList;
@@ -54,7 +53,7 @@
.setTotalUsage(total);
mData.add(builder.build());
}
- } catch (RemoteException e) {
+ } catch (RuntimeException e) {
Log.e(TAG, "Exception querying network detail.", e);
}
}
@@ -85,7 +84,7 @@
if (bucket != null) {
usage = bucket.getRxBytes() + bucket.getTxBytes();
}
- } catch (RemoteException e) {
+ } catch (RuntimeException e) {
Log.e(TAG, "Exception querying network detail.", e);
}
data.add(new NetworkCycleData.Builder()
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java
index ed093629..54d5c3d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/NetworkStatsSummaryLoader.java
@@ -20,7 +20,6 @@
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.net.NetworkTemplate;
-import android.os.RemoteException;
import android.util.Log;
import androidx.loader.content.AsyncTaskLoader;
@@ -55,7 +54,7 @@
public NetworkStats loadInBackground() {
try {
return mNetworkStatsManager.querySummary(mNetworkTemplate, mStart, mEnd);
- } catch (RemoteException e) {
+ } catch (RuntimeException e) {
Log.e(TAG, "Exception querying network detail.", e);
return null;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtils.java
new file mode 100644
index 0000000..21a4ac6
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtils.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.wifi;
+
+import android.content.Context;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.util.Log;
+
+import androidx.annotation.ChecksSdkIntAtLeast;
+
+/* Utility class is to confirm the Wi-Fi function is available by enterprise restriction */
+public class WifiEnterpriseRestrictionUtils {
+ private static final String TAG = "WifiEntResUtils";
+
+ /**
+ * Confirm Wi-Fi tethering is allowed according to whether user restriction is set
+ *
+ * @param context A context
+ * @return whether the device is permitted to use Wi-Fi Tethering
+ */
+ public static boolean isWifiTetheringAllowed(Context context) {
+ final UserManager userManager = context.getSystemService(UserManager.class);
+ final Bundle restrictions = userManager.getUserRestrictions();
+ if (isAtLeastT() && restrictions.getBoolean(UserManager.DISALLOW_WIFI_TETHERING)) {
+ Log.i(TAG, "Wi-Fi Tethering isn't available due to user restriction.");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Confirm Wi-Fi Direct is allowed according to whether user restriction is set
+ *
+ * @param context A context
+ * @return whether the device is permitted to use Wi-Fi Direct
+ */
+ public static boolean isWifiDirectAllowed(Context context) {
+ final UserManager userManager = context.getSystemService(UserManager.class);
+ final Bundle restrictions = userManager.getUserRestrictions();
+ if (isAtLeastT() && restrictions.getBoolean(UserManager.DISALLOW_WIFI_DIRECT)) {
+ Log.i(TAG, "Wi-Fi Direct isn't available due to user restriction.");
+ return false;
+ }
+ return true;
+ }
+
+ @ChecksSdkIntAtLeast(api=Build.VERSION_CODES.TIRAMISU)
+ private static boolean isAtLeastT() {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU;
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiRestrictionsCache.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiRestrictionsCache.java
new file mode 100644
index 0000000..7ffae40
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiRestrictionsCache.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.wifi;
+
+import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.util.SparseArray;
+
+import androidx.annotation.VisibleForTesting;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This is a singleton class for Wi-Fi restrictions caching.
+ */
+public class WifiRestrictionsCache {
+ private static final String TAG = "WifiResCache";
+
+ /**
+ * Manages mapping between user ID and corresponding singleton {@link WifiRestrictionsCache}
+ * object.
+ */
+ @VisibleForTesting
+ protected static final SparseArray<WifiRestrictionsCache> sInstances = new SparseArray<>();
+
+ @VisibleForTesting
+ protected UserManager mUserManager;
+ @VisibleForTesting
+ protected Bundle mUserRestrictions;
+ @VisibleForTesting
+ protected final Map<String, Boolean> mRestrictions = new HashMap<>();
+
+ /**
+ * @return an instance of {@link WifiRestrictionsCache} object.
+ */
+ @NonNull
+ public static WifiRestrictionsCache getInstance(@NonNull Context context) {
+ final int requestUserId = context.getUserId();
+ WifiRestrictionsCache cache;
+ synchronized (sInstances) {
+ // We have same user context as request.
+ if (sInstances.indexOfKey(requestUserId) >= 0) {
+ return sInstances.get(requestUserId);
+ }
+ // Request by a new user context.
+ cache = new WifiRestrictionsCache(context);
+ sInstances.put(context.getUserId(), cache);
+ }
+ return cache;
+ }
+
+ /**
+ * Removes all the instances.
+ */
+ public static void clearInstance() {
+ synchronized (sInstances) {
+ for (int i = 0; i < sInstances.size(); i++) {
+ int key = sInstances.keyAt(i);
+ WifiRestrictionsCache cache = sInstances.get(key);
+ cache.clearRestrictions();
+ sInstances.remove(key);
+ }
+ sInstances.clear();
+ }
+ }
+
+ /**
+ * Constructor to create a singleton class for Wi-Fi restrictions cache.
+ *
+ * @param context The Context this is associated with.
+ */
+ protected WifiRestrictionsCache(@NonNull Context context) {
+ mUserManager = context.getSystemService(UserManager.class);
+ if (mUserManager != null) {
+ mUserRestrictions = mUserManager.getUserRestrictions();
+ }
+ }
+
+ /**
+ * @return the boolean value of the restrictions
+ */
+ public Boolean getRestriction(String key) {
+ if (mUserRestrictions == null) {
+ return false;
+ }
+ Boolean restriction;
+ synchronized (mRestrictions) {
+ if (mRestrictions.containsKey(key)) {
+ return mRestrictions.get(key);
+ }
+ restriction = mUserRestrictions.getBoolean(key);
+ mRestrictions.put(key, restriction);
+ }
+ return restriction;
+ }
+
+ /**
+ * Removes all the restrictions.
+ */
+ public void clearRestrictions() {
+ synchronized (mRestrictions) {
+ mRestrictions.clear();
+ }
+ }
+
+ /**
+ * @return Whether the user is allowed to config Wi-Fi.
+ */
+ public Boolean isConfigWifiAllowed() {
+ return !getRestriction(DISALLOW_CONFIG_WIFI);
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index bf5ab1c..426ea42 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -342,7 +342,8 @@
resumeScanning();
if (!mRegistered) {
- mContext.registerReceiver(mReceiver, mFilter, null /* permission */, mWorkHandler);
+ mContext.registerReceiver(mReceiver, mFilter, null /* permission */, mWorkHandler,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
// NetworkCallback objects cannot be reused. http://b/20701525 .
mNetworkCallback = new WifiTrackerNetworkCallback();
mConnectivityManager.registerNetworkCallback(
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index d8f4d7f..55d125e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -527,7 +527,7 @@
// Set PAN profile to be disconnected and test connection state summary
updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
- assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+ assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
// Test with battery level
mBatteryLevel = 10;
@@ -537,7 +537,7 @@
// Set PAN profile to be disconnected and test connection state summary
updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
- assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+ assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
// Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
@@ -548,7 +548,7 @@
// Set PAN profile to be disconnected and test connection state summary
updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
- assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+ assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
}
@Test
@@ -579,7 +579,7 @@
// Disconnect all profiles and test connection state summary
updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
- assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+ assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
}
@Test
@@ -600,7 +600,7 @@
// Set A2DP profile to be disconnected and test connection state summary
updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
- assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+ assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
// Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
@@ -611,7 +611,7 @@
// Set A2DP profile to be disconnected and test connection state summary
updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
- assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+ assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
}
@Test
@@ -632,7 +632,7 @@
// Set HFP profile to be disconnected and test connection state summary
updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
- assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+ assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
// Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
@@ -643,7 +643,7 @@
// Set HFP profile to be disconnected and test connection state summary
updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
- assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+ assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
}
@Test
@@ -660,7 +660,7 @@
// Set Hearing Aid profile to be disconnected and test connection state summary
mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEARING_AID);
updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_DISCONNECTED);
- assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+ assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
}
@Test
@@ -707,9 +707,32 @@
// Set A2DP and HFP profiles to be disconnected and test connection state summary
updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
- assertThat(mCachedDevice.getCarConnectionSummary()).isNull();
+ assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected");
}
+ @Test
+ public void getCarConnectionSummary_shortSummary_returnShortSummary() {
+ // Test without battery level
+ // Set A2DP profile to be connected and test connection state summary
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ assertThat(mCachedDevice.getCarConnectionSummary(true /* shortSummary */))
+ .isEqualTo("Connected");
+
+ // Set device as Active for A2DP and test connection state summary
+ mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
+ assertThat(mCachedDevice.getCarConnectionSummary(true /* shortSummary */))
+ .isEqualTo("Connected");
+
+ // Test with battery level
+ mBatteryLevel = 10;
+ assertThat(mCachedDevice.getCarConnectionSummary(true /* shortSummary */))
+ .isEqualTo("Connected");
+
+ // Set A2DP profile to be disconnected and test connection state summary
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+ assertThat(mCachedDevice.getCarConnectionSummary(true /* shortSummary */))
+ .isEqualTo("Disconnected");
+ }
@Test
public void deviceName_testAliasNameAvailable() {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtilsTest.java
new file mode 100644
index 0000000..3c339de
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtilsTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settingslib.wifi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.UserManager;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+public class WifiEnterpriseRestrictionUtilsTest {
+
+ private Context mContext;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private Bundle mBundle;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+ when(mUserManager.getUserRestrictions()).thenReturn(mBundle);
+ }
+
+ @Test
+ public void isWifiTetheringAllowed_setSDKForS_shouldReturnTrue() {
+ ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.S);
+ when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_TETHERING)).thenReturn(true);
+
+ assertThat(WifiEnterpriseRestrictionUtils.isWifiTetheringAllowed(mContext)).isTrue();
+ }
+
+ @Test
+ public void isWifiTetheringAllowed_setSDKForTAndDisallowForRestriction_shouldReturnFalse() {
+ ReflectionHelpers.setStaticField(
+ Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);
+ when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_TETHERING)).thenReturn(true);
+
+ assertThat(WifiEnterpriseRestrictionUtils.isWifiTetheringAllowed(mContext)).isFalse();
+ }
+
+ @Test
+ public void isWifiTetheringAllowed_setSDKForTAndAllowForRestriction_shouldReturnTrue() {
+ ReflectionHelpers.setStaticField(
+ Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);
+ when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_TETHERING)).thenReturn(false);
+
+ assertThat(WifiEnterpriseRestrictionUtils.isWifiTetheringAllowed(mContext)).isTrue();
+ }
+
+ @Test
+ public void isWifiDirectAllowed_setSDKForS_shouldReturnTrue() {
+ ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.S);
+ when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_DIRECT)).thenReturn(true);
+
+ assertThat(WifiEnterpriseRestrictionUtils.isWifiDirectAllowed(mContext)).isTrue();
+ }
+
+ @Test
+ public void isWifiDirectAllowed_setSDKForTAndDisallowForRestriction_shouldReturnFalse() {
+ ReflectionHelpers.setStaticField(
+ Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);
+ when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_DIRECT)).thenReturn(true);
+
+ assertThat(WifiEnterpriseRestrictionUtils.isWifiDirectAllowed(mContext)).isFalse();
+ }
+
+ @Test
+ public void isWifiDirectAllowed_setSDKForTAndAllowForRestriction_shouldReturnTrue() {
+ ReflectionHelpers.setStaticField(
+ Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);
+ when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_DIRECT)).thenReturn(false);
+
+ assertThat(WifiEnterpriseRestrictionUtils.isWifiDirectAllowed(mContext)).isTrue();
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiRestrictionsCacheTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiRestrictionsCacheTest.java
new file mode 100644
index 0000000..404e0e8
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiRestrictionsCacheTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.wifi;
+
+import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.UserManager;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class WifiRestrictionsCacheTest {
+
+ private static final int USER_OWNER = 0;
+ private static final int USER_1 = 1;
+ private static final int USER_2 = 2;
+ private static final int USER_3 = 3;
+ private static final int USER_GUEST = 10;
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Mock
+ UserManager mUserManager;
+ @Mock
+ Bundle mUserRestrictionsOwner;
+ @Mock
+ Bundle mUserRestrictionsGuest;
+
+ private Context mContext;
+ private WifiRestrictionsCache mWifiRestrictionsCacheOwner;
+ private WifiRestrictionsCache mWifiRestrictionsCacheGuest;
+
+ @Before
+ public void setUp() {
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+
+ when(mContext.getUserId()).thenReturn(USER_OWNER);
+ when(mUserManager.getUserRestrictions()).thenReturn(mUserRestrictionsOwner);
+ when(mUserRestrictionsOwner.getBoolean(anyString())).thenReturn(false);
+ mWifiRestrictionsCacheOwner = WifiRestrictionsCache.getInstance(mContext);
+
+ when(mContext.getUserId()).thenReturn(USER_GUEST);
+ when(mUserManager.getUserRestrictions()).thenReturn(mUserRestrictionsGuest);
+ when(mUserRestrictionsGuest.getBoolean(anyString())).thenReturn(true);
+ mWifiRestrictionsCacheGuest = WifiRestrictionsCache.getInstance(mContext);
+ }
+
+ @After
+ public void tearDown() {
+ WifiRestrictionsCache.clearInstance();
+ }
+
+ @Test
+ public void getInstance_sameUserId_sameInstance() {
+ when(mContext.getUserId()).thenReturn(USER_OWNER);
+ WifiRestrictionsCache instance1 = WifiRestrictionsCache.getInstance(mContext);
+
+ WifiRestrictionsCache instance2 = WifiRestrictionsCache.getInstance(mContext);
+
+ assertThat(instance1).isEqualTo(instance2);
+ }
+
+ @Test
+ public void getInstance_diffUserId_diffInstance() {
+ when(mContext.getUserId()).thenReturn(USER_OWNER);
+ WifiRestrictionsCache instance1 = WifiRestrictionsCache.getInstance(mContext);
+
+ when(mContext.getUserId()).thenReturn(USER_GUEST);
+ WifiRestrictionsCache instance2 = WifiRestrictionsCache.getInstance(mContext);
+
+ assertThat(instance1).isNotEqualTo(instance2);
+ }
+
+ @Test
+ public void clearInstance_instanceShouldBeEmpty() {
+ WifiRestrictionsCache.clearInstance();
+
+ assertThat(WifiRestrictionsCache.sInstances.size()).isEqualTo(0);
+ }
+
+ @Test
+ public void getRestriction_firstTime_getFromSystem() {
+ Bundle userRestrictions = mock(Bundle.class);
+ WifiRestrictionsCache wifiRestrictionsCache = mockInstance(USER_1, userRestrictions);
+
+ wifiRestrictionsCache.getRestriction(DISALLOW_CONFIG_WIFI);
+
+ verify(userRestrictions).getBoolean(DISALLOW_CONFIG_WIFI);
+ }
+
+ @Test
+ public void getRestriction_secondTime_notGetFromSystem() {
+ Bundle userRestrictions = mock(Bundle.class);
+ WifiRestrictionsCache wifiRestrictionsCache = mockInstance(USER_2, userRestrictions);
+ // First time to get the restriction value
+ wifiRestrictionsCache.getRestriction(DISALLOW_CONFIG_WIFI);
+ reset(userRestrictions);
+
+ // Second time to get the restriction value
+ wifiRestrictionsCache.getRestriction(DISALLOW_CONFIG_WIFI);
+
+ verify(userRestrictions, never()).getBoolean(DISALLOW_CONFIG_WIFI);
+ }
+
+ @Test
+ public void clearRestrictions_shouldGetRestrictionFromSystemAgain() {
+ Bundle userRestrictions = mock(Bundle.class);
+ WifiRestrictionsCache wifiRestrictionsCache = mockInstance(USER_3, userRestrictions);
+ // First time to get the restriction value
+ wifiRestrictionsCache.getRestriction(DISALLOW_CONFIG_WIFI);
+ reset(userRestrictions);
+
+ // Clear the cache and then second time to get the restriction value
+ wifiRestrictionsCache.clearRestrictions();
+ wifiRestrictionsCache.getRestriction(DISALLOW_CONFIG_WIFI);
+
+ verify(userRestrictions).getBoolean(DISALLOW_CONFIG_WIFI);
+ }
+
+ @Test
+ public void isConfigWifiAllowed_ownerUser_returnTrue() {
+ assertThat(mWifiRestrictionsCacheOwner.isConfigWifiAllowed()).isTrue();
+ }
+
+ @Test
+ public void isConfigWifiAllowed_guestUser_returnFalse() {
+ assertThat(mWifiRestrictionsCacheGuest.isConfigWifiAllowed()).isFalse();
+ }
+
+ private WifiRestrictionsCache mockInstance(int userId, Bundle userRestrictions) {
+ when(mContext.getUserId()).thenReturn(userId);
+ when(mUserManager.getUserRestrictions()).thenReturn(userRestrictions);
+ return WifiRestrictionsCache.getInstance(mContext);
+ }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index cdf274f..dec3245 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1348,7 +1348,6 @@
Settings.Global.CONNECTIVITY_CHANGE_DELAY,
Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED,
Settings.Global.CAPTIVE_PORTAL_SERVER,
- Settings.Global.NSD_ON,
Settings.Global.SET_INSTALL_LOCATION,
Settings.Global.DEFAULT_INSTALL_LOCATION,
Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 6072f68..38a258f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1100,10 +1100,6 @@
p.end(notificationToken);
dumpSetting(s, p,
- Settings.Global.NSD_ON,
- GlobalSettingsProto.NSD_ON);
-
- dumpSetting(s, p,
Settings.Global.NR_NSA_TRACKING_SCREEN_OFF_MODE,
GlobalSettingsProto.NR_NSA_TRACKING_SCREEN_OFF_MODE);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1e2d4e9..927f11f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2117,7 +2117,7 @@
}
if ((ai.flags & ApplicationInfo.FLAG_TEST_ONLY) == 0) {
// Skip checking readable annotations for test_only apps
- checkReadableAnnotation(settingsType, settingName, ai.targetSandboxVersion);
+ checkReadableAnnotation(settingsType, settingName, ai.targetSdkVersion);
}
/**
* some settings need additional permission check, this is to have a matching security
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 2d1f0cb..368dda1 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -391,7 +391,6 @@
Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
Settings.Global.NOTIFICATION_FEEDBACK_ENABLED,
Settings.Global.NR_NSA_TRACKING_SCREEN_OFF_MODE,
- Settings.Global.NSD_ON,
Settings.Global.NTP_SERVER,
Settings.Global.NTP_TIMEOUT,
Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE,
@@ -658,6 +657,7 @@
Settings.Global.Wearable.WRIST_ORIENTATION_MODE,
Settings.Global.Wearable.CLOCKWORK_SYSUI_PACKAGE,
Settings.Global.Wearable.CLOCKWORK_SYSUI_MAIN_ACTIVITY,
+ Settings.Global.Wearable.CLOCKWORK_LONG_PRESS_TO_ASSISTANT_ENABLED,
Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_SET_BY_USER);
private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS =
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index a3f07d8..10252ee 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -610,6 +610,9 @@
<!-- Permission required for CTS test - CtsSafetyCenterTestCases -->
<uses-permission android:name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
+ <!-- Permission required for CTS test - CtsSafetyCenterTestCases -->
+ <uses-permission android:name="android.permission.READ_SAFETY_CENTER_STATUS" />
+
<!-- Permission required for CTS test - CommunalManagerTest -->
<uses-permission android:name="android.permission.WRITE_COMMUNAL_STATE" />
<uses-permission android:name="android.permission.READ_COMMUNAL_STATE" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 1e9a41e..e907efb 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -260,6 +260,8 @@
<uses-permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS" />
<!-- For handling silent audio recordings -->
<uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
+ <!-- For asking AudioManager audio information -->
+ <uses-permission android:name="android.permission.QUERY_AUDIO_STATE"/>
<!-- to read and change hvac values in a car -->
<uses-permission android:name="android.car.permission.CONTROL_CAR_CLIMATE" />
diff --git a/packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_header_bg.xml b/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_header_bg.xml
similarity index 91%
rename from packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_header_bg.xml
rename to packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_header_bg.xml
index 177f695..1119935 100644
--- a/packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_header_bg.xml
+++ b/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_header_bg.xml
@@ -17,14 +17,14 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:paddingMode="stack"
- android:paddingStart="44dp"
+ android:paddingStart="24dp"
android:paddingEnd="44dp"
android:paddingLeft="0dp"
android:paddingRight="0dp">
<item>
<shape android:shape="rectangle">
<solid android:color="?androidprv:attr/colorSurface" />
- <corners android:radius="@dimen/keyguard_user_switcher_corner" />
+ <corners android:radius="32dp" />
</shape>
</item>
<item
diff --git a/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_item_selected_bg.xml b/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_item_selected_bg.xml
new file mode 100644
index 0000000..5bb5690
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_item_selected_bg.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<shape android:shape="rectangle"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <solid android:color="?androidprv:attr/colorAccentPrimary" />
+ <corners android:radius="24dp" />
+</shape>
diff --git a/packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml b/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_popup_bg.xml
similarity index 92%
rename from packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml
rename to packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_popup_bg.xml
index 96a2d15..74ece15 100644
--- a/packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml
+++ b/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_popup_bg.xml
@@ -18,5 +18,5 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
<solid android:color="?androidprv:attr/colorSurface" />
- <corners android:radius="@dimen/keyguard_user_switcher_popup_corner" />
+ <corners android:radius="28dp" />
</shape>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
index 4f0925f..36035fc 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
@@ -30,8 +30,8 @@
<ImageView
android:id="@+id/user_icon"
- android:layout_width="@dimen/keyguard_user_switcher_icon_size"
- android:layout_height="@dimen/keyguard_user_switcher_icon_size" />
+ android:layout_width="@dimen/bouncer_user_switcher_icon_size"
+ android:layout_height="@dimen/bouncer_user_switcher_icon_size" />
<!-- need to keep this outer view in order to have a correctly sized anchor
for the dropdown menu, as well as dropdown background in the right place -->
@@ -40,13 +40,12 @@
android:orientation="horizontal"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
- android:layout_marginTop="30dp"
- android:minHeight="48dp">
+ android:layout_marginTop="30dp">
<TextView
- style="@style/Keyguard.UserSwitcher.Spinner.Header"
+ style="@style/Bouncer.UserSwitcher.Spinner.Header"
android:clickable="false"
android:id="@+id/user_switcher_header"
- android:layout_width="@dimen/keyguard_user_switcher_width"
+ android:layout_width="@dimen/bouncer_user_switcher_width"
android:layout_height="wrap_content" />
</LinearLayout>>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher_item.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher_item.xml
index b08e1ff..c388f15 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher_item.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher_item.xml
@@ -13,13 +13,14 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<TextView
+<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/Keyguard.UserSwitcher.Spinner.Item"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="start"
- android:paddingStart="@dimen/control_menu_horizontal_padding"
- android:paddingEnd="@dimen/control_menu_horizontal_padding"
- android:textDirection="locale"/>
-
+ android:layout_height="wrap_content">
+ <TextView
+ style="@style/Bouncer.UserSwitcher.Spinner.Item"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp" />
+</FrameLayout>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 2819dc9..c8bb8e9 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -108,11 +108,15 @@
<dimen name="one_handed_bouncer_move_animation_translation">120dp</dimen>
- <dimen name="keyguard_user_switcher_header_text_size">32sp</dimen>
- <dimen name="keyguard_user_switcher_item_text_size">32sp</dimen>
- <dimen name="keyguard_user_switcher_width">320dp</dimen>
- <dimen name="keyguard_user_switcher_icon_size">310dp</dimen>
- <dimen name="keyguard_user_switcher_corner">32dp</dimen>
- <dimen name="keyguard_user_switcher_popup_corner">24dp</dimen>
- <dimen name="keyguard_user_switcher_item_padding_vertical">15dp</dimen>
+ <dimen name="bouncer_user_switcher_header_text_size">20sp</dimen>
+ <dimen name="bouncer_user_switcher_item_text_size">20sp</dimen>
+ <dimen name="bouncer_user_switcher_item_line_height">24sp</dimen>
+ <dimen name="bouncer_user_switcher_item_icon_size">28dp</dimen>
+ <dimen name="bouncer_user_switcher_item_icon_padding">12dp</dimen>
+ <dimen name="bouncer_user_switcher_width">248dp</dimen>
+ <dimen name="bouncer_user_switcher_icon_size">190dp</dimen>
+ <dimen name="bouncer_user_switcher_popup_header_height">12dp</dimen>
+ <dimen name="bouncer_user_switcher_popup_divider_height">4dp</dimen>
+ <dimen name="bouncer_user_switcher_item_padding_vertical">10dp</dimen>
+ <dimen name="bouncer_user_switcher_item_padding_horizontal">12dp</dimen>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 60f034a..5048f85 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -141,22 +141,23 @@
<item name="android:shadowRadius">0</item>
</style>
- <style name="Keyguard.UserSwitcher.Spinner" parent="@android:style/Widget.DeviceDefault.TextView">
+ <style name="Bouncer.UserSwitcher.Spinner" parent="@android:style/Widget.DeviceDefault.TextView">
<item name="android:textColor">?android:attr/textColorPrimary</item>
- <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
<item name="android:singleLine">true</item>
<item name="android:ellipsize">end</item>
- <item name="android:paddingTop">@dimen/keyguard_user_switcher_item_padding_vertical</item>
- <item name="android:paddingBottom">@dimen/keyguard_user_switcher_item_padding_vertical</item>
+ <item name="android:minHeight">48dp</item>
+ <item name="android:paddingVertical">@dimen/bouncer_user_switcher_item_padding_vertical</item>
+ <item name="android:paddingHorizontal">@dimen/bouncer_user_switcher_item_padding_horizontal</item>
+ <item name="android:lineHeight">@dimen/bouncer_user_switcher_item_line_height</item>
+ <item name="android:gravity">start|center_vertical</item>
</style>
- <style name="Keyguard.UserSwitcher.Spinner.Header">
- <item name="android:background">@drawable/keyguard_user_switcher_header_bg</item>
- <item name="android:textSize">@dimen/keyguard_user_switcher_header_text_size</item>
+ <style name="Bouncer.UserSwitcher.Spinner.Header">
+ <item name="android:background">@drawable/bouncer_user_switcher_header_bg</item>
+ <item name="android:textSize">@dimen/bouncer_user_switcher_header_text_size</item>
</style>
- <style name="Keyguard.UserSwitcher.Spinner.Item">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textSize">@dimen/keyguard_user_switcher_item_text_size</item>
+ <style name="Bouncer.UserSwitcher.Spinner.Item">
+ <item name="android:textSize">@dimen/bouncer_user_switcher_item_text_size</item>
</style>
</resources>
diff --git a/packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml b/packages/SystemUI/res/drawable/media_ttt_chip_background_receiver.xml
similarity index 65%
copy from packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml
copy to packages/SystemUI/res/drawable/media_ttt_chip_background_receiver.xml
index 96a2d15..708bc1a 100644
--- a/packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml
+++ b/packages/SystemUI/res/drawable/media_ttt_chip_background_receiver.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 The Android Open Source Project
~
@@ -12,11 +11,16 @@
~ 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.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:shape="rectangle">
+
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="oval">
+ <size
+ android:height="@dimen/media_ttt_chip_size_receiver"
+ android:width="@dimen/media_ttt_chip_size_receiver"
+ />
<solid android:color="?androidprv:attr/colorSurface" />
- <corners android:radius="@dimen/keyguard_user_switcher_popup_corner" />
</shape>
diff --git a/packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml b/packages/SystemUI/res/drawable/qs_media_round_button_background.xml
similarity index 60%
copy from packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml
copy to packages/SystemUI/res/drawable/qs_media_round_button_background.xml
index 96a2d15..33ad2d6 100644
--- a/packages/SystemUI/res-keyguard/drawable/keyguard_user_switcher_popup_bg.xml
+++ b/packages/SystemUI/res/drawable/qs_media_round_button_background.xml
@@ -12,11 +12,14 @@
~ 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.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface" />
- <corners android:radius="@dimen/keyguard_user_switcher_popup_corner" />
-</shape>
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/media_seamless_border">
+ <item android:id="@android:id/background">
+ <shape android:shape="oval">
+ <solid android:color="@color/media_seamless_border" />
+ <size android:width="48dp" android:height="48dp" />
+ </shape>
+ </item>
+</ripple>
diff --git a/packages/SystemUI/res/layout/dream_overlay_container.xml b/packages/SystemUI/res/layout/dream_overlay_container.xml
index b611ffa..4929f50 100644
--- a/packages/SystemUI/res/layout/dream_overlay_container.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_container.xml
@@ -32,8 +32,8 @@
android:id="@+id/dream_overlay_status_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/dream_overlay_status_bar_height"
- android:layout_marginEnd="@dimen/dream_overlay_status_bar_margin"
- android:layout_marginStart="@dimen/dream_overlay_status_bar_margin"
+ android:paddingEnd="@dimen/dream_overlay_status_bar_margin"
+ android:paddingStart="@dimen/dream_overlay_status_bar_margin"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index baf5336..e69582f 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -53,21 +53,22 @@
</LinearLayout>
<LinearLayout
- android:layout_width="match_parent"
+ android:layout_width="@dimen/internet_dialog_progress_bar_width"
android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
android:layout_marginBottom="@dimen/internet_dialog_network_layout_margin"
android:orientation="vertical">
<View
android:id="@+id/divider"
- android:layout_gravity="center_vertical|center_horizontal"
- android:layout_width="340dp"
+ android:layout_width="match_parent"
android:layout_height="4dp"
+ android:layout_gravity="center_vertical|center_horizontal"
android:background="?androidprv:attr/colorSurfaceVariant"/>
<ProgressBar
android:id="@+id/wifi_searching_progress"
- android:layout_width="340dp"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:visibility="gone"
diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml
new file mode 100644
index 0000000..cc02fea
--- /dev/null
+++ b/packages/SystemUI/res/layout/media_session_view.xml
@@ -0,0 +1,313 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Layout for media session-based controls -->
+<com.android.systemui.util.animation.TransitionLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/qs_media_controls"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:gravity="center_horizontal|fill_vertical"
+ android:forceHasOverlappingRendering="false"
+ android:background="@drawable/qs_media_background"
+ android:theme="@style/MediaPlayer">
+
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/center_vertical_guideline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ app:layout_constraintGuide_percent="0.6" />
+
+ <!-- App icon -->
+ <com.android.internal.widget.CachingIconView
+ android:id="@+id/icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginStart="@dimen/qs_media_padding"
+ android:layout_marginTop="@dimen/qs_media_padding"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <!-- Seamless Output Switcher -->
+ <LinearLayout
+ android:id="@+id/media_seamless"
+ android:orientation="horizontal"
+ android:gravity="top|end"
+ android:paddingTop="@dimen/qs_media_padding"
+ android:paddingEnd="@dimen/qs_media_padding"
+ android:background="@drawable/qs_media_light_source"
+ android:forceHasOverlappingRendering="false"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_marginStart="@dimen/qs_center_guideline_padding"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toEndOf="@id/center_vertical_guideline"
+ app:layout_constraintHorizontal_bias="1"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
+ app:layout_constraintHeight_min="@dimen/min_clickable_item_size">
+ <LinearLayout
+ android:id="@+id/media_seamless_button"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/qs_seamless_height"
+ android:minHeight="@dimen/qs_seamless_height"
+ android:theme="@style/MediaPlayer.SolidButton"
+ android:background="@drawable/qs_media_seamless_background"
+ android:orientation="horizontal"
+ android:contentDescription="@string/quick_settings_media_device_label">
+ <ImageView
+ android:id="@+id/media_seamless_image"
+ android:layout_width="@dimen/qs_seamless_icon_size"
+ android:layout_height="@dimen/qs_seamless_icon_size"
+ android:layout_gravity="center"
+ android:tint="?android:attr/textColorPrimary"
+ android:src="@*android:drawable/ic_media_seamless" />
+ <TextView
+ android:id="@+id/media_seamless_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="4dp"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:singleLine="true"
+ android:text="@*android:string/ext_media_seamless_action"
+ android:textDirection="locale"
+ android:textSize="12sp"
+ android:lineHeight="16sp" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <!-- Song name -->
+ <TextView
+ android:id="@+id/header_title"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:singleLine="true"
+ android:textSize="16sp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:layout_marginStart="@dimen/qs_media_padding"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintTop_toBottomOf="@id/icon"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+ app:layout_constraintHorizontal_bias="0" />
+
+ <!-- Artist name -->
+ <TextView
+ android:id="@+id/header_artist"
+ android:fontFamily="@*android:string/config_headlineFontFamily"
+ android:singleLine="true"
+ style="@style/MediaPlayer.Subtitle"
+ android:textSize="14sp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ app:layout_constrainedWidth="true"
+ android:layout_marginTop="1dp"
+ app:layout_constraintTop_toBottomOf="@id/header_title"
+ app:layout_constraintStart_toStartOf="@id/header_title"
+ app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+ app:layout_constraintBottom_toBottomOf="@id/actionPlayPause"
+ app:layout_constraintHorizontal_bias="0" />
+
+ <ImageButton
+ android:id="@+id/actionPlayPause"
+ style="@style/MediaPlayer.SessionAction.Primary"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="@dimen/qs_media_padding"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp"
+ android:layout_marginBottom="0dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless"
+ app:layout_constraintBottom_toTopOf="@id/actionEnd" />
+
+ <ImageButton
+ android:id="@+id/actionPrev"
+ style="@style/MediaPlayer.SessionAction"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="0dp"
+ android:layout_marginBottom="0dp"
+ android:layout_marginTop="0dp"
+ app:layout_constraintHorizontal_chainStyle="packed"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/media_progress_bar"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+
+ <!-- Seek Bar -->
+ <!-- As per Material Design on Bidirectionality, this is forced to LTR in code -->
+ <SeekBar
+ android:id="@+id/media_progress_bar"
+ style="@style/MediaPlayer.ProgressBar"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/qs_media_session_enabled_seekbar_vertical_padding"
+ android:paddingBottom="12dp"
+ android:maxHeight="@dimen/qs_media_enabled_seekbar_height"
+ android:splitTrack="false"
+ android:layout_marginBottom="0dp"
+ android:layout_marginTop="0dp"
+ android:layout_marginStart="0dp"
+ android:layout_marginEnd="0dp"
+ app:layout_constraintStart_toEndOf="@id/actionPrev"
+ app:layout_constraintEnd_toStartOf="@id/actionNext"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+
+ <ImageButton
+ android:id="@+id/actionNext"
+ style="@style/MediaPlayer.SessionAction"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="0dp"
+ android:layout_marginEnd="@dimen/qs_media_action_spacing"
+ android:layout_marginBottom="0dp"
+ android:layout_marginTop="0dp"
+ app:layout_constraintStart_toEndOf="@id/media_progress_bar"
+ app:layout_constraintEnd_toStartOf="@id/actionStart"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+
+ <ImageButton
+ android:id="@+id/actionStart"
+ style="@style/MediaPlayer.SessionAction"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="@dimen/qs_media_action_spacing"
+ android:layout_marginEnd="@dimen/qs_media_action_spacing"
+ android:layout_marginBottom="0dp"
+ android:layout_marginTop="0dp"
+ app:layout_constraintStart_toEndOf="@id/actionNext"
+ app:layout_constraintEnd_toStartOf="@id/actionEnd"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+
+ <ImageButton
+ android:id="@+id/actionEnd"
+ style="@style/MediaPlayer.SessionAction"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="@dimen/qs_media_action_spacing"
+ android:layout_marginEnd="4dp"
+ android:layout_marginBottom="0dp"
+ android:layout_marginTop="0dp"
+ app:layout_constraintHorizontal_chainStyle="packed"
+ app:layout_constraintStart_toEndOf="@id/actionStart"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+
+ <!-- Long press menu -->
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/qs_media_padding"
+ android:layout_marginStart="@dimen/qs_media_padding"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ android:id="@+id/remove_text"
+ android:fontFamily="@*android:string/config_headlineFontFamily"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:marqueeRepeatLimit="marquee_forever"
+ android:text="@string/controls_media_close_session"
+ android:gravity="center_horizontal|top"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/cancel" />
+
+ <FrameLayout
+ android:id="@+id/settings"
+ android:background="@drawable/qs_media_light_source"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/qs_media_padding"
+ android:layout_marginEnd="@dimen/qs_media_action_spacing"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
+ app:layout_constraintHeight_min="@dimen/min_clickable_item_size"
+ app:layout_constraintHorizontal_chainStyle="spread_inside"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/cancel"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/remove_text">
+ <TextView
+ android:id="@+id/settings_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center|bottom"
+ style="@style/MediaPlayer.OutlineButton"
+ android:text="@string/controls_media_settings_button" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/cancel"
+ android:background="@drawable/qs_media_light_source"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/qs_media_action_spacing"
+ android:layout_marginEnd="@dimen/qs_media_action_spacing"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
+ app:layout_constraintHeight_min="@dimen/min_clickable_item_size"
+ app:layout_constraintStart_toEndOf="@id/settings"
+ app:layout_constraintEnd_toStartOf="@id/dismiss"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/remove_text">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center|bottom"
+ style="@style/MediaPlayer.OutlineButton"
+ android:text="@string/cancel" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/dismiss"
+ android:background="@drawable/qs_media_light_source"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/qs_media_action_spacing"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
+ app:layout_constraintHeight_min="@dimen/min_clickable_item_size"
+ app:layout_constraintStart_toEndOf="@id/cancel"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/remove_text">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center|bottom"
+ style="@style/MediaPlayer.OutlineButton"
+ android:text="@string/controls_media_dismiss_button" />
+ </FrameLayout>
+</com.android.systemui.util.animation.TransitionLayout>
diff --git a/packages/SystemUI/res/layout/media_ttt_chip.xml b/packages/SystemUI/res/layout/media_ttt_chip.xml
index 6fbc41c..2d082dc 100644
--- a/packages/SystemUI/res/layout/media_ttt_chip.xml
+++ b/packages/SystemUI/res/layout/media_ttt_chip.xml
@@ -26,6 +26,13 @@
android:gravity="center_vertical"
>
+ <com.android.internal.widget.CachingIconView
+ android:id="@+id/app_icon"
+ android:layout_width="@dimen/media_ttt_icon_size"
+ android:layout_height="@dimen/media_ttt_icon_size"
+ android:layout_marginEnd="12dp"
+ />
+
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
@@ -37,8 +44,8 @@
<ProgressBar
android:id="@+id/loading"
android:indeterminate="true"
- android:layout_width="@dimen/media_ttt_icon_size"
- android:layout_height="@dimen/media_ttt_icon_size"
+ android:layout_width="@dimen/media_ttt_loading_size"
+ android:layout_height="@dimen/media_ttt_loading_size"
android:layout_marginStart="12dp"
android:indeterminateTint="?androidprv:attr/colorAccentPrimaryVariant"
style="?android:attr/progressBarStyleSmall"
diff --git a/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml b/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
new file mode 100644
index 0000000..88feacd
--- /dev/null
+++ b/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<!-- TODO(b/203800646): layout_marginTop doesn't seem to work on some large screens. -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/media_ttt_chip_background_receiver"
+ >
+
+ <com.android.internal.widget.CachingIconView
+ android:id="@+id/app_icon"
+ android:layout_width="@dimen/media_ttt_icon_size_receiver"
+ android:layout_height="@dimen/media_ttt_icon_size_receiver"
+ android:layout_gravity="center"
+ />
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index f2754aa..f083b85 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Geen toestelle beskikbaar nie"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi is nie gekoppel nie"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Helderheid"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Keer kleure om"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Kleuromkering"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Meer instellings"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Gebruikerinstellings"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Klaar"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Vergroot die hele skerm"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Vergroot \'n deel van die skerm"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Wissel"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Toeganklikheidknoppie het die toeganklikheidgebaar vervang\n\n"<annotation id="link">"Bekyk instellings"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tik om toeganklikheidkenmerke oop te maak Pasmaak of vervang knoppie in Instellings.\n\n"<annotation id="link">"Bekyk instellings"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Skuif knoppie na kant om dit tydelik te versteek"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Beweeg na links bo"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Beweeg na regs bo"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Instellings"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> deur <xliff:g id="ARTIST_NAME">%2$s</xliff:g> speel tans vanaf <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> van <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Speel"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Onderbreek"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Vorige snit"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Volgende snit"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Speel"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Maak <xliff:g id="APP_LABEL">%1$s</xliff:g> oop"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Speel <xliff:g id="SONG_NAME">%1$s</xliff:g> deur <xliff:g id="ARTIST_NAME">%2$s</xliff:g> vanaf <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Speel <xliff:g id="SONG_NAME">%1$s</xliff:g> vanaf <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Ontdoen"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Beweeg nader om op <xliff:g id="DEVICENAME">%1$s</xliff:g> te speel"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Speel tans op <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Onaktief, gaan program na"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nie gekry nie"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrole is nie beskikbaar nie"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 toestel gekies"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> toestelle gekies"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ontkoppel)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Kon nie koppel nie. Probeer weer."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Kan nie wissel nie. Tik om weer te probeer."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bind nuwe toestel saam"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Bounommer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Bounommer is na knipbord gekopieer."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Sien alles"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ontkoppel Ethernet om netwerke te wissel"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Om toestelervaring te verbeter, kan programme en dienste steeds enige tyd na wi‑fi-netwerke soek, selfs wanneer wi‑fi af is. Jy kan dit in Wi-fi-opsporing-instellings verander. "<annotation id="link">"Verander"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Skakel vliegtuigmodus af"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wil die volgende teël by Kitsinstellings voeg"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Voeg teël by"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Moenie teël byvoeg nie"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Kies gebruiker"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Programme wat op die agtergrond werk"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
</resources>
diff --git a/packages/SystemUI/res/values-af/tiles_states_strings.xml b/packages/SystemUI/res/values-af/tiles_states_strings.xml
index a9e1a23..2059490 100644
--- a/packages/SystemUI/res/values-af/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-af/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Af"</item>
<item msgid="460891964396502657">"Aan"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Onbeskikbaar"</item>
+ <item msgid="5581384648880018330">"Af"</item>
+ <item msgid="8000850843692192257">"Aan"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index e463894..839b8d2 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ምንም መሣሪያዎች አይገኙም"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi አልተገናኘም"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ብሩህነት"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ቀለማትን ግልብጥ"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ተቃራኒ ቀለም"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"ተጨማሪ ቅንብሮች"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"የተጠቃሚ ቅንብሮች"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"ተከናውኗል"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ሙሉ ገጽ እይታን ያጉሉ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"የማያ ገጹን ክፍል አጉላ"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ማብሪያ/ማጥፊያ"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"የተደራሽነት አዝራር የተደራሽነት ምልክትን ተክቷል\n\n"<annotation id="link">" ቅንብሮችን አሳይ"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"የተደራሽነት ባህሪያትን ለመክፈት መታ ያድርጉ። ይህንን አዝራር በቅንብሮች ውስጥ ያብጁ ወይም ይተኩ።\n\n"<annotation id="link">"ቅንብሮችን አሳይ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ለጊዜው ለመደበቅ አዝራሩን ወደ ጠርዝ ያንቀሳቅሱ"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ወደ ላይኛው ግራ አንቀሳቅስ"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ወደ ላይኛው ቀኝ አንቀሳቅስ"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"ቅንብሮች"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> በ<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ከ<xliff:g id="APP_LABEL">%3$s</xliff:g> እየተጫወተ ነው"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> ከ<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"አጫውት"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"ላፍታ አቁም"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"ቀዳሚ ትራክ"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"ቀጣይ ትራክ"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"አጫውት"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ክፈት"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> በ<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ከ<xliff:g id="APP_LABEL">%3$s</xliff:g> ያጫውቱ"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ከ<xliff:g id="APP_LABEL">%2$s</xliff:g> ያጫውቱ"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"ቀልብስ"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"በ<xliff:g id="DEVICENAME">%1$s</xliff:g> ላይ ለማጫወት ጠጋ ያድርጉ"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"በ<xliff:g id="DEVICENAME">%1$s</xliff:g> ላይ በማጫወት ላይ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ንቁ ያልኾነ፣ መተግበሪያን ይፈትሹ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"አልተገኘም"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"መቆጣጠሪያ አይገኝም"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 መሣሪያ ተመርጧል"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> መሣሪያዎች ተመርጠዋል"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ተቋርጧል)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ማገናኘት አልተቻለም። እንደገና ይሞክሩ።"</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"መቀየር አይቻልም። እንደገና ለመሞከር መታ ያድርጉ።"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"አዲስ መሣሪያ ያጣምሩ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"የግንብ ቁጥር"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"የገንባ ቁጥር ወደ ቅንጥብ ሰሌዳ ተቀድቷል።"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"ሁሉንም ይመልከቱ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"አውታረ መረቦችን ለመቀየር፣ የኢተርኔት ግንኙነት ያቋርጡ"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"የመሣሪያ ተሞክሮን ለማሻሻል፣ መተግበሪያዎች እና አገልግሎቶች አሁንም በማንኛውም ጊዜ የWi-Fi አውታረ መረቦችን መቃኘት ይችላሉ፣ Wi-Fi ጠፍቶ ቢሆንም እንኳ። ይህንን በ Wi‑Fi ቅኝት ቅንብሮች ውስጥ መቀየር ይችላሉ። "<annotation id="link">"ቀይር"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"የአውሮፕላን ሁነታን ያጥፉ"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> የሚከተለውን ሰቅ ወደ ፈጣን ቅንብሮች ማከል ይፈልጋል"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ሰቅ አክል"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ሰቅ አታክል"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ተጠቃሚን ይምረጡ"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ከበስተጀርባ የሚሠሩ መተግበሪያዎች"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"መቆሚያ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/tiles_states_strings.xml b/packages/SystemUI/res/values-am/tiles_states_strings.xml
index 2b0062a..7fdfd11 100644
--- a/packages/SystemUI/res/values-am/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-am/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"አጥፋ"</item>
<item msgid="460891964396502657">"አብራ"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"አይገኝም"</item>
+ <item msgid="5581384648880018330">"አጥፋ"</item>
+ <item msgid="8000850843692192257">"አብራ"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 6f73bed..6110793 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -222,7 +222,7 @@
<string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"تم قفل الشاشة في الاتجاه الأفقي."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"تم قفل الشاشة في الاتجاه العمودي."</string>
<string name="dessert_case" msgid="9104973640704357717">"حالة الحلويات"</string>
- <string name="start_dreams" msgid="9131802557946276718">"شاشة التوقف"</string>
+ <string name="start_dreams" msgid="9131802557946276718">"شاشة الاستراحة"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"عدم الإزعاج"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"بلوتوث"</string>
@@ -254,7 +254,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"لا يتوفر أي جهاز"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"لم يتم الاتصال بشبكة Wi-Fi."</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"السطوع"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"قلب الألوان"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"قلب الألوان"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"المزيد من الإعدادات"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"إعدادات المستخدم"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"تم"</string>
@@ -767,7 +767,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"تكبير الشاشة كلها"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"تكبير جزء من الشاشة"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"تبديل"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"تم استبدال \"زر أدوات تسهيل الاستخدام\" بإيماءة تسهيل الاستخدام.\n\n"<annotation id="link">"الاطّلاع على الإعدادات"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"انقر لفتح ميزات تسهيل الاستخدام. يمكنك تخصيص هذا الزر أو استبداله من الإعدادات.\n\n"<annotation id="link">"عرض الإعدادات"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"يمكنك نقل الزر إلى الحافة لإخفائه مؤقتًا."</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"نقل إلى أعلى يمين الشاشة"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"نقل إلى أعلى يسار الشاشة"</string>
@@ -822,10 +822,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"الإعدادات"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"يتم تشغيل <xliff:g id="SONG_NAME">%1$s</xliff:g> للفنان <xliff:g id="ARTIST_NAME">%2$s</xliff:g> من تطبيق <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> من إجمالي <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"تشغيل"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"إيقاف مؤقت"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"المقطع الصوتي السابق"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"المقطع الصوتي التالي"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"تشغيل"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"فتح <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"تشغيل <xliff:g id="SONG_NAME">%1$s</xliff:g> للفنان <xliff:g id="ARTIST_NAME">%2$s</xliff:g> من تطبيق <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"تشغيل <xliff:g id="SONG_NAME">%1$s</xliff:g> من تطبيق <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"تراجع"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"عليك الاقتراب لتشغيل الموسيقى على <xliff:g id="DEVICENAME">%1$s</xliff:g>."</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"جارٍ تشغيل الموسيقى على <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"غير نشط، تحقّق من التطبيق."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"لم يتم العثور عليه."</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"عنصر التحكّم غير متوفّر"</string>
@@ -840,7 +847,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"تم اختيار جهاز واحد."</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"تم اختيار <xliff:g id="COUNT">%1$d</xliff:g> جهاز."</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(غير متّصل)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"تعذّر الاتصال. يُرجى إعادة المحاولة."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"لا يمكن التبديل. انقر لإعادة المحاولة."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"إقران جهاز جديد"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"رقم الإصدار"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"تم نسخ رقم الإصدار إلى الحافظة."</string>
@@ -905,8 +912,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"عرض الكل"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"للتبديل بين الشبكات، يجب فصل إيثرنت."</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"لتحسين تجربتك على الجهاز، يظل بإمكان التطبيقات والخدمات البحث عن شبكات Wi‑Fi في أي وقت، حتى عند إيقاف شبكة Wi‑Fi. وبإمكانك تغيير هذا الخيار في إعدادات البحث عن شبكات Wi-Fi. "<annotation id="link">"تغيير"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"إيقاف وضع الطيران"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"يريد تطبيق <xliff:g id="APPNAME">%1$s</xliff:g> إضافة المربّع التالي إلى \"الإعدادات السريعة\""</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"إضافة مربّع"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"عدم إضافة مربّع"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"اختيار المستخدم"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"التطبيقات التي يتم تشغيلها في الخلفية"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"إيقاف"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/tiles_states_strings.xml b/packages/SystemUI/res/values-ar/tiles_states_strings.xml
index 4facf293d..d7026c7 100644
--- a/packages/SystemUI/res/values-ar/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ar/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"غير مفعّل"</item>
<item msgid="460891964396502657">"مفعّل"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"غير متوفّر"</item>
+ <item msgid="5581384648880018330">"غير مفعّل"</item>
+ <item msgid="8000850843692192257">"مفعّل"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 679231f..3fe47cb 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"কোনো ডিভাইচ নাই"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ৱাই-ফাইৰ সৈতে সংযোগ হৈ থকা নাই"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"উজ্জ্বলতা"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ৰং ওলোটা কৰক"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ৰং বিপৰীতকৰণ"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"অধিক ছেটিং"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ব্যৱহাৰকাৰীৰ ছেটিং"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"সম্পন্ন কৰা হ’ল"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"পূৰ্ণ স্ক্ৰীন বিবৰ্ধন কৰক"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"স্ক্ৰীনৰ কিছু অংশ বিবৰ্ধন কৰক"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ছুইচ"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"সাধ্য সুবিধাৰ বুটামটোৱে সাধ্য সুবিধাৰ নিৰ্দেশ সলনি কৰিছে\n\n"<annotation id="link">"ছেটিং চাওক"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"সাধ্য সুবিধাসমূহ খুলিবলৈ টিপক। ছেটিঙত এই বুটামটো কাষ্টমাইজ অথবা সলনি কৰক।\n\n"<annotation id="link">"ছেটিং চাওক"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"বুটামটোক সাময়িকভাৱে লুকুৱাবলৈ ইয়াক একেবাৰে কাষলৈ লৈ যাওক"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"শীৰ্ষৰ বাওঁফালে নিয়ক"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"শীৰ্ষৰ সোঁফালে নিয়ক"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"ছেটিং"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ত <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ৰ <xliff:g id="SONG_NAME">%1$s</xliff:g> গীতটো প্লে’ হৈ আছে"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>ৰ <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"প্লে’ কৰক"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"পজ কৰক"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"পূৰ্বৱৰ্তী ট্ৰেক"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"পৰৱৰ্তী ট্ৰেক"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"প্লে’ কৰক"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> খোলক"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ত <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ৰ <xliff:g id="SONG_NAME">%1$s</xliff:g> গীতটো প্লে’ কৰক"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g>ত <xliff:g id="SONG_NAME">%1$s</xliff:g> গীতটো প্লে’ কৰক"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"আনডু কৰক"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ত প্লে\' কৰিবলৈ ওপৰলৈ যাওক"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ত প্লে\' কৰি থকা হৈছে"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"সক্ৰিয় নহয়, এপ্টো পৰীক্ষা কৰক"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"বিচাৰি পোৱা নগ’ল"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"নিয়ন্ত্ৰণটো উপলব্ধ নহয়"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"১ টা ডিভাইচ বাছনি কৰা হৈছে"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> টা ডিভাইচ বাছনি কৰা হৈছে"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(সংযোগ বিচ্ছিন্ন কৰা হৈছে)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"সংযোগ কৰিব পৰা নগ’ল। পুনৰ চেষ্টা কৰক।"</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"সলনি কৰিব নোৱাৰি। আকৌ চেষ্টা কৰিবলৈ টিপক।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইচ পেয়াৰ কৰক"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ডৰ নম্বৰ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ক্লিপব’ৰ্ডলৈ বিল্ডৰ নম্বৰ প্ৰতিলিপি কৰা হ’ল।"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"আটাইবোৰ চাওক"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"নেটৱৰ্ক সলনি কৰিবলৈ ইথাৰনেটৰ পৰা সংযোগ বিচ্ছিন্ন কৰক"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"ডিভাইচ ব্যৱহাৰৰ অভিজ্ঞতা উন্নত কৰিবলৈ ৱাই-ফাই অফ থকা অৱস্থাতো এপ্ আৰু সেৱাসমূহে ৱাই-ফাই নেটৱৰ্কবোৰ স্কেন কৰিব পাৰে। আপুনি ৱাই-ফাই স্কেনিঙৰ ছেটিঙত এইটো সলনি কৰিব পাৰে। "<annotation id="link">"সলনি কৰক"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"এয়াৰপ্লে’ন ম’ডটো অফ কৰক"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g>এ ক্ষিপ্ৰ ছেটিঙত এই টাইলটো যোগ দিব বিচাৰিছে"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"টাইল যোগ দিয়ক"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"টাইল যোগ নিদিব"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ব্যৱহাৰকাৰী বাছনি কৰক"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"নেপথ্যত চলি থকা এপ্"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"বন্ধ কৰক"</string>
</resources>
diff --git a/packages/SystemUI/res/values-as/tiles_states_strings.xml b/packages/SystemUI/res/values-as/tiles_states_strings.xml
index 69a2efc..efb2351 100644
--- a/packages/SystemUI/res/values-as/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-as/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"অফ"</item>
<item msgid="460891964396502657">"অন"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"উপলব্ধ নহয়"</item>
+ <item msgid="5581384648880018330">"অফ আছে"</item>
+ <item msgid="8000850843692192257">"অন আছে"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index a7fe41d..255ce58 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Heç bir cihaz əlçatan deyil"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi qoşulu deyil"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Parlaqlıq"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Rəng inversiyası"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Rəng inversiyası"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Digər ayarlar"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"İstifadəçi ayarları"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Hazır"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Tam ekranı böyüdün"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekran hissəsinin böyüdülməsi"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Dəyişdirici"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Jest xüsusi imkanlar düyməsinə dəyişdirildi\n\n"<annotation id="link">"Ayarlara baxın"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Əlçatımlılıq funksiyalarını açmaq üçün toxunun. Ayarlarda bu düyməni fərdiləşdirin və ya dəyişdirin.\n\n"<annotation id="link">"Ayarlara baxın"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Düyməni müvəqqəti gizlətmək üçün kənara çəkin"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Yuxarıya sola köçürün"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Yuxarıya sağa köçürün"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Ayarlar"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> tərəfindən <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%3$s</xliff:g> tətbiqindən oxudulur"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Oxudun"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Durdurun"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Əvvəlki trek"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Növbəti trek"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Oxudun"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> tətbiqini açın"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> tərəfindən <xliff:g id="SONG_NAME">%1$s</xliff:g> mahnısını <xliff:g id="APP_LABEL">%3$s</xliff:g> tətbiqindən oxudun"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> mahnısını <xliff:g id="APP_LABEL">%2$s</xliff:g> tətbiqindən oxudun"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Geri qaytarın"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oxutmaq üçün yaxınlaşın"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oxudulur"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Aktiv deyil, tətbiqi yoxlayın"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Tapılmadı"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Nəzarət əlçatan deyil"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 cihaz seçilib"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> cihaz seçilib"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(bağlantı kəsildi)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Qoşulmaq alınmadı. Yenə cəhd edin."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Dəyişmək olmur. Yenidən cəhd etmək üçün toxunun."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Cihaz əlavə edin"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Montaj nömrəsi"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versiya nömrəsi mübadilə buferinə kopyalandı."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Hamısına baxın"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Şəbəkəni dəyişmək üçün etherneti ayırın"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Cihaz təcrübəsini yaxşılaşdırmaq üçün Wi-Fi deaktiv olduqda belə, tətbiqlər və xidmətlər Wi-Fi şəbəkəsini axtara biləcək. Bunu Wi-Fi axtarışı ayarlarında dəyişə bilərsiniz. "<annotation id="link">"Dəyişin"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Təyyarə rejimini deaktiv edin"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> aşağıdakı mozaiki Sürətli Ayarlara əlavə etmək istəyir"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Mozaik əlavə edin"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Mozaik əlavə etməyin"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"İstifadəçi seçin"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Arxa fonda işləyən tətbiqlər"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Dayandırın"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/tiles_states_strings.xml b/packages/SystemUI/res/values-az/tiles_states_strings.xml
index d46175bd..7c47203 100644
--- a/packages/SystemUI/res/values-az/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-az/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Deaktiv"</item>
<item msgid="460891964396502657">"Aktiv"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Əlçatmazdır"</item>
+ <item msgid="5581384648880018330">"Deaktiv"</item>
+ <item msgid="8000850843692192257">"Aktiv"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index bebec60..f29d9de 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -251,7 +251,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nije dostupan nijedan uređaj"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"WiFi nije povezan"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Osvetljenost"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Obrni boje"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija boja"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Još podešavanja"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Korisnička podešavanja"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Gotovo"</string>
@@ -752,7 +752,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Uvećajte ceo ekran"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Uvećajte deo ekrana"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Pređi"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Dugme Pristupačnost je zamenilo pokret za pristupačnost\n\n"<annotation id="link">"Prikaži podešavanja"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dodirnite za funkcije pristupačnosti. Prilagodite ili zamenite ovo dugme u Podešavanjima.\n\n"<annotation id="link">"Podešavanja"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Pomerite dugme do ivice da biste ga privremeno sakrili"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Premesti gore levo"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Premesti gore desno"</string>
@@ -804,10 +804,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Podešavanja"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se pušta iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> od <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Pusti"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pauziraj"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Prethodna pesma"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Sledeća pesma"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Pusti"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otvorite <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Pustite <xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Pustite <xliff:g id="SONG_NAME">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Opozovi"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Približite da biste puštali muziku na: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Pušta se na: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno. Vidite aplikaciju"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
@@ -822,7 +829,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Izabran je 1 uređaj"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Izabranih uređaja: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(veza je prekinuta)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Povezivanje nije uspelo. Probajte ponovo."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Prebacivanje nije uspelo. Probajte ponovo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Upari novi uređaj"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u privremenu memoriju."</string>
@@ -887,8 +894,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Pogledajte sve"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da biste promenili mrežu, prekinite eternet vezu"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Radi boljeg doživljaja uređaja, aplikacije i usluge i dalje mogu da traže WiFi mreže u bilo kom trenutku, čak i kada je WiFi isključen. To možete da promenite u podešavanjima WiFi skeniranja. "<annotation id="link">"Promenite"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Isključite režim rada u avionu"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> želi da doda sledeću pločicu u Brza podešavanja"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj pločicu"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne dodaj pločicu"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Izaberite korisnika"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikacije pokrenute u pozadini"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zaustavi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml b/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
index 5d9edf5..88caf97 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Isključeno"</item>
<item msgid="460891964396502657">"Uključeno"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Nedostupno"</item>
+ <item msgid="5581384648880018330">"Isključeno"</item>
+ <item msgid="8000850843692192257">"Uključeno"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 98a4e22..3b0c1a3 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -252,7 +252,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Няма даступных прылад"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Няма падключэння да Wi-Fi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яркасць"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Інвертаваць колеры"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Інверсія колераў"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Дадатковыя налады"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Налады карыстальніка"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Гатова"</string>
@@ -757,7 +757,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Павялічыць увесь экран"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Павялічыць частку экрана"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Пераключальнік"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Замест жэста спецыяльных магчымасцей будзе выкарыстоўвацца кнопка\n\n"<annotation id="link">"Праглядзець налады"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Націсніце, каб адкрыць спецыяльныя магчымасці. Рэгулюйце ці замяняйце кнопку ў Наладах.\n\n"<annotation id="link">"Прагляд налад"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Каб часова схаваць кнопку, перамясціце яе на край"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Перамясціць лявей і вышэй"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Перамясціць правей і вышэй"</string>
@@ -810,10 +810,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Налады"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"У праграме \"<xliff:g id="APP_LABEL">%3$s</xliff:g>\" прайграецца кампазіцыя \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\", выканаўца – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> з <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Прайграць"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Прыпыніць"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Папярэдні трэк"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Наступны трэк"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Прайграць"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Адкрыйце праграму \"<xliff:g id="APP_LABEL">%1$s</xliff:g>\""</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Прайграйце кампазіцыю \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" (выканаўца – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) з дапамогай праграмы \"<xliff:g id="APP_LABEL">%3$s</xliff:g>\""</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Прайграйце кампазіцыю \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" з дапамогай праграмы \"<xliff:g id="APP_LABEL">%2$s</xliff:g>\""</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Адрабіць"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Наблізьцеся, каб прайграць музыку на прыладзе \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\""</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Прайграецца на прыладзе \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\""</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактыўна, праверце праграму"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не знойдзена"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Кіраванне недаступнае"</string>
@@ -828,7 +835,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Выбрана 1 прылада"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Выбрана прылад: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(адключана)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не ўдалося падключыцца. Паўтарыце спробу."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Не ўдалося пераключыцца. Дакраніцеся, каб паўтарыць спробу."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спалучыць з новай прыладай"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Нумар зборкі"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Нумар зборкі скапіраваны ў буфер абмену."</string>
@@ -893,8 +900,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Паказаць усе"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Каб падключыцца да сетак, выключыце Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Каб палепшыць працу прылады, вы можаце дазволіць праграмам і сэрвісам шукаць сеткі Wi-Fi, нават калі Wi‑Fi выключаны. Змяніць гэты рэжым можна ў наладах пошуку сетак Wi-Fi. "<annotation id="link">"Змяніць"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Выключыць рэжым палёту"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> запытвае дазвол на дадаванне ў хуткія налады наступнай пліткі"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Дадаць плітку"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Не дадаваць плітку"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Выбар карыстальніка"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Праграмы працуюць у фонавым рэжыме"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Спыніць"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/tiles_states_strings.xml b/packages/SystemUI/res/values-be/tiles_states_strings.xml
index 72b9bc6..ecfde0b 100644
--- a/packages/SystemUI/res/values-be/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-be/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Выключана"</item>
<item msgid="460891964396502657">"Уключана"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Недаступна"</item>
+ <item msgid="5581384648880018330">"Выключана"</item>
+ <item msgid="8000850843692192257">"Уключана"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index ea68193..6881fcf 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Няма налични устройства"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"не е установена връзка с Wi-Fi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яркост"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Инвертиране на цветовете"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инвертиране на цветовете"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Още настройки"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Потребителски настройки"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Увеличаване на целия екран"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увеличаване на част от екрана"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Превключване"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Жестът за достъпност бе заменен от бутон\n\n"<annotation id="link">"Преглед на настройките"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Докоснете, за да отворите функциите за достъпност. Персон./заменете бутона от настройките.\n\n"<annotation id="link">"Преглед на настройките"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Преместете бутона до края, за да го скриете временно"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Преместване горе вляво"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Преместване горе вдясно"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Настройки"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> на <xliff:g id="ARTIST_NAME">%2$s</xliff:g> се възпроизвежда от <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> от <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Пускане"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Пауза"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Предишен запис"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Следващ запис"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Google Play"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Отваряне на <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Пускане на <xliff:g id="SONG_NAME">%1$s</xliff:g> на <xliff:g id="ARTIST_NAME">%2$s</xliff:g> от <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Пускане на <xliff:g id="SONG_NAME">%1$s</xliff:g> от <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Отмяна"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Преместете се по-близо, за да се възпроизведе на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Възпроизвежда се на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, проверете прилож."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не е намерено"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е налице"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 избрано устройство"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> избрани устройства"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(връзката е прекратена)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Неуспешно свързване. Опитайте отново."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Не може да се превключи. Докоснете за нов опит."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Сдвояване на ново устройство"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер на компилацията"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номерът на компилацията е копиран в буферната памет."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Вижте всички"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"За да превключите мрежите, прекъснете връзката с Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"С цел подобряване на практическата работа с устройството приложенията и услугите пак могат да сканират за Wi‑Fi мрежи по всяко време дори когато функцията за Wi‑Fi e изключена. Можете да промените съответното поведение от настройките за сканиране за Wi‑Fi. "<annotation id="link">"Промяна"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Изключване на самолетния режим"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> иска да добави следния панел към бързите настройки"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Добавяне на панел"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Отмяна на добавянето"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Избор на потребител"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Приложения, които се изпълняват на заден план"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Спиране"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/tiles_states_strings.xml b/packages/SystemUI/res/values-bg/tiles_states_strings.xml
index f0747cc..7424f81 100644
--- a/packages/SystemUI/res/values-bg/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bg/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Изкл."</item>
<item msgid="460891964396502657">"Вкл."</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Не е налице"</item>
+ <item msgid="5581384648880018330">"Изкл."</item>
+ <item msgid="8000850843692192257">"Вкл."</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 377bd47..571118a 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"কোনো ডিভাইস উপলব্ধ নয়"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ওয়াই-ফাই কানেক্ট করা নেই"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"উজ্জ্বলতা"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"বিপরীত রঙ"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"কালার ইনভার্সন"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"আরও সেটিংস"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ব্যবহারকারী সেটিংস"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"সম্পন্ন হয়েছে"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"সম্পূর্ণ স্ক্রিন বড় করে দেখা"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"স্ক্রিনের কিছুটা অংশ বড় করুন"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"বদল করুন"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"অ্যাক্সেসিবিলিটি জেসচার পরিবর্তন করে অ্যাক্সেসেবিলিটি বোতাম করা হয়েছে\n\n"<annotation id="link">"সেটিংস দেখুন"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"অ্যাক্সেসিবিলিটি ফিচার খুলতে ট্যাপ করুন। কাস্টমাইজ করুন বা সেটিংসে এই বোতামটি সরিয়ে দিন।\n\n"<annotation id="link">"সেটিংস দেখুন"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"এটি অস্থায়ীভাবে লুকাতে বোতামটি কোণে সরান"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"উপরে বাঁদিকে সরান"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"উপরে ডানদিকে সরান"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"সেটিংস"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>-এর <xliff:g id="SONG_NAME">%1$s</xliff:g> গানটি <xliff:g id="APP_LABEL">%3$s</xliff:g> অ্যাপে চলছে"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>টির মধ্যে <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>টি"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"চালান"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"পজ করুন"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"আগের ট্র্যাক"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"পরের ট্র্যাক"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"চালান"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> অ্যাপ খুলুন"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>-এর <xliff:g id="SONG_NAME">%1$s</xliff:g> গানটি <xliff:g id="APP_LABEL">%3$s</xliff:g> অ্যাপে চালান"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> গানটি <xliff:g id="APP_LABEL">%2$s</xliff:g> অ্যাপে চালান"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"আগের অবস্থায় ফিরুন"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g>-এ চালাতে আরও কাছে আনুন"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g>-এ ভিডিও চালানো হচ্ছে"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"বন্ধ আছে, অ্যাপ চেক করুন"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"খুঁজে পাওয়া যায়নি"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"কন্ট্রোল উপলভ্য নেই"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"১টি ডিভাইস বেছে নেওয়া হয়েছে"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g>টি ডিভাইস বেছে নেওয়া হয়েছে"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ডিসকানেক্ট হয়ে গেছে)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"কানেক্ট করা যায়নি। আবার চেষ্টা করুন।"</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"পাল্টানো যাচ্ছে না। আবার চেষ্টা করতে ট্যাপ করুন।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইস পেয়ার করুন"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ড নম্বর"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"বিল্ড নম্বর ক্লিপবোর্ডে কপি করা হয়েছে।"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"সবকটি দেখুন"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"নেটওয়ার্ক বদলাতে ইথারনেট ডিসকানেক্ট করুন"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"ডিভাইস সংক্রান্ত অভিজ্ঞতা আরও ভাল করতে, অ্যাপ ও পরিষেবা যেকোনও সময় আপনার ওয়াই-ফাই নেটওয়ার্ক স্ক্যান করতে পারবে, এমনকি ডিভাইসের ওয়াই-ফাই বন্ধ করা থাকলেও। ওয়াই-ফাই স্ক্যানিং সেটিংস থেকে আপনি এটি পরিবর্তন করতে পারবেন। "<annotation id="link">"পরিবর্তন করুন"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"\'বিমান\' মোড বন্ধ করুন"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> নিম্নলিখিত টাইল দ্রুত সেটিংস মেনুতে যোগ করতে চায়"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"টাইল যোগ করুন"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"টাইল যোগ করবেন না"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ব্যবহারকারী বেছে নিন"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ব্যাকগ্রাউন্ডে অ্যাপ চলছে"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"বন্ধ করুন"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/tiles_states_strings.xml b/packages/SystemUI/res/values-bn/tiles_states_strings.xml
index 0530e46..eddf851 100644
--- a/packages/SystemUI/res/values-bn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bn/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"বন্ধ আছে"</item>
<item msgid="460891964396502657">"চালু আছে"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"উপলভ্য নেই"</item>
+ <item msgid="5581384648880018330">"বন্ধ আছে"</item>
+ <item msgid="8000850843692192257">"চালু আছে"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 23eeb77..6d4326b 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -251,7 +251,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nema dostupnih uređaja"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"WiFi mreža nije povezana"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Osvjetljenje"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverzija boja"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija boja"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Više postavki"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Korisničke postavke"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Gotovo"</string>
@@ -752,7 +752,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Uvećavanje prikaza preko cijelog ekrana"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Uvećavanje dijela ekrana"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Prekidač"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Dugme za pristupačnost je zamijenilo pokret za pristupačnost\n\n"<annotation id="link">"Prikaži postavke"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dodirnite da otvorite funkcije pristupačnosti. Prilagodite ili zamijenite dugme u Postavkama.\n\n"<annotation id="link">"Postavke"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Premjestite dugme do ivice da ga privremeno sakrijete"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Pomjeranje gore lijevo"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Pomjeranje gore desno"</string>
@@ -804,10 +804,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Postavke"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"Pjesma <xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se reproducira pomoću aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> od <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Reproduciranje"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pauziranje"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Prethodna numera"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Sljedeća numera"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Pokrenite"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otvorite aplikaciju <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Reproducirajte pjesmu <xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> pomoću aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reproducirajte pjesmu <xliff:g id="SONG_NAME">%1$s</xliff:g> pomoću aplikacije <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Poništi"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Približite se da reproducirate na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Reproducira se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, vidite aplikaciju"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
@@ -822,7 +829,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Odabran je 1 uređaj"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Broj odabranih uređaja: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(veza je prekinuta)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Povezivanje nije uspjelo. Pokušajte ponovo."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nije moguće prebaciti. Dodirnite da pokušate ponovo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uparite novi uređaj"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u međumemoriju."</string>
@@ -887,8 +894,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da promijenite mrežu, isključite ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Radi poboljšanja iskustva s uređajem aplikacije i usluge i dalje mogu bilo kada skenirati WiFi mreže, čak i kada je WiFi isključen. Ovo možete promijeniti u Postavkama skeniranja WiFi mreže. "<annotation id="link">"Promijeni"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Isključi način rada u avionu"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> želi dodati sljedeću karticu u Brze postavke"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj karticu"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nemoj dodati karticu"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Odaberite korisnika"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikacije su aktivne u pozadini"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zaustavi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/tiles_states_strings.xml b/packages/SystemUI/res/values-bs/tiles_states_strings.xml
index 5d9edf5..88caf97 100644
--- a/packages/SystemUI/res/values-bs/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-bs/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Isključeno"</item>
<item msgid="460891964396502657">"Uključeno"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Nedostupno"</item>
+ <item msgid="5581384648880018330">"Isključeno"</item>
+ <item msgid="8000850843692192257">"Uključeno"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 446b0f4..e6c7cfb 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No hi ha cap dispositiu disponible."</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"La Wi‑Fi no està connectada"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillantor"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverteix colors"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversió de colors"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Més opcions"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Configuració d\'usuari"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Fet"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Amplia la pantalla completa"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Amplia una part de la pantalla"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Canvia"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"El gest d\'accessibilitat s\'ha substituït pel botó d\'accessibilitat\n\n"<annotation id="link">"Mostra la configuració"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toca per obrir funcions d\'accessibilitat. Personalitza o substitueix el botó a Configuració.\n\n"<annotation id="link">"Mostra"</annotation>"."</string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mou el botó a l\'extrem per amagar-lo temporalment"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mou a dalt a l\'esquerra"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mou a dalt a la dreta"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Configuració"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) s\'està reproduint des de l\'aplicació <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Reprodueix"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Posa en pausa"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Pista anterior"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Pista següent"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reprodueix"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Obre <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Reprodueix <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) des de l\'aplicació <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reprodueix <xliff:g id="SONG_NAME">%1$s</xliff:g> des de l\'aplicació <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Desfés"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Mou més a prop per reproduir a <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"S\'està reproduint a <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactiu; comprova l\'aplicació"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"No s\'ha trobat"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"El control no està disponible"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositiu seleccionat"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"S\'han seleccionat <xliff:g id="COUNT">%1$d</xliff:g> dispositius"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desconnectat)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"No s\'ha pogut connectar. Torna-ho a provar."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"No es pot canviar. Torna-ho a provar."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincula un dispositiu nou"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilació"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"El número de compilació s\'ha copiat al porta-retalls."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Mostra-ho tot"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Per canviar de xarxa, desconnecta la connexió Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Per millorar l\'experiència del dispositiu, les aplicacions i els serveis poden cercar xarxes Wi‑Fi en qualsevol moment, fins i tot quan la Wi‑Fi estigui desactivada. Pots canviar aquesta opció a la configuració de cerca de xarxes Wi‑Fi. "<annotation id="link">"Canvia-la"</annotation>"."</string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desactiva el mode d\'avió"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vol afegir la icona següent a la configuració ràpida"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Afegeix la icona"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"No afegeixis la icona"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecciona un usuari"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplicacions que s\'executen en segon pla"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Atura"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/tiles_states_strings.xml b/packages/SystemUI/res/values-ca/tiles_states_strings.xml
index 55dfec0..e3538fa 100644
--- a/packages/SystemUI/res/values-ca/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ca/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Desactivat"</item>
<item msgid="460891964396502657">"Activat"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"No disponible"</item>
+ <item msgid="5581384648880018330">"Desactivat"</item>
+ <item msgid="8000850843692192257">"Activat"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 37a827b..b2becd8 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -252,7 +252,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nejsou dostupná žádná zařízení"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Není připojena Wi-Fi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Jas"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Převrátit barvy"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Převrácení barev"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Další nastavení"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Uživatelské nastavení"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Hotovo"</string>
@@ -757,7 +757,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Zvětšit celou obrazovku"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zvětšit část obrazovky"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Přepnout"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Tlačítko přístupnosti bylo nahrazeno gestem přístupnosti\n\n"<annotation id="link">"Zobrazit nastavení"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Klepnutím otevřete funkce přístupnosti. Tlačítko lze upravit nebo nahradit v Nastavení.\n\n"<annotation id="link">"Nastavení"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Přesunutím tlačítka k okraji ho dočasně skryjete"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Přesunout vlevo nahoru"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Přesunout vpravo nahoru"</string>
@@ -810,10 +810,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavení"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"Skladba <xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> hrajte z aplikace <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> z <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Přehrát"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pozastavit"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Předchozí skladba"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Další skladba"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Přehrát"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otevřít aplikaci <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Přehrát skladbu <xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> z aplikace <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Přehrát skladbu <xliff:g id="SONG_NAME">%1$s</xliff:g> z aplikace <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Vrátit zpět"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Pokud chcete přehrávat na zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>, přibližte se k němu"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Přehrává se na zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivní, zkontrolujte aplikaci"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nenalezeno"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládání není k dispozici"</string>
@@ -828,7 +835,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Je vybráno 1 zařízení"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Vybraná zařízení: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(odpojeno)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Spojení se nezdařilo. Zkuste to znovu."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nelze přepnout. Klepnutím opakujte akci."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovat nové zařízení"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo sestavení"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Číslo sestavení bylo zkopírováno do schránky."</string>
@@ -893,8 +900,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Zobrazit vše"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pokud chcete přepnout sítě, odpojte ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Za účelem lepšího fungování zařízení mohou aplikace a služby vyhledávat sítě Wi-Fi, i když je připojení Wi-Fi vypnuté. Toto chování můžete změnit v nastavení vyhledávání Wi-Fi. "<annotation id="link">"Změnit"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Vypnout režim Letadlo"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Aplikace <xliff:g id="APPNAME">%1$s</xliff:g> chce do Rychlého nastavení přidat následující dlaždici"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Přidat dlaždici"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nepřidávat dlaždici"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Zvolte uživatele"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikace běžící na pozadí"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Konec"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/tiles_states_strings.xml b/packages/SystemUI/res/values-cs/tiles_states_strings.xml
index 30f5bef..3f40ab6 100644
--- a/packages/SystemUI/res/values-cs/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-cs/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Vypnuto"</item>
<item msgid="460891964396502657">"Zapnuto"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Nedostupné"</item>
+ <item msgid="5581384648880018330">"Vyp"</item>
+ <item msgid="8000850843692192257">"Zap"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index bb4553f..d559c15 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Der er ingen tilgængelige enheder"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Manglende Wi-Fi-forbindelse"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Lysstyrke"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Ombyt farver"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ombytning af farver"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Flere indstillinger"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Brugerindstillinger"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Udfør"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Forstør hele skærmen"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Forstør en del af skærmen"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Skift"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Knappen Hjælpefunktioner har erstattet bevægelsen for hjælpefunktioner\n\n"<annotation id="link">"Se indstillinger"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tryk for at åbne hjælpefunktioner. Tilpas eller erstat denne knap i Indstillinger.\n\n"<annotation id="link">"Se indstillingerne"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Flyt knappen til kanten for at skjule den midlertidigt"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Flyt op til venstre"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Flyt op til højre"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Indstillinger"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> af <xliff:g id="ARTIST_NAME">%2$s</xliff:g> afspilles via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> af <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Afspil"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Sæt på pause"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Afspil forrige"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Næste nummer"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Afspil"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Åbn <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Afspil <xliff:g id="SONG_NAME">%1$s</xliff:g> af <xliff:g id="ARTIST_NAME">%2$s</xliff:g> via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Afspil <xliff:g id="SONG_NAME">%1$s</xliff:g> via <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Fortryd"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Flyt enheden tættere på for at afspille på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Afspilles på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Tjek appen"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ikke fundet"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Styringselement ikke tilgængeligt"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Der er valgt 1 enhed"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Der er valgt <xliff:g id="COUNT">%1$d</xliff:g> enhed"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(afbrudt)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Der kunne ikke oprettes forbindelse. Prøv igen."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Det var ikke muligt at skifte. Tryk for at prøve igen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Par ny enhed"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildnummeret blev kopieret til udklipsholderen."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Afbryd ethernetforbindelsen for at skifte netværk"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"For at forbedre brugeroplevelsen på enheden kan apps og tjenester stadig til enhver tid scanne efter Wi‑Fi-netværk, også selvom Wi‑Fi er deaktiveret. Du kan ændre dette i indstillingerne for Wi-Fi-scanning. "<annotation id="link">"Skift indstilling"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Deaktiver flytilstand"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vil gerne føje dette handlingsfelt til Kvikmenu"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Tilføj handlingsfelt"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Tilføj ikke felt"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Vælg bruger"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps, der kører i baggrunden"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/tiles_states_strings.xml b/packages/SystemUI/res/values-da/tiles_states_strings.xml
index 0423949..b479a44 100644
--- a/packages/SystemUI/res/values-da/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-da/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Fra"</item>
<item msgid="460891964396502657">"Til"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Ikke tilgængelig"</item>
+ <item msgid="5581384648880018330">"Fra"</item>
+ <item msgid="8000850843692192257">"Til"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 13ad7aa..801d9e0 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -181,7 +181,7 @@
<string name="accessibility_quick_settings_airplane_changed_on" msgid="6327378061894076288">"Der Flugmodus ist aktiviert."</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"lautlos"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"nur Weckrufe"</string>
- <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Nicht stören."</string>
+ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Bitte nicht stören."</string>
<string name="accessibility_quick_settings_dnd_changed_off" msgid="1457150026842505799">"„Bitte nicht stören“ deaktiviert."</string>
<string name="accessibility_quick_settings_dnd_changed_on" msgid="186315911607486129">"„Bitte nicht stören“ aktiviert"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth."</string>
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Keine Geräte verfügbar"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"WLAN nicht verbunden"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Helligkeit"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Farben umkehren"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Farbumkehr"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Weitere Einstellungen"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Nutzereinstellungen"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Fertig"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ganzen Bildschirm vergrößern"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Teil des Bildschirms vergrößern"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Schalter"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Die Schaltfläche „Bedienungshilfen“ ersetzt die Touch-Geste für Bedienungshilfen\n\n"<annotation id="link">"Einstellungen aufrufen"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tippe, um die Bedienungshilfen aufzurufen. Du kannst diese Schaltfläche in den Einstellungen anpassen oder ersetzen.\n\n"<annotation id="link">"Zu den Einstellungen"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Durch Ziehen an den Rand wird die Schaltfläche zeitweise ausgeblendet"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Nach oben links verschieben"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Nach rechts oben verschieben"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Einstellungen"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> von <xliff:g id="ARTIST_NAME">%2$s</xliff:g> wird gerade über <xliff:g id="APP_LABEL">%3$s</xliff:g> wiedergegeben"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> von <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Wiedergeben"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pausieren"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Vorheriger Titel"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Nächster Titel"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Wiedergeben"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> öffnen"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> von <xliff:g id="ARTIST_NAME">%2$s</xliff:g> über <xliff:g id="APP_LABEL">%3$s</xliff:g> wiedergeben"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> über <xliff:g id="APP_LABEL">%2$s</xliff:g> wiedergeben"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Rückgängig machen"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Gehe für die Wiedergabe näher an <xliff:g id="DEVICENAME">%1$s</xliff:g> heran"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Wird auf <xliff:g id="DEVICENAME">%1$s</xliff:g> abgespielt"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv – sieh in der App nach"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nicht gefunden"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Steuerelement nicht verfügbar"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Ein Gerät ausgewählt"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> Geräte ausgewählt"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(nicht verbunden)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Verbindung nicht möglich. Versuch es noch einmal."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Wechseln nicht möglich. Tippe, um es noch einmal zu versuchen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Neues Gerät koppeln"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-Nummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build-Nummer in Zwischenablage kopiert."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Alle ansehen"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Trenne das Ethernetkabel, um das Netzwerk zu wechseln"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Zur Verbesserung der Gerätenutzung können Apps und Dienste weiter nach WLANs suchen, auch wenn die WLAN-Funktion deaktiviert ist. Dies lässt sich in den Einstellungen für die WLAN-Suche ändern. "<annotation id="link">"Ändern"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Flugmodus deaktivieren"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> möchte die folgende Kachel den Schnelleinstellungen hinzufügen"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Kachel hinzufügen"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Kachel nicht hinzu"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Nutzer auswählen"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps, die im Hintergrund ausgeführt werden"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Beenden"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/tiles_states_strings.xml b/packages/SystemUI/res/values-de/tiles_states_strings.xml
index a67ce6c..81f030c 100644
--- a/packages/SystemUI/res/values-de/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-de/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Aus"</item>
<item msgid="460891964396502657">"An"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Nicht verfügbar"</item>
+ <item msgid="5581384648880018330">"Aus"</item>
+ <item msgid="8000850843692192257">"An"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 38534f4..bc7d3b0 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Δεν υπάρχουν διαθέσιμες συσκευές"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Το Wi-Fi δεν είναι συνδεδεμένο"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Φωτεινότητα"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Αντιστροφή χρωμάτων"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Αντιστροφή χρωμάτων"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Περισσότερες ρυθμίσεις"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Ρυθμίσεις χρήστη"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Τέλος"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Μεγέθυνση πλήρους οθόνης"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Μεγέθυνση μέρους της οθόνης"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Εναλλαγή"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Το κουμπί προσβασιμότητας αντικατέστησε την κίνηση προσβασιμότητας\n\n"<annotation id="link">"Προβολή ρυθμίσεων"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Πατήστε για άνοιγμα των λειτουργιών προσβασιμότητας. Προσαρμόστε ή αντικαταστήστε το κουμπί στις Ρυθμίσεις.\n\n"<annotation id="link">"Προβολή ρυθμίσεων"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Μετακινήστε το κουμπί στο άκρο για προσωρινή απόκρυψη"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Μετακίνηση επάνω αριστερά"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Μετακίνηση επάνω δεξιά"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Ρυθμίσεις"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"Γίνεται αναπαραγωγή του <xliff:g id="SONG_NAME">%1$s</xliff:g> από <xliff:g id="ARTIST_NAME">%2$s</xliff:g> στην εφαρμογή <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> από <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Αναπαραγωγή"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Παύση"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Προηγούμενο κομμάτι"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Επόμενο κομμάτι"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Άνοιγμα της εφαρμογής <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Αναπαραγωγή του <xliff:g id="SONG_NAME">%1$s</xliff:g> από <xliff:g id="ARTIST_NAME">%2$s</xliff:g> στην εφαρμογή <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Αναπαραγωγή του <xliff:g id="SONG_NAME">%1$s</xliff:g> στην εφαρμογή <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Αναίρεση"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Πλησιάστε για αναπαραγωγή στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Αναπαραγωγή στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Ανενεργό, έλεγχος εφαρμογής"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Δεν βρέθηκε."</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Μη διαθέσιμο στοιχείο ελέγχου"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Επιλέχτηκε 1 συσκευή"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Επιλέχτηκαν <xliff:g id="COUNT">%1$d</xliff:g> συσκευές"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(αποσυνδέθηκε)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Δεν ήταν δυνατή η σύνδεση. Δοκιμάστε ξανά."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Δεν είναι δυνατή η εναλλαγή. Πατήστε για επανάληψη."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Σύζευξη νέας συσκευής"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Αριθμός έκδοσης"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Ο αριθμός έκδοσης αντιγράφηκε στο πρόχειρο."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Εμφάνιση όλων"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Για εναλλαγή δικτύων, αποσυνδέστε το ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Για βελτίωση της εμπειρίας στη συσκευή, οι εφαρμογές και οι υπηρεσίες μπορούν ακόμα να εκτελούν σάρωση για δίκτυα Wi‑Fi ανά πάσα στιγμή, ακόμα και όταν το Wi‑Fi είναι απενεργοποιημένο. Μπορείτε να αλλάξετε αυτήν τη ρύθμιση στις ρυθμίσεις της Σάρωσης Wi‑Fi. "<annotation id="link">"Αλλαγή"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Απενεργοποίηση λειτουργίας πτήσης"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Η εφαρμογή <xliff:g id="APPNAME">%1$s</xliff:g> θέλει να προσθέσει το παρακάτω πλακίδιο στις Γρήγορες ρυθμίσεις"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Προσθήκη πλακιδίου"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Χωρίς προσθ. πλακιδ."</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Επιλογή χρήστη"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Οι εφαρμογές βρίσκονται σε εξέλιξη στο παρασκήνιο"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Διακοπή"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/tiles_states_strings.xml b/packages/SystemUI/res/values-el/tiles_states_strings.xml
index 55d162d..422f2aa 100644
--- a/packages/SystemUI/res/values-el/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-el/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Ανενεργή"</item>
<item msgid="460891964396502657">"Ενεργή"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Μη διαθέσιμο"</item>
+ <item msgid="5581384648880018330">"Ανενεργό"</item>
+ <item msgid="8000850843692192257">"Ενεργό"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 8debf42..3427442 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No devices available"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi‑Fi not connected"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invert colours"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Colour inversion"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"More settings"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Accessibility button replaced the accessibility gesture\n\n"<annotation id="link">"View settings"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Move top right"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> of <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Play"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pause"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Previous track"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Next track"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Open <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> from <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Undo"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> devices selected"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Can\'t switch. Tap to try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"To improve device experience, apps and services can still scan for Wi‑Fi networks at any time, even when Wi‑Fi is off. You can change this in Wi‑Fi scanning settings. "<annotation id="link">"Change"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Turn off aeroplane mode"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wants to add the following tile to Quick Settings"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Add tile"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Do not add tile"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps running in the background"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
index fea1f10..9b00c8b 100644
--- a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Unavailable"</item>
+ <item msgid="5581384648880018330">"Off"</item>
+ <item msgid="8000850843692192257">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index da144d8..b6d1b1d 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No devices available"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi‑Fi not connected"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invert colours"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Colour inversion"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"More settings"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Accessibility button replaced the accessibility gesture\n\n"<annotation id="link">"View settings"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Move top right"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> of <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Play"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pause"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Previous track"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Next track"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Open <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> from <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Undo"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> devices selected"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Can\'t switch. Tap to try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"To improve device experience, apps and services can still scan for Wi‑Fi networks at any time, even when Wi‑Fi is off. You can change this in Wi‑Fi scanning settings. "<annotation id="link">"Change"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Turn off aeroplane mode"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wants to add the following tile to Quick Settings"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Add tile"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Do not add tile"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps running in the background"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
index fea1f10..9b00c8b 100644
--- a/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Unavailable"</item>
+ <item msgid="5581384648880018330">"Off"</item>
+ <item msgid="8000850843692192257">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 8debf42..3427442 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No devices available"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi‑Fi not connected"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invert colours"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Colour inversion"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"More settings"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Accessibility button replaced the accessibility gesture\n\n"<annotation id="link">"View settings"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Move top right"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> of <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Play"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pause"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Previous track"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Next track"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Open <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> from <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Undo"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> devices selected"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Can\'t switch. Tap to try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"To improve device experience, apps and services can still scan for Wi‑Fi networks at any time, even when Wi‑Fi is off. You can change this in Wi‑Fi scanning settings. "<annotation id="link">"Change"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Turn off aeroplane mode"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wants to add the following tile to Quick Settings"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Add tile"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Do not add tile"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps running in the background"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
index fea1f10..9b00c8b 100644
--- a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Unavailable"</item>
+ <item msgid="5581384648880018330">"Off"</item>
+ <item msgid="8000850843692192257">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 8debf42..3427442 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No devices available"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi‑Fi not connected"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invert colours"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Colour inversion"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"More settings"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Accessibility button replaced the accessibility gesture\n\n"<annotation id="link">"View settings"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Move top right"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> of <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Play"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pause"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Previous track"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Next track"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Open <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> from <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Undo"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> devices selected"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Can\'t switch. Tap to try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"To improve device experience, apps and services can still scan for Wi‑Fi networks at any time, even when Wi‑Fi is off. You can change this in Wi‑Fi scanning settings. "<annotation id="link">"Change"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Turn off aeroplane mode"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wants to add the following tile to Quick Settings"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Add tile"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Do not add tile"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps running in the background"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
index fea1f10..9b00c8b 100644
--- a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Unavailable"</item>
+ <item msgid="5581384648880018330">"Off"</item>
+ <item msgid="8000850843692192257">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index bb95d28..a4e9ab4 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No devices available"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi‑Fi not connected"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invert colors"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Color inversion"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"More settings"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Accessibility button replaced the accessibility gesture\n\n"<annotation id="link">"View settings"</annotation>""</string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customize or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation>""</string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Move top right"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> of <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Play"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pause"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Previous track"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Next track"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Open <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> from <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Undo"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Move closer to play on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 device selected"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> devices selected"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Can\'t switch. Tap to try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"To improve device experience, apps and services can still scan for Wi‑Fi networks at any time, even when Wi‑Fi is off. You can change this in Wi‑Fi scanning settings. "<annotation id="link">"Change"</annotation>""</string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Turn off airplane mode"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wants to add the following tile to Quick Settings"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Add tile"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Do not add tile"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps running in the background"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
index 78f4137..0012b57 100644
--- a/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Unavailable"</item>
+ <item msgid="5581384648880018330">"Off"</item>
+ <item msgid="8000850843692192257">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index fd18230..9065e7f 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No hay dispositivos disponibles"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Red Wi-Fi no conectada"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillo"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invertir colores"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversión de color"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Más configuraciones"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Configuración del usuario"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Listo"</string>
@@ -743,11 +743,11 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Mover hacia abajo"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Mover hacia la izquierda"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Mover hacia la derecha"</string>
- <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Botón de ampliación"</string>
+ <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Interruptor de ampliación"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar pantalla completa"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte de la pantalla"</string>
- <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Botón"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"El botón de accesibilidad ha reemplazado el gesto de accesibilidad\n\n"<annotation id="link">"Ver configuración"</annotation></string>
+ <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Interruptor"</string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Presiona para abrir las funciones de accesibilidad. Personaliza o cambia botón en Config.\n\n"<annotation id="link">"Ver config"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mueve el botón hacia el borde para ocultarlo temporalmente"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover arriba a la izquierda"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover arriba a la derecha"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Configuración"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"Se está reproduciendo <xliff:g id="SONG_NAME">%1$s</xliff:g>, de <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Reproducir"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pausar"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Pista anterior"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Pista siguiente"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproducir"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abre <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Reproduce <xliff:g id="SONG_NAME">%1$s</xliff:g>, de <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reproducir <xliff:g id="SONG_NAME">%1$s</xliff:g> en <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Deshacer"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Acércate para reproducir en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Reproduciendo en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Verifica la app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"No se encontró"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"El control no está disponible"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Se seleccionó 1 dispositivo"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Se seleccionaron <xliff:g id="COUNT">%1$d</xliff:g> dispositivos"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desconectado)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"No se pudo establecer la conexión. Vuelve a intentarlo."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"No se pudo conectar. Presiona para volver a intentarlo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo nuevo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Se copió el número de compilación en el portapapeles."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de red, desconéctate de Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para mejorar la experiencia con el dispositivo, las apps y los servicios pueden seguir buscando redes Wi-Fi en cualquier momento, incluso cuando la conexión Wi-Fi esté desactivada. Puedes cambiar este parámetro en la configuración de búsqueda de Wi-Fi. "<annotation id="link">"Cambiar"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desactivar el modo de avión"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> quiere agregar el siguiente azulejo a la Configuración rápida"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Agregar azulejo"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"No agregar azulejo"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleccionar usuario"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps en ejecución en segundo plano"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Detener"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
index d70aa53..afb0e72 100644
--- a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"No"</item>
<item msgid="460891964396502657">"Sí"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"No disponible"</item>
+ <item msgid="5581384648880018330">"Desactivado"</item>
+ <item msgid="8000850843692192257">"Activado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index a2eb152..cf3b2f7 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"UI del sistema"</string>
- <string name="battery_low_title" msgid="6891106956328275225">"Es posible que te quedes sin batería pronto"</string>
+ <string name="battery_low_title" msgid="6891106956328275225">"Puede que te quedes sin batería pronto"</string>
<string name="battery_low_percent_format" msgid="4276661262843170964">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería"</string>
<string name="invalid_charger_title" msgid="938685362320735167">"No se puede cargar por USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Utiliza el cargador original incluido con el dispositivo"</string>
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"No hay dispositivos disponibles"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi‑Fi no conectado"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillo"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invertir colores"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Invertir colores"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Más ajustes"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Ajustes de usuario"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Hecho"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar pantalla completa"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte de la pantalla"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Cambiar"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"El botón Accesibilidad ha reemplazado el gesto de accesibilidad\n\nVer ajustes"<annotation id="link"></annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toca para abrir funciones de accesibilidad. Personaliza o sustituye este botón en Ajustes.\n\n"<annotation id="link">"Ver ajustes"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mueve el botón hacia el borde para ocultarlo temporalmente"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover arriba a la izquierda"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover arriba a la derecha"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Ajustes"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"Se está reproduciendo <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Reproducir"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pausar"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Pista anterior"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Siguiente pista"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproducir"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abrir <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Poner <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Poner <xliff:g id="SONG_NAME">%1$s</xliff:g> en <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Deshacer"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g> para que se reproduzca en ese dispositivo"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Reproduciendo en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo, comprobar aplicación"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"No se ha encontrado"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Control no disponible"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo seleccionado"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> dispositivos seleccionados"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desconectado)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"No se ha podido conectar. Inténtalo de nuevo."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"No se puede cambiar. Toca para volver a intentarlo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Emparejar nuevo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número de compilación copiado en el portapapeles."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de red, desconecta el cable Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para mejorar la experiencia con el dispositivo, las aplicaciones y los servicios podrán buscar redes Wi-Fi en cualquier momento, aunque la conexión Wi-Fi esté desactivada. Puedes cambiarlo en los ajustes de búsqueda de redes Wi-Fi. "<annotation id="link">"Cambiar"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desactivar modo avión"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> quiere añadir el siguiente recuadro a ajustes rápidos"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Añadir recuadro"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"No añadir recuadro"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleccionar usuario"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplicaciones ejecutándose en segundo plano"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Detener"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/tiles_states_strings.xml b/packages/SystemUI/res/values-es/tiles_states_strings.xml
index 9773954..dd1ed43 100644
--- a/packages/SystemUI/res/values-es/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Desactivado"</item>
<item msgid="460891964396502657">"Activado"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"No disponible"</item>
+ <item msgid="5581384648880018330">"Desactivado"</item>
+ <item msgid="8000850843692192257">"Activado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index f1acddaf..1494f0f 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Ühtegi seadet pole saadaval"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"WiFi-ühendus puudub"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Heledus"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Värvide vahetamine"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Värvide ümberpööramine"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Rohkem seadeid"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Kasutaja seaded"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Valmis"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Täisekraani suurendamine"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekraanikuva osa suurendamine"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Vaheta"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Juurdepääsetavuse nupp asendas juurdepääsuliigutuse\n\n"<annotation id="link">"Vaadake seadeid"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Puudutage juurdepääsufunktsioonide avamiseks. Kohandage nuppu või asendage see seadetes.\n\n"<annotation id="link">"Kuva seaded"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Teisaldage nupp serva, et see ajutiselt peita"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Teisalda üles vasakule"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Teisalda üles paremale"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Seaded"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> esitajalt <xliff:g id="ARTIST_NAME">%2$s</xliff:g> esitatakse rakenduses <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Esita"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Peata"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Eelmine lugu"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Järgmine lugu"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Esitamine"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Rakenduse <xliff:g id="APP_LABEL">%1$s</xliff:g> avamine"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Esita lugu <xliff:g id="SONG_NAME">%1$s</xliff:g> esitajalt <xliff:g id="ARTIST_NAME">%2$s</xliff:g> rakenduses <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Esita lugu <xliff:g id="SONG_NAME">%1$s</xliff:g> rakenduses <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Võta tagasi"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Minge lähemale, et seadmes <xliff:g id="DEVICENAME">%1$s</xliff:g> esitada"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Esitatakse seadmes <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Passiivne, vaadake rakendust"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ei leitud"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Juhtelement pole saadaval"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 seade on valitud"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> seadet on valitud"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ühendus on katkestatud)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ühenduse loomine ebaõnnestus. Proovige uuesti."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Ei saa lülitada. Puudutage uuesti proovimiseks."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uue seadme sidumine"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Järgunumber"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Järgunumber kopeeriti lõikelauale."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Kuva kõik"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Võrkude vahetamiseks katkestage Etherneti-ühendus"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Seadme kasutuskogemuse parandamiseks võivad rakendused ja teenused siiski alati otsida WiFi-võrke isegi siis, kui WiFi on väljas. Seda saab muuta WiFi-skannimise seadetes. "<annotation id="link">"Muuda"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Lennureżiimi väljalülitamine"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> soovib kiirseadetesse lisada järgmise paani"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Lisa paan"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ära lisa paani"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Kasutaja valimine"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Taustal töötavad rakendused"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Peata"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/tiles_states_strings.xml b/packages/SystemUI/res/values-et/tiles_states_strings.xml
index 1f14a1c..26fbe80 100644
--- a/packages/SystemUI/res/values-et/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-et/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Väljas"</item>
<item msgid="460891964396502657">"Sees"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Pole saadaval"</item>
+ <item msgid="5581384648880018330">"Väljas"</item>
+ <item msgid="8000850843692192257">"Sees"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index f220cc7..565bc1b 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Ez dago gailurik erabilgarri"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Ez zaude konektatuta wifi-sarera"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Distira"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Alderantzikatu koloreak"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Kolore-alderantzikatzea"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Ezarpen gehiago"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Erabiltzaile-ezarpenak"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Eginda"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Handitu pantaila osoa"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Handitu pantailaren zati bat"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Botoia"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Erabilerraztasuna botoiak erabilerraztasun-keinua ordezkatu du\n\n"<annotation id="link">"Ikusi ezarpenak"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Erabilerraztasun-eginbideak irekitzeko, sakatu hau. Ezarpenetan pertsonalizatu edo ordez dezakezu botoia.\n\n"<annotation id="link">"Ikusi ezarpenak"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Eraman botoia ertzera aldi baterako ezkutatzeko"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Eraman goialdera, ezkerretara"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Eraman goialdera, eskuinetara"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Ezarpenak"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) ari da erreproduzitzen <xliff:g id="APP_LABEL">%3$s</xliff:g> bidez"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Erreproduzitu"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pausatu"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Aurrekoa"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Hurrengo pista"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Erreproduzitu"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Ireki <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Erreproduzitu <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) <xliff:g id="APP_LABEL">%3$s</xliff:g> bidez"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Erreproduzitu <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%2$s</xliff:g> bidez"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Desegin"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Gerturatu <xliff:g id="DEVICENAME">%1$s</xliff:g> gailuan erreproduzitzeko"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> pantailan erreproduzitzen"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktibo; egiaztatu aplikazioa"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ez da aurkitu"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Ez dago erabilgarri kontrolatzeko aukera"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 gailu hautatu da"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> gailu hautatu dira"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(deskonektatuta)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ezin izan da konektatu. Saiatu berriro."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Ezin da aldatu. Berriro saiatzeko, sakatu hau."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parekatu beste gailu batekin"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Konpilazio-zenbakia"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Kopiatu da konpilazio-zenbakia arbelean."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Ikusi guztiak"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Sarea aldatzeko, deskonektatu Ethernet-a"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Gailuaren funtzionamendua hobetzeko, aplikazioek eta zerbitzuek wifi-sareak bilatzen jarraituko dute, baita wifi-konexioa desaktibatuta dagoenean ere. Aukera hori aldatzeko, joan wifi-sareen bilaketaren ezarpenetara. "<annotation id="link">"Aldatu"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desaktibatu hegaldi modua"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> aplikazioak lauza hau gehitu nahi du Ezarpen bizkorrak menuan:"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Gehitu lauza"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ez gehitu lauza"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Hautatu erabiltzaile bat"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Atzeko planoan exekutatzen ari diren aplikazioak"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Gelditu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/tiles_states_strings.xml b/packages/SystemUI/res/values-eu/tiles_states_strings.xml
index 88e7069..a2a08db 100644
--- a/packages/SystemUI/res/values-eu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-eu/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Desaktibatuta"</item>
<item msgid="460891964396502657">"Aktibatuta"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Ez dago erabilgarri"</item>
+ <item msgid="5581384648880018330">"Desaktibatuta"</item>
+ <item msgid="8000850843692192257">"Aktibatuta"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 08d13fd..674101d6 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"دستگاهی موجود نیست"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi وصل نیست"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"روشنایی"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"برگردان رنگها"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"وارونگی رنگ"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"تنظیمات بیشتر"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"تنظیمات کاربر"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"تمام"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"درشتنمایی تمامصفحه"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"درشتنمایی بخشی از صفحه"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"کلید"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"دکمه دسترسپذیری جایگزین اشاره دسترسپذیری شد\n\n"<annotation id="link">"مشاهده تنظیمات"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"برای باز کردن ویژگیهای دسترسپذیری ضربه بزنید. در تنظیمات این دکمه را سفارشی یا جایگزین کنید\n\n"<annotation id="link">"تنظیمات"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"برای پنهان کردن موقتی دکمه، آن را به لبه ببرید"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"انتقال به بالا سمت راست"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"انتقال به بالا سمت چپ"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"تنظیمات"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> از <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ازطریق <xliff:g id="APP_LABEL">%3$s</xliff:g> پخش میشود"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> از <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"پخش"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"توقف موقت"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"آهنگ قبلی"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"آهنگ بعدی"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"پخش"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"باز کردن <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> از <xliff:g id="ARTIST_NAME">%2$s</xliff:g> را ازطریق <xliff:g id="APP_LABEL">%3$s</xliff:g> پخش کنید"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> را ازطریق <xliff:g id="APP_LABEL">%2$s</xliff:g> پخش کنید"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"واگرد"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"برای پخش در <xliff:g id="DEVICENAME">%1$s</xliff:g>، به دستگاه نزدیکتر شوید"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"درحال پخش در <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"غیرفعال، برنامه را بررسی کنید"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"پیدا نشد"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"کنترل دردسترس نیست"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"۱ دستگاه انتخاب شد"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> دستگاه انتخاب شد"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(اتصال قطع شد)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"متصل نشد. دوباره امتحان کنید."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"عوض نمیشود. برای تلاش مجدد ضربه بزنید."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"مرتبط کردن دستگاه جدید"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"شماره ساخت"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"شماره ساخت در بریدهدان کپی شد."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"مشاهده همه"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"برای تغییر شبکه، اترنت را قطع کنید"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"برای بهبود تجربه استفاده از دستگاه، برنامهها و سرویسها همچنان میتوانند در هر زمانی شبکههای Wi-Fi را اسکن کنند؛ حتی وقتی که Wi-Fi خاموش باشد. میتوانید این مورد را در تنظیمات اسکن کردن Wi‑Fi تغییر دهید. "<annotation id="link">"تغییر"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"خاموش کردن حالت هواپیما"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> میخواهد کاشی زیر را به «تنظیمات فوری» اضافه کند"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"افزودن کاشی"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"کاشی اضافه نشود"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"انتخاب کاربر"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"برنامههایی که در پسزمینه اجرا میشود"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"توقف"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/tiles_states_strings.xml b/packages/SystemUI/res/values-fa/tiles_states_strings.xml
index c3d6169..8c40e71 100644
--- a/packages/SystemUI/res/values-fa/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fa/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"خاموش"</item>
<item msgid="460891964396502657">"روشن"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"دردسترس نیست"</item>
+ <item msgid="5581384648880018330">"خاموش"</item>
+ <item msgid="8000850843692192257">"روشن"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index f0410e8..432d951 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Laitteita ei ole käytettävissä"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fiä ei ole yhdistetty"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Kirkkaus"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Käänteiset värit"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Käänteiset värit"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Lisäasetukset"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Käyttäjäasetukset"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Valmis"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Koko näytön suurennus"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Suurenna osa näytöstä"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Vaihda"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Esteettömyyspainike on korvannut esteettömyyseleen\n\n"<annotation id="link">"Katso asetukset"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Avaa esteettömyysominaisuudet napauttamalla. Yksilöi tai vaihda painike asetuksista.\n\n"<annotation id="link">"Avaa asetukset"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Piilota painike tilapäisesti siirtämällä se reunaan"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Siirrä vasempaan yläreunaan"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Siirrä oikeaan yläreunaan"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Asetukset"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> soittaa nyt tätä: <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>)"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Toista"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Keskeytä"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Edellinen kappale"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Seuraava kappale"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Toista"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Avaa <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Soita <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) sovelluksessa <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Soita <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="APP_LABEL">%2$s</xliff:g>)"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Kumoa"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Siirry lähemmäs, jotta <xliff:g id="DEVICENAME">%1$s</xliff:g> voi toistaa tämän"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> toistaa tämän"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Epäaktiivinen, tarkista sovellus"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ei löydy"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Ohjain ei ole käytettävissä"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 laite valittu"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> laitetta valittu"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(yhteys katkaistu)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ei yhteyttä. Yritä uudelleen."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Vaihtaminen ei onnistunut. Yritä uudelleen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Muodosta uusi laitepari"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Koontiversion numero"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Koontiversion numero kopioitu leikepöydälle"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Näytä kaikki"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Irrota Ethernet-johto, jos haluat vaihtaa verkkoa"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Laitteen käyttökokemuksen parantamiseksi sovellukset ja palvelut voivat hakea Wi-Fi-verkkoja myös silloin, kun Wi-Fi on pois päältä. Voit muuttaa asetusta Wi-Fi-haun asetuksissa. "<annotation id="link">"Muuta"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Laita lentokonetila pois päältä"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> haluaa lisätä seuraavan laatan pika-asetuksiin"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Lisää laatta"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Älä lisää laattaa"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Valitse käyttäjä"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Sovellukset jotka ovat käynnissä taustalla"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Lopeta"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/tiles_states_strings.xml b/packages/SystemUI/res/values-fi/tiles_states_strings.xml
index 7e7468d..cb9e07c 100644
--- a/packages/SystemUI/res/values-fi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fi/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Poissa päältä"</item>
<item msgid="460891964396502657">"Päällä"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Ei saatavilla"</item>
+ <item msgid="5581384648880018330">"Poissa päältä"</item>
+ <item msgid="8000850843692192257">"Päällä"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 1825a02..1123c40 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Aucun appareil à proximité"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Non connecté au Wi-Fi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminosité"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverser les couleurs"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversion des couleurs"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Plus de paramètres"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Paramètres utilisateur"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Terminé"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Agrandir la totalité de l\'écran"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Agrandir une partie de l\'écran"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Commutateur"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Le bouton d\'accessibilité a remplacé le geste d\'accessibilité\n\n"<annotation id="link">"Voir les paramètres"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Touchez pour ouvrir fonction. d\'access. Personnalisez ou remplacez bouton dans Param.\n\n"<annotation id="link">"Afficher param."</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Déplacez le bouton vers le bord pour le masquer temporairement"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Déplacer dans coin sup. gauche"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Déplacer dans coin sup. droit"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Paramètres"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> est en cours de lecteur à partir de <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Faire jouer"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Interrompre"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Chanson précédente"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Chanson suivante"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Faire jouer"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Ouvrez <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Lecture de <xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> à partir de <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Lecture de <xliff:g id="SONG_NAME">%1$s</xliff:g> à partir de <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Annuler"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Rapprochez-vous pour faire jouer le contenu sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifiez l\'appli"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"La commande n\'est pas accessible"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Un appareil sélectionné"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> appareil sélectionné"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(déconnecté)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Impossible de se connecter. Réessayez."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Changement impossible. Touchez pour réessayer."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un autre appareil"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de version"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Le numéro de version a été copié dans le presse-papiers."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pour changer de réseau, débranchez le câble Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Pour améliorer l\'expérience de l\'appareil, les applications et les services peuvent quand même rechercher des réseaux Wi-Fi en tout temps, même lorsque le Wi-Fi est désactivé. Vous pouvez modifier vos préférences dans les paramètres de recherche de réseaux Wi-Fi. "<annotation id="link">"Modifier"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Désactiver le mode Avion"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"L\'application <xliff:g id="APPNAME">%1$s</xliff:g> veut ajouter la tuile suivante au menu Paramètres rapides"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ajouter la tuile"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne pas ajouter tuile"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Sélect. utilisateur"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Applications exécutées en arrière-plan"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Arrêter"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
index bce1dde..eb38d94 100644
--- a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Désactivé"</item>
<item msgid="460891964396502657">"Activé"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Non disponible"</item>
+ <item msgid="5581384648880018330">"Désactivé"</item>
+ <item msgid="8000850843692192257">"Activé"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 8b6a490..74ad1bd 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Aucun appareil disponible."</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi non connecté"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminosité"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverser les couleurs"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversion des couleurs"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Plus de paramètres"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Paramètres utilisateur"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"OK"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Agrandir tout l\'écran"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Agrandir une partie de l\'écran"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Changer"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Le bouton Accessibilité a remplacé le geste d\'accessibilité\n\n"<annotation id="link">"Afficher les paramètres"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Appuyez pour ouvrir fonctionnalités d\'accessibilité. Personnalisez ou remplacez bouton dans paramètres.\n\n"<annotation id="link">"Voir paramètres"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Déplacer le bouton vers le bord pour le masquer temporairement"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Déplacer en haut à gauche"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Déplacer en haut à droite"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Paramètres"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> est en cours de lecture depuis <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> sur <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Lecture"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pause"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Titre précédent"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Titre suivant"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Lire"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Ouvre <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Mets <xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> depuis <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Mets <xliff:g id="SONG_NAME">%1$s</xliff:g> depuis <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Annuler"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Rapprochez-vous pour lire sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>…"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifier l\'appli"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Commande indisponible"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 appareil sélectionné"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> appareils sélectionnés"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(déconnecté)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Impossible de se connecter. Réessayez."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Impossible de changer. Appuyez pour réessayer."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un nouvel appareil"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numéro de build copié dans le presse-papiers."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pour changer de réseau, déconnectez l\'Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Pour améliorer l\'expérience sur l\'appareil, les applis et les services peuvent continuer de rechercher les réseaux Wi-Fi, même si le Wi-Fi est désactivé. Vous pouvez modifier cela dans les paramètres de recherche Wi-Fi. "<annotation id="link">"Modifier"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Désactiver le mode Avion"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> veut ajouter le bloc suivant aux Réglages rapides"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ajouter un bloc"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne pas ajouter bloc"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Choisir utilisateur"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Applis exécutées en arrière-plan"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Arrêter"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/tiles_states_strings.xml b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
index a2e2f73..3aefb1d 100644
--- a/packages/SystemUI/res/values-fr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Désactivé"</item>
<item msgid="460891964396502657">"Activé"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Indisponible"</item>
+ <item msgid="5581384648880018330">"Désactivé"</item>
+ <item msgid="8000850843692192257">"Activé"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 6c21265..121d434 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Non hai dispositivos dispoñibles"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"A wifi non está conectada"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillo"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverter cores"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversión da cor"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Máis opcións"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Configuración de usuario"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Feito"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar pantalla completa"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Amplía parte da pantalla"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Cambiar"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"O botón de accesibilidade substituíu o xesto de accesibilidade\n\n"<annotation id="link">"Ver configuración"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toca para abrir as funcións de accesibilidade. Cambia este botón en Configuración.\n\n"<annotation id="link">"Ver configuración"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Para ocultar temporalmente o botón, móveo ata o bordo"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover á parte super. esquerda"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover á parte superior dereita"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Configuración"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"Estase reproducindo <xliff:g id="SONG_NAME">%1$s</xliff:g>, de <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Reproducir"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pór en pausa"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Pista anterior"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Pista seguinte"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproducir"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abre <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Reproduce <xliff:g id="SONG_NAME">%1$s</xliff:g>, de <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reproduce <xliff:g id="SONG_NAME">%1$s</xliff:g> en <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Desfacer"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Achega o dispositivo para reproducir a música en: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Estase reproducindo o contido en: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Comproba a app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Non se atopou"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"O control non está dispoñible"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Seleccionouse 1 dispositivo"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Seleccionáronse <xliff:g id="COUNT">%1$d</xliff:g> dispositivos"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desconectado)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Non se puido establecer a conexión. Téntao de novo."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Non se puido realizar o cambio. Toca para tentalo de novo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo novo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Copiouse o número de compilación no portapapeis."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de rede, desconecta a Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para mellorar a experiencia que ofrece o dispositivo, as aplicacións e os servizos poden seguir buscando redes wifi en calquera momento, aínda que esta conexión estea desactivada. Podes cambiar esta opción na configuración da función Busca de redes wifi. "<annotation id="link">"Cambiar"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desactivar modo avión"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> solicita a túa aprobación para engadir o seguinte atallo a Configuración rápida"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Engadir atallo"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Non engadir atallo"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleccionar usuario"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplicacións que se están executando en segundo plano"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Deter"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/tiles_states_strings.xml b/packages/SystemUI/res/values-gl/tiles_states_strings.xml
index 7819fbb..90dcf7d 100644
--- a/packages/SystemUI/res/values-gl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-gl/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Desactivado"</item>
<item msgid="460891964396502657">"Activado"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Non dispoñible"</item>
+ <item msgid="5581384648880018330">"Desactivado"</item>
+ <item msgid="8000850843692192257">"Activado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index f1bd364..c397848 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"કોઈ ઉપકરણો ઉપલબ્ધ નથી"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"વાઇ-ફાઇ કનેક્ટ નથી"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"તેજ"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"રંગોને ઉલટાવો"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"વિપરીત રંગમાં બદલવું"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"વધુ સેટિંગ"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"વપરાશકર્તા સેટિંગ"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"થઈ ગયું"</string>
@@ -334,7 +334,7 @@
<string name="user_new_user_name" msgid="2019166282704195789">"નવો વપરાશકર્તા"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"અતિથિ દૂર કરીએ?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"આ સત્રમાંની તમામ ઍપ અને ડેટા કાઢી નાખવામાં આવશે."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"દૂર કરો"</string>
+ <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"કાઢી નાખો"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"ફરી સ્વાગત છે, અતિથિ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"શું તમે તમારું સત્ર ચાલુ રાખવા માંગો છો?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"શરૂ કરો"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"પૂર્ણ સ્ક્રીનને મોટી કરો"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"સ્ક્રીનનો કોઈ ભાગ મોટો કરો"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"સ્વિચ"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"ઍક્સેસિબિલિટી સંકેતને ઍક્સેસિબિલિટી બટન વડે બદલવામાં આવ્યા છે\n\n"<annotation id="link">"સેટિંગ જુઓ"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ઍક્સેસિબિલિટી સુવિધાઓ ખોલવા માટે ટૅપ કરો. સેટિંગમાં આ બટનને કસ્ટમાઇઝ કરો અથવા બદલો.\n\n"<annotation id="link">"સેટિંગ જુઓ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"તેને હંગામી રૂપે ખસેડવા માટે બટનને કિનારી પર ખસેડો"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ઉપર ડાબે ખસેડો"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ઉપર જમણે ખસેડો"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"સેટિંગ"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> પર <xliff:g id="ARTIST_NAME">%2$s</xliff:g>નું <xliff:g id="SONG_NAME">%1$s</xliff:g> ગીત ચાલી રહ્યું છે"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>માંથી <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"ચલાવો"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"થોભાવો"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"પહેલાનો ટ્રૅક"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"આગલો ટ્રૅક"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ચલાવો"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ખોલો"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> પર <xliff:g id="ARTIST_NAME">%2$s</xliff:g>નું <xliff:g id="SONG_NAME">%1$s</xliff:g> ગીત ચલાવો"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> પર <xliff:g id="SONG_NAME">%1$s</xliff:g> ગીત ચલાવો"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"છેલ્લો ફેરફાર રદ કરો"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> પર ચલાવવા માટે વધુ નજીક ખસેડો"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> પર ચલાવવામાં આવી રહ્યું છે"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"નિષ્ક્રિય, ઍપને ચેક કરો"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"મળ્યું નથી"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"નિયંત્રણ ઉપલબ્ધ નથી"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ડિવાઇસ પસંદ કર્યું"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> ડિવાઇસ પસંદ કર્યા"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ડિસ્કનેક્ટ કરેલું)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"કનેક્ટ કરી શકાયું નહીં. ફરી પ્રયાસ કરો."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"સ્વિચ કરી શકતા નથી. ફરી પ્રયાસ કરવા માટે ટૅપ કરો."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"નવા ડિવાઇસ સાથે જોડાણ કરો"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"બિલ્ડ નંબર"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"બિલ્ડ નંબર ક્લિપબૉર્ડ પર કૉપિ કર્યો."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"બધા જુઓ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"બીજા નેટવર્ક પર જવા માટે, ઇથરનેટ ડિસ્કનેક્ટ કરો"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"ડિવાઇસના અનુભવને બહેતર બનાવવા માટે, વાઇ-ફાઇ બંધ હોય ત્યારે પણ ઍપ અને સેવાઓ કોઈપણ સમયે વાઇ-ફાઇ નેટવર્ક સ્કૅન કરી શકે છે. તમે વાઇ-ફાઇ સ્કૅનિંગના સેટિંગમાં જઈને આને બદલી શકો છો. "<annotation id="link">"બદલો"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"એરપ્લેન મોડ બંધ કરો"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"ઝડપી સેટિંગમાં <xliff:g id="APPNAME">%1$s</xliff:g> નીચે જણાવેલા ટાઇલ ઉમેરવા માગે છે"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ટાઇલ ઉમેરો"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ટાઇલ ઉમેરશો નહીં"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"વપરાશકર્તા પસંદ કરો"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"બૅકગ્રાઉન્ડમાં ચાલતી ઍપ"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"રોકો"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/tiles_states_strings.xml b/packages/SystemUI/res/values-gu/tiles_states_strings.xml
index ddf18f6..e50f3cf 100644
--- a/packages/SystemUI/res/values-gu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-gu/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"બંધ છે"</item>
<item msgid="460891964396502657">"ચાલુ છે"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"અનુપલબ્ધ"</item>
+ <item msgid="5581384648880018330">"બંધ છે"</item>
+ <item msgid="8000850843692192257">"ચાલુ છે"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 72eb309..098b2a1 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"कोई डिवाइस उपलब्ध नहीं"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"वाई-फ़ाई कनेक्ट नहीं है"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"स्क्रीन की रोशनी"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"रंग उलटें"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"रंग बदलने की सुविधा"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"और सेटिंग"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"उपयोगकर्ता सेटिंग"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"हो गया"</string>
@@ -689,7 +689,7 @@
<string name="notification_channel_battery" msgid="9219995638046695106">"बैटरी"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"स्क्रीनशॉट"</string>
<string name="notification_channel_general" msgid="4384774889645929705">"सामान्य संदेश"</string>
- <string name="notification_channel_storage" msgid="2720725707628094977">"जगह"</string>
+ <string name="notification_channel_storage" msgid="2720725707628094977">"स्टोरेज"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"संकेत"</string>
<string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string>
<string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> चल रहा है"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"फ़ुल स्क्रीन को ज़ूम करें"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रीन के किसी हिस्से को ज़ूम करें"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"स्विच"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"सुलभता वाले हाथ के जेस्चर (हाव-भाव) को सुलभता बटन से बदल दिया गया है\n\n"<annotation id="link">"सेटिंग देखें"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"सुलभता सुविधाएं खोलने के लिए टैप करें. सेटिंग में, इस बटन को बदलें या अपने हिसाब से सेट करें.\n\n"<annotation id="link">"सेटिंग देखें"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"बटन को कुछ समय छिपाने के लिए, उसे किनारे पर ले जाएं"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"सबसे ऊपर बाईं ओर ले जाएं"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"सबसे ऊपर दाईं ओर ले जाएं"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिंग"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> पर, <xliff:g id="ARTIST_NAME">%2$s</xliff:g> का <xliff:g id="SONG_NAME">%1$s</xliff:g> चल रहा है"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> में से <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"चलाएं"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"रोकें"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"पिछला ट्रैक"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"अगला ट्रैक"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"चलाएं"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> खोलें"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> पर, <xliff:g id="ARTIST_NAME">%2$s</xliff:g> का <xliff:g id="SONG_NAME">%1$s</xliff:g> चलाएं"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> पर, <xliff:g id="SONG_NAME">%1$s</xliff:g> चलाएं"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"पहले जैसा करें"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> पर गाने चलाने के लिए उसके पास जाएं"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> पर चल रहा है"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"काम नहीं कर रहा, ऐप जांचें"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"कंट्रोल नहीं है"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"कंट्रोल मौजूद नहीं है"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"एक डिवाइस चुना गया"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> डिवाइस चुने गए"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(डिसकनेक्ट हो गया)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"कनेक्ट नहीं किया जा सका. फिर से कोशिश करें."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"स्विच नहीं किया जा सकता. फिर से कोशिश करने के लिए टैप करें."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नया डिवाइस जोड़ें"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर को क्लिपबोर्ड पर कॉपी किया गया."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"सभी देखें"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क बदलने के लिए, पहले ईथरनेट को डिसकनेक्ट करें"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"डिवाइस इस्तेमाल करने के अनुभव काे बेहतर बनाने के लिए, ऐप्लिकेशन और सेवाओं की मदद से, किसी भी समय वाई-फ़ाई नेटवर्क स्कैन किए जा सकते हैं. ऐसा वाई-फ़ाई बंद होने पर भी किया जा सकता है. वाई-फ़ाई स्कैनिंग की सेटिंग में जाकर, इसे बदला जा सकता है. "<annotation id="link">"बदलें"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"हवाई जहाज़ मोड बंद करें"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> इस टाइल को \'फटाफट सेटिंग\' में जोड़ने के लिए अनुमति चाहता है"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"टाइल जोड़ें"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"टाइल न जोड़ें"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"उपयोगकर्ता चुनें"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"बैकग्राउंड में चल रहे ऐप्लिकेशन"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"बंद करें"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/tiles_states_strings.xml b/packages/SystemUI/res/values-hi/tiles_states_strings.xml
index 08db65b..7698912 100644
--- a/packages/SystemUI/res/values-hi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hi/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"बंद है"</item>
<item msgid="460891964396502657">"चालू है"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"उपलब्ध नहीं है"</item>
+ <item msgid="5581384648880018330">"बंद है"</item>
+ <item msgid="8000850843692192257">"चालू है"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index e549d725..45fa359 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -251,7 +251,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nema dostupnih uređaja"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi mreža nije povezana"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Svjetlina"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Zamjena boja"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija boja"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Više postavki"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Korisničke postavke"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Gotovo"</string>
@@ -752,7 +752,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Povećajte cijeli zaslon"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Povećaj dio zaslona"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Prebacivanje"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Gumb za Pristupačnost zamijenio je pokret pristupačnosti\n\n"<annotation id="link">"Prikaz postavki"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dodirnite za otvaranje značajki pristupačnosti. Prilagodite ili zamijenite taj gumb u postavkama.\n\n"<annotation id="link">"Pregledajte postavke"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Pomaknite gumb do ruba da biste ga privremeno sakrili"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Premjesti u gornji lijevi kut"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Premjesti u gornji desni kut"</string>
@@ -804,10 +804,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Postavke"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g> reproducira se putem aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> od <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Reproduciraj"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pauziraj"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Prethodni zapis"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Sljedeći zapis"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reprodukcija"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otvori <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Pustite <xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g> putem aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Pustite <xliff:g id="SONG_NAME">%1$s</xliff:g> putem aplikacije <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Poništi"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Približite se radi reprodukcije na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Reproducira se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, provjerite aplik."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
@@ -822,7 +829,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Odabran je jedan uređaj"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Odabrano uređaja: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(nije povezano)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Povezivanje nije bilo moguće. Pokušajte ponovo."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nije prebačeno. Dodirnite da biste pokušali ponovo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uparite novi uređaj"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj međuverzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj međuverzije kopiran je u međuspremnik."</string>
@@ -887,8 +894,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da biste se prebacili na drugu mrežu, odspojite Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Da bi se poboljšao doživljaj uređaja, aplikacije i usluge i dalje mogu tražiti Wi-Fi mreže u bilo kojem trenutku, čak i kada je Wi-Fi isključen. To možete promijeniti u postavkama traženja Wi-Fija. "<annotation id="link">"Promijeni"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Isključi način rada u zrakoplovu"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> želi dodati sljedeću pločicu u Brze postavke"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj pločicu"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nemoj dodati pločicu"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Odabir korisnika"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikacije koje se izvode u pozadini"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zaustavi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/tiles_states_strings.xml b/packages/SystemUI/res/values-hr/tiles_states_strings.xml
index 5d9edf5..ae9ffb3 100644
--- a/packages/SystemUI/res/values-hr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hr/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Isključeno"</item>
<item msgid="460891964396502657">"Uključeno"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Nije dostupno"</item>
+ <item msgid="5581384648880018330">"Isključeno"</item>
+ <item msgid="8000850843692192257">"Uključeno"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 5bb6dd0..5539787 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nem áll rendelkezésre eszköz"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Nem kapcsolódik Wi‑Fi-hálózathoz"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Fényerő"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Színek invertálása"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Színek invertálása"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"További beállítások"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Felhasználói beállítások"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Kész"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"A teljes képernyő felnagyítása"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Képernyő bizonyos részének nagyítása"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Váltás"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"A kisegítő kézmozdulat helyébe a Kisegítő lehetőségek gomb lépett\n\n"<annotation id="link">"Beállítások megtekintése"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Koppintson a kisegítő lehetőségek megnyitásához. A gombot a Beállításokban módosíthatja.\n\n"<annotation id="link">"Beállítások"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"A gombot a szélre áthelyezve ideiglenesen elrejtheti"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Áthelyezés fel és balra"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Áthelyezés fel és jobbra"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Beállítások"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> <xliff:g id="SONG_NAME">%1$s</xliff:g> című száma hallható itt: <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>/<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Lejátszás"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Szünet"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Előző szám"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Következő szám"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Játék"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> megnyitása"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> <xliff:g id="SONG_NAME">%1$s</xliff:g> című számának lejátszása innen: <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> lejátszása innen: <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Visszavonás"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Menjen közelebb a következőn való lejátszáshoz: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Lejátszás folyamatban a(z) <xliff:g id="DEVICENAME">%1$s</xliff:g> eszközön"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktív, ellenőrizze az appot"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nem található"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Nem hozzáférhető vezérlő"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 eszköz kiválasztva"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> eszköz kiválasztva"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(leválasztva)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Sikertelen csatlakozás. Próbálja újra."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"A váltás nem sikerült. Próbálja újra."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Új eszköz párosítása"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildszám"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildszám a vágólapra másolva."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Megtekintés"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Hálózatváltáshoz válassza le az ethernetet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Az eszközhasználati élmény javítása érdekében az alkalmazások és a szolgáltatások továbbra is bármikor kereshetnek Wi-Fi-hálózatokat, még akkor is, ha a Wi-Fi ki van kapcsolva. A funkciót a „Wi-Fi scanning settings” (Wi-Fi-keresési beállítások) részben módosíthatja. "<annotation id="link">"Módosítás"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Repülős üzemmód kikapcsolása"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"A(z) <xliff:g id="APPNAME">%1$s</xliff:g> a következő mozaikot szeretné hozzáadni a Gyorsbeállításokhoz"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Mozaik hozzáadása"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne legyen hozzáadva"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Felhasználóválasztás"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Több alkalmazás is fut a háttérben"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Leállítás"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/tiles_states_strings.xml b/packages/SystemUI/res/values-hu/tiles_states_strings.xml
index dbfdf99..140f2db 100644
--- a/packages/SystemUI/res/values-hu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hu/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Ki"</item>
<item msgid="460891964396502657">"Be"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Nem áll rendelkezésre"</item>
+ <item msgid="5581384648880018330">"Ki"</item>
+ <item msgid="8000850843692192257">"Be"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 4b02f8b..7323cef 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Հասանելի սարքեր չկան"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi-ը միացված չէ"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Պայծառություն"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Շրջել գույները"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Գունաշրջում"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Հավելյալ կարգավորումներ"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Օգտատիրոջ կարգավորումներ"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Պատրաստ է"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Խոշորացնել ամբողջ էկրանը"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Խոշորացնել էկրանի որոշակի հատվածը"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Փոխել"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Հատուկ գործառույթների ժեստը փոխարինվել է կոճակով\n\n"<annotation id="link">"Բացել կարգավորումները"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Հատուկ գործառույթները բացելու համար հպեք։ Անհատականացրեք այս կոճակը կարգավորումներում։\n\n"<annotation id="link">"Կարգավորումներ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Կոճակը ժամանակավորապես թաքցնելու համար այն տեղափոխեք էկրանի եզր"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Տեղափոխել վերև՝ ձախ"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Տեղափոխել վերև՝ աջ"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Կարգավորումներ"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"Այժմ նվագարկվում է <xliff:g id="SONG_NAME">%1$s</xliff:g> երգը <xliff:g id="ARTIST_NAME">%2$s</xliff:g>-ի կատարմամբ <xliff:g id="APP_LABEL">%3$s</xliff:g> հավելվածից"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>՝ <xliff:g id="TOTAL_TIME">%2$s</xliff:g>-ից"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Նվագարկել"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Դադարեցնել"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Նախորդ կատարումը"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Հաջորդ կատարումը"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Նվագարկել"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Բացեք <xliff:g id="APP_LABEL">%1$s</xliff:g> հավելվածը"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Նվագարկել <xliff:g id="SONG_NAME">%1$s</xliff:g> երգը <xliff:g id="ARTIST_NAME">%2$s</xliff:g>-ի կատարմամբ <xliff:g id="APP_LABEL">%3$s</xliff:g> հավելվածից"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Նվագարկել <xliff:g id="SONG_NAME">%1$s</xliff:g> երգը <xliff:g id="APP_LABEL">%2$s</xliff:g> հավելվածից"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Հետարկել"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Ավելի մոտ եկեք՝ <xliff:g id="DEVICENAME">%1$s</xliff:g> սարքում նվագարկելու համար"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Նվագարկվում է <xliff:g id="DEVICENAME">%1$s</xliff:g> սարքում"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Ակտիվ չէ, ստուգեք հավելվածը"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Չի գտնվել"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Կառավարման տարրը հասանելի չէ"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Ընտրված է 1 սարք"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Ընտրված է <xliff:g id="COUNT">%1$d</xliff:g> սարք"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(անջատված է)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Չհաջողվեց միանալ։ Նորից փորձեք։"</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Սխալ առաջացավ։ Հպեք՝ կրկնելու համար։"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Նոր սարքի զուգակցում"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Կառուցման համարը"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Կառուցման համարը պատճենվեց սեղմատախտակին։"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Տեսնել բոլորը"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Մի ցանցից մյուսին անցնելու համար անջատեք Ethernet-ը"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Սարքի աշխատանքը բարելավելու համար հավելվածներն ու ծառայությունները կորոնեն Wi‑Fi ցանցեր, նույնիսկ երբ Wi‑Fi-ն անջատված է։ Այս պարամետրը կարող եք փոխել Wi‑Fi ցանցերի որոնման կարգավորումներում։ "<annotation id="link">"Փոխել"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Անջատել ավիառեժիմը"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> հավելվածն ուզում է ավելացնել հետևյալ սալիկը Արագ կարգավորումներում"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ավելացնել սալիկ"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Չավելացնել սալիկ"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Ընտրեք օգտատեր"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Ֆոնային ռեժիմում աշխատող հավելվածներ"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Դադարեցնել"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/tiles_states_strings.xml b/packages/SystemUI/res/values-hy/tiles_states_strings.xml
index 323d292..df69ce7 100644
--- a/packages/SystemUI/res/values-hy/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-hy/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Անջատված է"</item>
<item msgid="460891964396502657">"Միացված է"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Հասանելի չէ"</item>
+ <item msgid="5581384648880018330">"Անջատված է"</item>
+ <item msgid="8000850843692192257">"Միացված է"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 546f694..f659465 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Perangkat tak tersedia"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi‑Fi tidak terhubung"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Kecerahan"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inversi warna"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversi warna"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Setelan lainnya"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Setelan pengguna"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Selesai"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Memperbesar tampilan layar penuh"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Perbesar sebagian layar"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Alihkan"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Tombol aksesibilitas menggantikan gestur aksesibilitas\n\n"<annotation id="link">"Tampilkan setelan"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Ketuk untuk membuka fitur aksesibilitas. Sesuaikan atau ganti tombol ini di Setelan.\n\n"<annotation id="link">"Lihat setelan"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Pindahkan tombol ke tepi agar tersembunyi untuk sementara"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Pindahkan ke kiri atas"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Pindahkan ke kanan atas"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Setelan"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> oleh <xliff:g id="ARTIST_NAME">%2$s</xliff:g> sedang diputar dari <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> dari <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Putar"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Jeda"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Lagu sebelumnya"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Lagu berikutnya"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Putar"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Buka <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Putar <xliff:g id="SONG_NAME">%1$s</xliff:g> oleh <xliff:g id="ARTIST_NAME">%2$s</xliff:g> dari <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Putar <xliff:g id="SONG_NAME">%1$s</xliff:g> dari <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Urungkan"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Dekatkan untuk memutar di <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Diputar di <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Nonaktif, periksa aplikasi"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol tidak tersedia"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 perangkat dipilih"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> perangkat dipilih"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(terputus)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Tidak dapat terhubung. Coba lagi."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Tidak dapat beralih. Ketuk untuk mencoba lagi."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sambungkan perangkat baru"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nomor build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nomor versi disalin ke papan klip."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Untuk beralih jaringan, lepaskan kabel ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Agar pengalaman perangkat menjadi lebih baik, aplikasi dan layanan tetap dapat memindai jaringan Wi-Fi kapan saja, bahkan saat Wi-Fi nonaktif. Anda dapat mengubahnya di setelan pemindaian Wi-Fi. "<annotation id="link">"Ubah"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Menonaktifkan mode pesawat"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ingin menambahkan kartu berikut ke Setelan Cepat"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Tambahkan kartu"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Jangan tambah kartu"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Pilih pengguna"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikasi berjalan di latar belakang"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Berhenti"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/tiles_states_strings.xml b/packages/SystemUI/res/values-in/tiles_states_strings.xml
index 29d50b50..811294f 100644
--- a/packages/SystemUI/res/values-in/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-in/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Nonaktif"</item>
<item msgid="460891964396502657">"Aktif"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Tidak tersedia"</item>
+ <item msgid="5581384648880018330">"Nonaktif"</item>
+ <item msgid="8000850843692192257">"Aktif"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 31fe363..48068b1 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Engin tæki til staðar"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi ekki tengt"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Birtustig"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Umsnúa litum"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Umsnúningur lita"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Fleiri stillingar"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Notandastillingar"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Lokið"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Stækka allan skjáinn"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Stækka hluta skjásins"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Rofi"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Aðgengishnappur kom í stað aðgengisbendingar\n\n"<annotation id="link">"Skoða stillingar"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Ýttu til að opna aðgengiseiginleika. Sérsníddu eða skiptu hnappinum út í stillingum.\n\n"<annotation id="link">"Skoða stillingar"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Færðu hnappinn að brúninni til að fela hann tímabundið"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Færa efst til vinstri"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Færa efst til hægri"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Stillingar"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> með <xliff:g id="ARTIST_NAME">%2$s</xliff:g> er í spilun á <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> af <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Spila"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Gera hlé"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Fyrra lag"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Næsta lag"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Spila"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Opna <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Spila <xliff:g id="SONG_NAME">%1$s</xliff:g> með <xliff:g id="ARTIST_NAME">%2$s</xliff:g> í <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Spila <xliff:g id="SONG_NAME">%1$s</xliff:g> í <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Afturkalla"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Færðu nær til að spila í <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Spilast í <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Óvirkt, athugaðu forrit"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Fannst ekki"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Stýring er ekki tiltæk"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 tæki valið"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> tæki valin"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(aftengt)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Tenging mistókst. Reyndu aftur."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Ekki er hægt að skipta. Ýttu til að reyna aftur."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Para nýtt tæki"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Útgáfunúmer smíðar"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Útgáfunúmer smíðar afritað á klippiborð."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Sjá allt"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Aftengdu ethernet til að skipta um net"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Til að bæta tækjaupplifun geta forrit og þjónustur áfram leitað að WiFi-netum hvenær sem er, jafnvel þótt slökkt sé á WiFi. Hægt er að breyta þessu í stillingum WiFi-leitar. "<annotation id="link">"Breyta"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Slökkva á flugstillingu"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vill bæta eftirfarandi reit við flýtistillingar"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Bæta reit við"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ekki bæta reit við"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Velja notanda"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Forrit keyra í bakgrunni"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stöðva"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/tiles_states_strings.xml b/packages/SystemUI/res/values-is/tiles_states_strings.xml
index 4d9a097..dd704a7 100644
--- a/packages/SystemUI/res/values-is/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-is/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Slökkt"</item>
<item msgid="460891964396502657">"Kveikt"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Ekki í boði"</item>
+ <item msgid="5581384648880018330">"Slökkt"</item>
+ <item msgid="8000850843692192257">"Kveikt"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 3b54801..cd53a50 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nessun dispositivo disponibile"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Nessuna connessione Wi-Fi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminosità"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverti colori"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversione dei colori"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Altre impostazioni"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Impostazioni utente"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Fine"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ingrandisci l\'intero schermo"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ingrandisci parte dello schermo"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Opzione"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Il pulsante Accessibilità ha sostituito il gesto di accessibilità\n\n"<annotation id="link">"Visualizza le impostazioni"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tocca per aprire funzioni di accessibilità. Personalizza o sostituisci il pulsante in Impostazioni.\n\n"<annotation id="link">"Vedi impostazioni"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Sposta il pulsante fino al bordo per nasconderlo temporaneamente"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Sposta in alto a sinistra"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Sposta in alto a destra"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Impostazioni"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> di <xliff:g id="ARTIST_NAME">%2$s</xliff:g> è in riproduzione da <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> di <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Riproduci"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Metti in pausa"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Traccia precedente"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Traccia successiva"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Riproduci"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Apri <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Riproduci <xliff:g id="SONG_NAME">%1$s</xliff:g> di <xliff:g id="ARTIST_NAME">%2$s</xliff:g> da <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Riproduci <xliff:g id="SONG_NAME">%1$s</xliff:g> da <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Annulla"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Avvicinati per riprodurre su <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"In riproduzione su <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inattivo, controlla l\'app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Controllo non trovato"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Il controllo non è disponibile"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selezionato"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> dispositivi selezionati"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnesso)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Impossibile connettersi. Riprova."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Non puoi cambiare. Tocca per riprovare."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Accoppia nuovo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numero build copiato negli appunti."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Mostra tutte"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Per cambiare rete, scollega il cavo Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Per migliorare l\'esperienza con il dispositivo, le app e i servizi possono continuare a cercare reti Wi-Fi in qualsiasi momento, anche quando la connessione Wi-Fi non è attiva. Puoi modificare questa preferenza nelle impostazioni relative alla ricerca di reti Wi-Fi. "<annotation id="link">"Cambia"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Disattiva la modalità aereo"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vuole aggiungere il seguente riquadro alle Impostazioni rapide"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Aggiungi riquadro"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Non aggiungerlo"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleziona utente"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"App in esecuzione in background"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Interrompi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/tiles_states_strings.xml b/packages/SystemUI/res/values-it/tiles_states_strings.xml
index db0bbb4..1596998 100644
--- a/packages/SystemUI/res/values-it/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-it/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Off"</item>
<item msgid="460891964396502657">"On"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Non disponibile"</item>
+ <item msgid="5581384648880018330">"Off"</item>
+ <item msgid="8000850843692192257">"On"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 066f3c2..f36827c 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -252,7 +252,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"אין מכשירים זמינים"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"אין חיבור ל-Wi-Fi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"בהירות"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"היפוך צבעים"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"היפוך צבעים"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"הגדרות נוספות"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"הגדרות המשתמש"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"בוצע"</string>
@@ -757,7 +757,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"הגדלה של המסך המלא"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"הגדלת חלק מהמסך"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"מעבר"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"לחצן הנגישות החליף את תנועת הנגישות\n\n"<annotation id="link">"להצגת ההגדרות"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"מקישים כדי לפתוח את תכונות הנגישות. אפשר להחליף את הלחצן או להתאים אותו אישית בהגדרות.\n\n"<annotation id="link">"הצגת ההגדרות"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"כדי להסתיר זמנית את הלחצן, יש להזיז אותו לקצה"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"העברה לפינה השמאלית העליונה"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"העברה לפינה הימנית העליונה"</string>
@@ -810,10 +810,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"הגדרות"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> של <xliff:g id="ARTIST_NAME">%2$s</xliff:g> מופעל מ-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> מתוך <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"הפעלה"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"השהיה"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"הטראק הקודם"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"הטראק הבא"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"הפעלה"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"פתיחה של <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"הפעלת <xliff:g id="SONG_NAME">%1$s</xliff:g> של <xliff:g id="ARTIST_NAME">%2$s</xliff:g> מ-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"הפעלת <xliff:g id="SONG_NAME">%1$s</xliff:g> מ-<xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"ביטול"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"צריך להתקרב כדי להפעיל מוזיקה במכשיר <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"ההפעלה הועברה למכשיר <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"לא פעיל, יש לבדוק את האפליקציה"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"לא נמצא"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"הפקד לא זמין"</string>
@@ -828,7 +835,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"נבחר מכשיר אחד"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"נבחרו <xliff:g id="COUNT">%1$d</xliff:g> מכשירים"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(מנותק)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"לא ניתן היה להתחבר. יש לנסות שוב."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"לא ניתן להחליף. צריך להקיש כדי לנסות שוב."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"התאמה של מכשיר חדש"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"מספר Build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"מספר ה-Build הועתק ללוח."</string>
@@ -893,8 +900,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"הצגת הכול"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"כדי לעבור בין רשתות, צריך לנתק את האתרנט"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"כדי לשפר את חוויית השימוש במכשיר, אפליקציות ושירותים יוכלו לחפש רשתות Wi-Fi בכל שלב, גם כאשר ה-Wi-Fi כבוי. אפשר לשנות זאת בהגדרות של חיפוש נקודות Wi-Fi. "<annotation id="link">"שינוי"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"השבתה של מצב טיסה"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"האפליקציה <xliff:g id="APPNAME">%1$s</xliff:g> מבקשת להוסיף להגדרות המהירות את האריח הבא"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"הוספת אריח"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"אין להוסיף אריח"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"בחירת משתמש"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"אפליקציות שפועלות ברקע"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"עצירה"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/tiles_states_strings.xml b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
index 61735cf..28548bc 100644
--- a/packages/SystemUI/res/values-iw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-iw/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"כבוי"</item>
<item msgid="460891964396502657">"פועל"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"לא זמין"</item>
+ <item msgid="5581384648880018330">"כבוי"</item>
+ <item msgid="8000850843692192257">"פועל"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 4295e96..6fbcbb3 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"利用可能なデバイスがありません"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi 未接続"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"画面の明るさ"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"色を反転"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"色反転"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"詳細設定"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ユーザー設定"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"完了"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"画面全体を拡大します"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"画面の一部を拡大します"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"スイッチ"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"ユーザー補助ジェスチャーに代わって、ユーザー補助機能ボタンが導入されました\n\n"<annotation id="link">"設定を表示"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"タップしてユーザー補助機能を開きます。ボタンのカスタマイズや入れ替えを [設定] で行えます。\n\n"<annotation id="link">"設定を表示"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ボタンを一時的に非表示にするには、端に移動させてください"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"左上に移動"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"右上に移動"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g>(アーティスト名: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>)が <xliff:g id="APP_LABEL">%3$s</xliff:g> で再生中"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"再生"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"一時停止"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"前のトラック"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"次のトラック"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"再生"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> を開く"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g>(アーティスト名: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>)を <xliff:g id="APP_LABEL">%3$s</xliff:g> で再生"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> を <xliff:g id="APP_LABEL">%2$s</xliff:g> で再生"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"元に戻す"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g>で再生するにはもっと近づけてください"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g>で再生しています"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"無効: アプリをご確認ください"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"見つかりませんでした"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"コントロールを使用できません"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"選択したデバイス: 1 台"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"選択したデバイス: <xliff:g id="COUNT">%1$d</xliff:g> 台"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(接続解除済み)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"接続できませんでした。もう一度お試しください。"</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"切り替えられません。タップしてやり直してください。"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"新しいデバイスとのペア設定"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ビルド番号"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ビルド番号をクリップボードにコピーしました。"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"すべて表示"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ネットワークを変更するにはイーサネット接続を解除してください"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"デバイスの機能向上のため、アプリやサービスは、Wi-Fi が OFF の場合でも、いつでも Wi-Fi ネットワークをスキャンできます。この設定は Wi-Fi スキャンの設定で変更できます。"<annotation id="link">"変更"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"機内モードを OFF にする"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> が以下のタイルをクイック設定に追加しようとしています"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"タイルを追加"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"タイルを追加しない"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ユーザーの選択"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"バックグラウンドで実行中のアプリ"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/tiles_states_strings.xml b/packages/SystemUI/res/values-ja/tiles_states_strings.xml
index b65d2f8..7fc9c08c 100644
--- a/packages/SystemUI/res/values-ja/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ja/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"OFF"</item>
<item msgid="460891964396502657">"ON"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"使用不可"</item>
+ <item msgid="5581384648880018330">"OFF"</item>
+ <item msgid="8000850843692192257">"ON"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 9ab002a..08adb0f 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"მოწყობილობები მიუწვდომელია"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi არ არის დაკავშირებული"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"განათება"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ფერების შებრუნება"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ფერთა ინვერსია"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"დამატებითი პარამეტრები"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"მომხმარებლის პარამეტრები"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"დასრულდა"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"გაადიდეთ სრულ ეკრანზე"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ეკრანის ნაწილის გადიდება"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"გადართვა"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"მარტივი წვდომის ღილაკმა ჩაანაცვლა მარტივი წვდომის ჟესტი\n\n"<annotation id="link">"პარამეტრების ნახვა"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"შეეხეთ მარტივი წვდომის ფუნქციების გასახსნელად. მოარგეთ ან შეცვალეთ ეს ღილაკი პარამეტრებში.\n\n"<annotation id="link">"პარამეტრების ნახვა"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"გადაიტანეთ ღილაკი კიდეში, რათა დროებით დამალოთ ის"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ზევით და მარცხნივ გადატანა"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ზევით და მარჯვნივ გადატანა"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"პარამეტრები"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, უკრავს <xliff:g id="APP_LABEL">%3$s</xliff:g>-დან"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>-დან <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"დაკვრა"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"პაუზა"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"წინა ჩანაწერი"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"შემდეგი ჩანაწერი"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"დაკვრა"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"გახსენით <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"დაუკარით <xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, <xliff:g id="APP_LABEL">%3$s</xliff:g>-დან"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"დაუკარით <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%2$s</xliff:g>-დან"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"მოქმედების გაუქმება"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"მიიტანეტ უფრო ახლოს, რომ დაუკრათ <xliff:g id="DEVICENAME">%1$s</xliff:g>-ზე"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"მიმდინარეობს დაკვრა <xliff:g id="DEVICENAME">%1$s</xliff:g>-ზე"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"არააქტიურია, გადაამოწმეთ აპი"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ვერ მოიძებნა"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"კონტროლი მიუწვდომელია"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"არჩეულია 1 მოწყობილობა"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"არჩეულია <xliff:g id="COUNT">%1$d</xliff:g> მოწყობილობა"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(კავშირი გაწყვეტილია)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"დაკავშირება ვერ მოხერხდა. ცადეთ ხელახლა."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ვერ გადაირთო. შეეხეთ ხელახლა საცდელად."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ახალი მოწყობილობის დაწყვილება"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ანაწყობის ნომერი"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ანაწყობის ნომერი დაკოპირებულია გაცვლის ბუფერში."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"ყველას ნახვა"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ქსელების გადასართავად, გაწყვიტეთ Ethernet-თან კავშირი"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"მოწყობილობისგან მიღებული გამოცდილების გასაუმჯობესებლად, აპებსა და სერვისებს მაინც შეუძლია სკანირება Wi‑Fi ქსელების აღმოსაჩენად, ნებისმიერ დროს, მაშინაც კი, როცა Wi‑Fi გამორთულია. ამის შეცვლა Wi-Fi სკანირების პარამეტრებში შეგიძლიათ. "<annotation id="link">"შეცვლა"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"თვითმფრინავის რეჟიმის გამორთვა"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g>-ს სურს, დაამატოს შემდეგი მოზაიკა სწრაფ პარამეტრებში"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"მოზაიკის დამატება"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"არ დაემატოს მოზაიკა"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"მომხმარებლის არჩევა"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ფონურად მომუშავე აპები"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"შეწყვეტა"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/tiles_states_strings.xml b/packages/SystemUI/res/values-ka/tiles_states_strings.xml
index 4e621a0..40dfd39 100644
--- a/packages/SystemUI/res/values-ka/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ka/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"გამორთვა"</item>
<item msgid="460891964396502657">"ჩართვა"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"მიუწვდომელია"</item>
+ <item msgid="5581384648880018330">"გამორთულია"</item>
+ <item msgid="8000850843692192257">"ჩართულია"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 623d329..ffdde5b 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Құрылғылар қол жетімді емес"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi желісіне жалғанбаған"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Жарықтығы"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Түс инверсиясы"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Түс инверсиясы"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Қосымша параметрлер"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Пайдаланушы параметрлері"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Дайын"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Толық экранды ұлғайту"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Экранның бөлігін ұлғайту"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Ауысу"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Арнайы мүмкіндіктер қимылының орнына \"Арнайы мүмкіндіктер\" түймесі болады.\n\n"<annotation id="link">"Параметрлерді көру"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Арнайы мүмкіндікті ашу үшін түртіңіз. Түймені параметрден реттеңіз не ауыстырыңыз.\n\n"<annotation id="link">"Параметрді көру"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Түймені уақытша жасыру үшін оны шетке қарай жылжытыңыз."</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Жоғарғы сол жаққа жылжыту"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Жоғарғы оң жаққа жылжыту"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Параметрлер"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> қолданбасында <xliff:g id="ARTIST_NAME">%2$s</xliff:g> орындайтын \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" әні ойнатылуда."</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>/<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Ойнату"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Кідірту"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Алдыңғы трек"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Келесі трек"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Ойнату"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> қолданбасын ашу"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> қолданбасында <xliff:g id="ARTIST_NAME">%2$s</xliff:g> орындайтын \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" әнін ойнату"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> қолданбасында \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" әнін ойнату"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Қайтару"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысында музыка ойнату үшін оған жақындаңыз."</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысында ойнатылуда."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Өшірулі. Қолданба тексеріңіз."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Табылмады"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Басқару виджеті қолжетімсіз"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 құрылғы таңдалды."</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> құрылғы таңдалды."</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ажыратулы)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Қосылмады. Қайта қосылып көріңіз."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Ауысу мүмкін емес. Әрекетті қайталау үшін түртіңіз."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңа құрылғымен жұптау"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Құрама нөмірі"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Құрама нөмірі буферге көшірілді."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Барлығын көру"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Желілерді ауыстыру үшін ethernet кабелін ажыратыңыз."</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Құрылғы жұмысын жақсарту үшін қолданбалар мен қызметтер Wi-Fi байланысы өшірулі кезде де Wi-Fi желілерін іздейді. Оны Wi-Fi іздеу параметрлерінен өзгерте аласыз. "<annotation id="link">"Өзгерту"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Ұшақ режимін өшіру"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> Жылдам параметрлерге келесі бөлшекті қосқысы келеді."</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Бөлшек қосу"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Бөлшек қоспау"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Пайдаланушыны таңдау"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Фондық режимде жұмыс істеп тұрған қолданбалар"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Тоқтату"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/tiles_states_strings.xml b/packages/SystemUI/res/values-kk/tiles_states_strings.xml
index d3ad572..3e9aefa 100644
--- a/packages/SystemUI/res/values-kk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-kk/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Өшірулі"</item>
<item msgid="460891964396502657">"Қосулы"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Қолжетімсіз"</item>
+ <item msgid="5581384648880018330">"Өшірулі"</item>
+ <item msgid="8000850843692192257">"Қосулы"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 75f5a0a..02f7550 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -234,7 +234,7 @@
<string name="quick_settings_location_label" msgid="2621868789013389163">"ទីតាំង"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"ការចូលប្រើកាមេរ៉ា"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"ការចូលប្រើមីក្រូហ្វូន"</string>
- <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"អាចប្រើបាន"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"អាចចូលប្រើបាន"</string>
<string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"បានទប់ស្កាត់"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"ឧបករណ៍មេឌៀ"</string>
<string name="quick_settings_user_title" msgid="8673045967216204537">"អ្នកប្រើ"</string>
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"មិនមានឧបករណ៍ដែលអាចប្រើបាន"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"មិនមានការតភ្ជាប់ Wi-Fi ទេ"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ពន្លឺ"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ដាក់បញ្ច្រាសពណ៌"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ការបញ្ច្រាសពណ៌"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"ការកំណត់ច្រើនទៀត"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ការកំណត់អ្នកប្រើប្រាស់"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"រួចរាល់"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ពង្រីកពេញអេក្រង់"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ពង្រីកផ្នែកនៃអេក្រង់"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ប៊ូតុងបិទបើក"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"ប៊ូតុងភាពងាយស្រួលបានជំនួសចលនាភាពងាយស្រួល\n\n"<annotation id="link">"មើលការកំណត់"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ចុចដើម្បីបើកមុខងារភាពងាយស្រួល។ ប្ដូរ ឬប្ដូរប៊ូតុងនេះតាមបំណងនៅក្នុងការកំណត់។\n\n"<annotation id="link">"មើលការកំណត់"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ផ្លាស់ទីប៊ូតុងទៅគែម ដើម្បីលាក់វាជាបណ្ដោះអាសន្ន"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ផ្លាស់ទីទៅខាងលើផ្នែកខាងឆ្វេង"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ផ្លាស់ទីទៅខាងលើផ្នែកខាងស្ដាំ"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"ការកំណត់"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ច្រៀងដោយ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> កំពុងចាក់ពី <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> នៃ <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"ចាក់"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"ផ្អាក"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"ចម្រៀងមុន"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"ចម្រៀងបន្ទាប់"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ចាក់"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"បើក <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"ចាក់ <xliff:g id="SONG_NAME">%1$s</xliff:g> ច្រៀងដោយ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ពី <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"ចាក់ <xliff:g id="SONG_NAME">%1$s</xliff:g> ពី <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"ត្រឡប់វិញ"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"រំកិលឱ្យកាន់តែជិត ដើម្បីចាក់នៅលើ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"កំពុងចាក់នៅលើ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"អសកម្ម ពិនិត្យមើលកម្មវិធី"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"រកមិនឃើញទេ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"មិនអាចគ្រប់គ្រងបានទេ"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"បានជ្រើសរើសឧបករណ៍ 1"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"បានជ្រើសរើសឧបករណ៍ <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(បានដាច់)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"មិនអាចភ្ជាប់បានទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"មិនអាចប្ដូរបានទេ។ សូមចុចដើម្បីព្យាយាមម្ដងទៀត។"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ផ្គូផ្គងឧបករណ៍ថ្មី"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"លេខកំណែបង្កើត"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"បានចម្លងលេខកំណែបង្កើតទៅឃ្លីបបត។"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"មើលទាំងអស់"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ដើម្បីប្ដូរបណ្ដាញ សូមផ្ដាច់អ៊ីសឺរណិត"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"ដើម្បីធ្វើឱ្យបទពិសោធន៍ប្រើប្រាស់ឧបករណ៍ប្រសើរឡើង កម្មវិធី និងសេវាកម្មនៅតែអាចស្កេនរកបណ្ដាញ Wi‑Fi បានគ្រប់ពេល ទោះបីជានៅពេលដែលបិទ Wi‑Fi ក៏ដោយ។ អ្នកអាចប្ដូរវាបាននៅក្នុងការកំណត់ការស្កេន Wi‑Fi។ "<annotation id="link">"ប្ដូរ"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"បិទមុខងារពេលជិះយន្តហោះ"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ចង់បញ្ចូលប្រអប់ខាងក្រោមទៅក្នុងការកំណត់រហ័ស"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"បញ្ចូលប្រអប់"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"កុំបញ្ចូលប្រអប់"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ជ្រើសរើសអ្នកប្រើប្រាស់"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"កម្មវិធីដែលកំពុងដំណើរការនៅផ្ទៃខាងក្រោយ"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ឈប់"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/tiles_states_strings.xml b/packages/SystemUI/res/values-km/tiles_states_strings.xml
index f67aafb..32a6e22 100644
--- a/packages/SystemUI/res/values-km/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-km/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"បិទ"</item>
<item msgid="460891964396502657">"បើក"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"មិនមានទេ"</item>
+ <item msgid="5581384648880018330">"បិទ"</item>
+ <item msgid="8000850843692192257">"បើក"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index ce594f7..b29b0bb 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ಯಾವುದೇ ಸಾಧನಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ವೈ-ಫೈ ಸಂಪರ್ಕಗೊಂಡಿಲ್ಲ"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ಪ್ರಕಾಶಮಾನ"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ಬಣ್ಣ ಇನ್ವರ್ಟ್ ಮಾಡಿ"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ಕಲರ್ ಇನ್ವರ್ಶನ್"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ಬಳಕೆದಾರರ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"ಮುಗಿದಿದೆ"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ಪೂರ್ಣ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಹಿಗ್ಗಿಸಿ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ಸ್ಕ್ರೀನ್ನ ಅರ್ಧಭಾಗವನ್ನು ಝೂಮ್ ಮಾಡಿ"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ಸ್ವಿಚ್"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"ಪ್ರವೇಶಿಸುವಿಕೆ ಬಟನ್, ಪ್ರವೇಶಿಸುವಿಕೆ ಗೆಸ್ಚರ್ ಅನ್ನು ಬದಲಾಯಿಸಿದೆ\n\n"<annotation id="link">"ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ತೆರೆಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಈ ಬಟನ್ ಅನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ ಅಥವಾ ಬದಲಾಯಿಸಿ.\n\n"<annotation id="link">"ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ಅದನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ಮರೆಮಾಡಲು ಅಂಚಿಗೆ ಬಟನ್ ಸರಿಸಿ"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ಎಡ ಮೇಲ್ಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ಬಲ ಮೇಲ್ಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ಅವರ <xliff:g id="SONG_NAME">%1$s</xliff:g> ಹಾಡನ್ನು <xliff:g id="APP_LABEL">%3$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> ರಲ್ಲಿ <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"ಪ್ಲೇ ಮಾಡಿ"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"ವಿರಾಮಗೊಳಿಸಿ"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"ಹಿಂದಿನ ಟ್ರ್ಯಾಕ್"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"ಮುಂದಿನ ಟ್ರ್ಯಾಕ್"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ಪ್ಲೇ ಮಾಡಿ"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ಅನ್ನು ತೆರೆಯಿರಿ"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ಅವರ <xliff:g id="SONG_NAME">%1$s</xliff:g> ಹಾಡನ್ನು <xliff:g id="APP_LABEL">%3$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಿ"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ಹಾಡನ್ನು <xliff:g id="APP_LABEL">%2$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಿ"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"ರದ್ದುಗೊಳಿಸಿ"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು ಅದರ ಹತ್ತಿರಕ್ಕೆ ಸರಿಯಿರಿ"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಆಗುತ್ತಿದೆ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ನಿಷ್ಕ್ರಿಯ, ಆ್ಯಪ್ ಪರಿಶೀಲಿಸಿ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ಕಂಡುಬಂದಿಲ್ಲ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ನಿಯಂತ್ರಣ ಲಭ್ಯವಿಲ್ಲ"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ಸಾಧನವನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> ಸಾಧನಗಳನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ಡಿಸ್ಕನೆಕ್ಟ್ ಆಗಿದೆ)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ಬದಲಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ಹೊಸ ಸಾಧನವನ್ನು ಜೋಡಿಸಿ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆಯನ್ನು ಕ್ಲಿಪ್ಬೋರ್ಡ್ನಲ್ಲಿ ನಕಲಿಸಲಾಗಿದೆ."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"ಎಲ್ಲವನ್ನೂ ನೋಡಿ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ನೆಟ್ವರ್ಕ್ಗಳನ್ನು ಬದಲಿಸಲು, ಇಥರ್ನೆಟ್ ಅನ್ನು ಡಿಸ್ಕನೆಕ್ಟ್ ಮಾಡಿ"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"ವೈ-ಫೈ ಆಫ್ ಇದ್ದಾಗಲೂ ಸಹ, ಸಾಧನದ ಅನುಭವವನ್ನು ಸುಧಾರಿಸಲು, ಆ್ಯಪ್ಗಳು ಮತ್ತು ಸೇವೆಗಳು ಯಾವಾಗ ಬೇಕಾದರೂ ಸಹ ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ಗಳಿಗಾಗಿ ಸ್ಕ್ಯಾನ್ ಮಾಡಬಹುದು. ನೀವು ಇದನ್ನು ವೈ-ಫೈ ಸ್ಕ್ಯಾನಿಂಗ್ ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಬದಲಾಯಿಸಬಹುದು. "<annotation id="link">"ಬದಲಿಸಿ"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ಏರ್ಪ್ಲೇನ್ ಮೋಡ್ ಆಫ್ ಮಾಡಿ"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ಈ ಕೆಳಗಿನ ಟೈಲ್ ಅನ್ನು ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಸೇರಿಸಲು ಬಯಸುತ್ತದೆ"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ಟೈಲ್ ಅನ್ನು ಸೇರಿಸಿ"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ಟೈಲ್ ಅನ್ನು ಸೇರಿಸಬೇಡಿ"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ಬಳಕೆದಾರ ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ಹಿನ್ನೆಲೆಯಲ್ಲಿ ರನ್ ಆಗುತ್ತಿರುವ ಆ್ಯಪ್ಗಳು"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ನಿಲ್ಲಿಸಿ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/tiles_states_strings.xml b/packages/SystemUI/res/values-kn/tiles_states_strings.xml
index 26ec958..c13e198 100644
--- a/packages/SystemUI/res/values-kn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-kn/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"ಆಫ್ ಮಾಡಿ"</item>
<item msgid="460891964396502657">"ಆನ್ ಮಾಡಿ"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"ಲಭ್ಯವಿಲ್ಲ"</item>
+ <item msgid="5581384648880018330">"ಆಫ್ ಆಗಿದೆ"</item>
+ <item msgid="8000850843692192257">"ಆನ್ ಆಗಿದೆ"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index e742659..b5f2ad3 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"사용 가능한 기기가 없습니다."</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi가 연결되지 않음"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"밝기"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"색상 반전"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"색상 반전"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"설정 더보기"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"사용자 설정"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"완료"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"전체 화면 확대"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"화면 일부 확대"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"전환"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"접근성 동작이 접근성 버튼으로 대체되었습니다.\n\n"<annotation id="link">"설정 보기"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"접근성 기능을 열려면 탭하세요. 설정에서 이 버튼을 맞춤설정하거나 교체할 수 있습니다.\n\n"<annotation id="link">"설정 보기"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"버튼을 가장자리로 옮겨서 일시적으로 숨기세요."</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"왼쪽 상단으로 이동"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"오른쪽 상단으로 이동"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"설정"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g>에서 <xliff:g id="ARTIST_NAME">%2$s</xliff:g>의 <xliff:g id="SONG_NAME">%1$s</xliff:g> 재생 중"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"재생"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"일시중지"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"이전 트랙"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"다음 트랙"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"재생"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> 열기"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g>에서 <xliff:g id="ARTIST_NAME">%2$s</xliff:g>의 <xliff:g id="SONG_NAME">%1$s</xliff:g> 재생"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g>에서 <xliff:g id="SONG_NAME">%1$s</xliff:g> 재생"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"실행취소"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g>에서 재생하려면 기기를 더 가까이로 옮기세요."</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g>에서 재생 중"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"비활성. 앱을 확인하세요."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"찾을 수 없음"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"컨트롤을 사용할 수 없음"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"기기 1대 선택됨"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"기기 <xliff:g id="COUNT">%1$d</xliff:g>대 선택됨"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(연결 끊김)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"연결할 수 없습니다. 다시 시도하세요."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"전환할 수 없습니다. 다시 시도하려면 탭하세요."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"새 기기와 페어링"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"빌드 번호"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"빌드 번호가 클립보드에 복사되었습니다."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"모두 보기"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"네트워크를 전환하려면 이더넷을 연결 해제하세요."</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"기기 환경을 개선하기 위해 Wi‑Fi가 꺼져 있을 때도 앱과 서비스에서 Wi‑Fi 네트워크를 검색할 수 있습니다. 이 설정은 Wi‑Fi 검색 설정에서 변경할 수 있습니다. "<annotation id="link">"변경"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"비행기 모드 사용 중지"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g>에서 빠른 설정에 다음 타일을 추가하려고 합니다."</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"타일 추가"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"타일 추가 안함"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"사용자 선택"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"백그라운드에서 실행 중인 앱"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"중지"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/tiles_states_strings.xml b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
index 0c22971..28d45cf 100644
--- a/packages/SystemUI/res/values-ko/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ko/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"꺼짐"</item>
<item msgid="460891964396502657">"켜짐"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"사용 불가"</item>
+ <item msgid="5581384648880018330">"사용 중지됨"</item>
+ <item msgid="8000850843692192257">"사용 설정됨"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index f6fe747..2d2f1cf 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Жеткиликтүү түзмөктөр жок"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi туташкан жок"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Жарыктыгы"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Түстөрдү инверсиялоо"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Түстү инверсиялоо"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Дагы жөндөөлөр"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Колдонуучунун жөндөөлөрү"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Бүттү"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Толук экранда ачуу"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Экрандын бир бөлүгүн чоңойтуу"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Которулуу"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Атайын мүмкүнчүлүктөр жаңсоосунун ордуна атайын мүмкүнчүлүктөр баскычы колдонулмакчы\n\n"<annotation id="link">"Жөндөөлөрдү көрүү"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Атайын мүмкүнчүлүктөрдү ачуу үчүн басыңыз. Бул баскычты Жөндөөлөрдөн өзгөртүңүз.\n\n"<annotation id="link">"Жөндөөлөрдү көрүү"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Баскычты убактылуу жашыра туруу үчүн экрандын четине жылдырыңыз"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Жогорку сол жакка жылдыруу"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Жогорку оң жакка жылдырыңыз"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Жөндөөлөр"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ыры (аткаруучу: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) <xliff:g id="APP_LABEL">%3$s</xliff:g> колдонмосунан ойнотулуп жатат"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> ичинен <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Ойнотуу"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Тындыруу"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Мурунку трек"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Кийинки трек"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Ойнотуу"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> колдонмосун ачуу"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ырын (аткаруучу: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) <xliff:g id="APP_LABEL">%3$s</xliff:g> колдонмосунан ойнотуу"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ырын <xliff:g id="APP_LABEL">%2$s</xliff:g> колдонмосунан ойнотуу"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Кайтаруу"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> түзмөгүндө ойнотуу үчүн жакыныраак жылдырыңыз"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> аркылуу ойнотулууда"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Жигерсиз. Колдонмону текшериңиз"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Табылган жок"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Башкара албайсыз"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 түзмөк тандалды"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> түзмөк тандалды"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ажыратылды)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Байланышпай койду. Кайталоо."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Которулбай жатат. Кайталоо үчүн басыңыз."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңы түзмөктү жупташтыруу"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Курама номери"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Курама номери алмашуу буферине көчүрүлдү."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Баарын көрүү"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Башка тармактарга которулуу үчүн Ethernet кабелин ажыратыңыз"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Түзмөктүн колдонулушун жакшыртуу үчүн колдонмолор менен кызматтар Wi‑Fi өчүп турса да зымсыз тармактарды издей беришет. Аны Wi-Fi тармактарын издөө жөндөөлөрүнөн өзгөртө аласыз. "<annotation id="link">"Өзгөртүү"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Учак режимин өчүрүү"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> төмөнкү ыкчам баскычты Ыкчам жөндөөлөргө кошкону жатат"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ыкчам баскыч кошуу"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ыкчам баскыч кошулбасын"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Колдонуучуну тандоо"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Фондо иштеп жаткан колдонмолор"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Токтотуу"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/tiles_states_strings.xml b/packages/SystemUI/res/values-ky/tiles_states_strings.xml
index ae6520e..139d784 100644
--- a/packages/SystemUI/res/values-ky/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ky/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Өчүк"</item>
<item msgid="460891964396502657">"Күйүк"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Жеткиликсиз"</item>
+ <item msgid="5581384648880018330">"Өчүк"</item>
+ <item msgid="8000850843692192257">"Күйүк"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index c401823..6903250 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ບໍ່ມີອຸປະກອນທີ່ສາມາດໃຊ້ໄດ້"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ບໍ່ໄດ້ເຊື່ອມຕໍ່ Wi-Fi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ຄວາມແຈ້ງ"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ສະຫຼັບສີ"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ການປີ້ນສີ"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"ການຕັ້ງຄ່າເພີ່ມເຕີມ"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ຕັ້ງຄ່າຜູ້ໃຊ້"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"ແລ້ວໆ"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ຂະຫຍາຍເຕັມຈໍ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ຂະຫຍາຍບາງສ່ວນຂອງໜ້າຈໍ"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ສະຫຼັບ"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"ປຸ່ມການຊ່ວຍເຂົ້າເຖິງຖືກແທນທີ່ທ່າທາງຊ່ວຍເຂົ້າເຖິງແລ້ວ\n\n"<annotation id="link">"ເບິ່ງການຕັ້ງຄ່າ"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ແຕະເພື່ອເປີດຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ. ປັບແຕ່ງ ຫຼື ປ່ຽນປຸ່ມນີ້ໃນການຕັ້ງຄ່າ.\n\n"<annotation id="link">"ເບິ່ງການຕັ້ງຄ່າ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ຍ້າຍປຸ່ມໄປໃສ່ຂອບເພື່ອເຊື່ອງມັນຊົ່ວຄາວ"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ຍ້າຍຊ້າຍເທິງ"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ຍ້າຍຂວາເທິງ"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"ການຕັ້ງຄ່າ"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ໂດຍ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ກຳລັງຫຼິ້ນຈາກ <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> ຈາກ <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"ຫຼິ້ນ"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"ຢຸດຊົ່ວຄາວ"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"ເພງກ່ອນໜ້າ"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"ເພງຕໍ່ໄປ"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ຫຼິ້ນ"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"ເປີດ <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"ຫຼິ້ນ <xliff:g id="SONG_NAME">%1$s</xliff:g> ໂດຍ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ຈາກ <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"ຫຼິ້ນ <xliff:g id="SONG_NAME">%1$s</xliff:g> ຈາກ <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"ຍົກເລີກ"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"ຍ້າຍໄປໃກ້ຂຶ້ນເພື່ອຫຼິ້ນຢູ່ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"ກຳລັງຫຼິ້ນຢູ່ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ບໍ່ເຮັດວຽກ, ກະລຸນາກວດສອບແອັບ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ບໍ່ພົບ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ບໍ່ສາມາດໃຊ້ການຄວບຄຸມໄດ້"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"ເລືອກ 1 ອຸປະກອນແລ້ວ"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"ເລືອກ <xliff:g id="COUNT">%1$d</xliff:g> ອຸປະກອນແລ້ວ"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ຕັດການເຊື່ອມຕໍ່ແລ້ວ)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້. ລອງໃໝ່."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ບໍ່ສາມາດສະຫຼັບໄດ້. ແຕະເພື່ອລອງໃໝ່."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ຈັບຄູ່ອຸປະກອນໃໝ່"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ໝາຍເລກສ້າງ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ສຳເນົາໝາຍເລກສ້າງໄປໃສ່ຄລິບບອດແລ້ວ."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"ເບິ່ງທັງໝົດ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ເພື່ອສະຫຼັບເຄືອຂ່າຍ, ໃຫ້ຕັດການເຊື່ອມຕໍ່ອີເທີເນັດກ່ອນ"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"ເພື່ອປັບປຸງປະສົບການອຸປະກອນ, ແອັບ ແລະ ບໍລິການຍັງຄົງສາມາດສະແກນຫາເຄືອຂ່າຍ Wi‑Fi ຕອນໃດກໍໄດ້, ເຖິງແມ່ນວ່າຈະປິດ Wi‑Fi ໄວ້ກໍຕາມ. ທ່ານສາມາດປ່ຽນສິ່ງນີ້ໄດ້ໃນການຕັ້ງຄ່າການສະແກນ Wi‑Fi. "<annotation id="link">"ປ່ຽນ"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ປິດໂໝດຢູ່ໃນຍົນ"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ຕ້ອງການເພີ່ມແຜ່ນຕໍ່ໄປນີ້ໃສ່ການຕັ້ງຄ່າດ່ວນ"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ເພີ່ມແຜ່ນ"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ຢ່າເພີ່ມແຜ່ນ"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ເລືອກຜູ້ໃຊ້"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ແອັບທີ່ກຳລັງເອີ້ນໃຊ້ໃນພື້ນຫຼັງ"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ຢຸດ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo/tiles_states_strings.xml b/packages/SystemUI/res/values-lo/tiles_states_strings.xml
index e818a09..74c0f24 100644
--- a/packages/SystemUI/res/values-lo/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lo/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"ປິດ"</item>
<item msgid="460891964396502657">"ເປີດ"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"ບໍ່ສາມາດໃຊ້ໄດ້"</item>
+ <item msgid="5581384648880018330">"ປິດ"</item>
+ <item msgid="8000850843692192257">"ເປີດ"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 2670ce4..b8c8a4a 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -252,7 +252,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nėra pasiekiamų įrenginių"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"„Wi-Fi“ neprijungtas"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Šviesumas"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Pakeisti spalvas"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Spalvų inversija"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Daugiau nustatymų"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Naudotojo nustatymai"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Atlikta"</string>
@@ -757,7 +757,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Viso ekrano didinimas"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Didinti ekrano dalį"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Perjungti"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Pritaikomumo gestas pakeistas pritaikomumo mygtuku\n\n"<annotation id="link">"Žr. nustatymus"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Palietę atidarykite pritaikymo neįgaliesiems funkcijas. Tinkinkite arba pakeiskite šį mygtuką nustatymuose.\n\n"<annotation id="link">"Žr. nustatymus"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Perkelkite mygtuką prie krašto, kad laikinai jį paslėptumėte"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Perkelti į viršų kairėje"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Perkelti į viršų dešinėje"</string>
@@ -810,10 +810,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Nustatymai"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> – „<xliff:g id="SONG_NAME">%1$s</xliff:g>“ leidžiama iš „<xliff:g id="APP_LABEL">%3$s</xliff:g>“"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> iš <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Paleisti"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pristabdyti"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Ankstesnis takelis"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Kitas takelis"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Leisti"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Atidaryti „<xliff:g id="APP_LABEL">%1$s</xliff:g>“"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Leisti <xliff:g id="ARTIST_NAME">%2$s</xliff:g> – „<xliff:g id="SONG_NAME">%1$s</xliff:g>“ iš „<xliff:g id="APP_LABEL">%3$s</xliff:g>“"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Leisti „<xliff:g id="SONG_NAME">%1$s</xliff:g>“ iš „<xliff:g id="APP_LABEL">%2$s</xliff:g>“"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Anuliuoti"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Prieikite arčiau, kad galėtumėte leisti įrenginyje „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Leidžiama įrenginyje „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktyvu, patikrinkite progr."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nerasta"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Valdiklis nepasiekiamas"</string>
@@ -828,7 +835,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Pasirinktas 1 įrenginys"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Pasirinkta įrenginių: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(atjungta)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nepavyko prijungti. Bandykite dar kartą."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nepavyko perjungti. Bandykite vėl palietę."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Naujo įrenginio susiejimas"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijos numeris"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versijos numeris nukopijuotas į iškarpinę."</string>
@@ -893,8 +900,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Žiūrėti viską"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Norėdami perjungti tinklus, atjunkite eternetą"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Kad pagerintų įrenginio funkcijas, programos ir paslaugos vis tiek gali bet kada nuskaityti ieškodamos „Wi‑Fi“ tinklų, net jei „Wi‑Fi“ išjungtas. Tai galite pakeisti „Wi-Fi“ nuskaitymo nustatymuose. "<annotation id="link">"Pakeisti"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Išjungti lėktuvo režimą"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"„<xliff:g id="APPNAME">%1$s</xliff:g>“ nori prie sparčiųjų nustatymų pridėti toliau pateiktą išklotinės elementą"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Pridėti išklotinės elementą"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nepridėti išklotinės elemento"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Naudotojo pasirinkimas"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Fone veikiančios programos"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Sustabdyti"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/tiles_states_strings.xml b/packages/SystemUI/res/values-lt/tiles_states_strings.xml
index 28d4a73..08e0e6d 100644
--- a/packages/SystemUI/res/values-lt/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lt/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Išjungta"</item>
<item msgid="460891964396502657">"Įjungta"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Nepasiekiama"</item>
+ <item msgid="5581384648880018330">"Išjungta"</item>
+ <item msgid="8000850843692192257">"Įjungta"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 16e2eef..48715802 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -251,7 +251,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nav pieejamu ierīču."</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Nav izveidots savienojums ar Wi-Fi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Spilgtums"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invertēt krāsas"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Krāsu inversija"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Vairāk iestatījumu"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Lietotāja iestatījumi"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Gatavs"</string>
@@ -752,7 +752,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Palielināt visu ekrānu"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Palielināt ekrāna daļu"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Pārslēgt"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Pieejamības žests ir aizstāts ar pieejamības pogu\n\n"<annotation id="link">"Skatīt iestatījumus"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Atveriet pieejamības funkcijas. Pielāgojiet vai aizstājiet šo pogu iestatījumos.\n\n"<annotation id="link">"Skatīt iestatījumus"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Lai īslaicīgi paslēptu pogu, pārvietojiet to uz malu"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Pārvietot augšpusē pa kreisi"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Pārvietot augšpusē pa labi"</string>
@@ -804,10 +804,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Iestatījumi"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"Tiek atskaņots fails “<xliff:g id="SONG_NAME">%1$s</xliff:g>” (izpildītājs: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) no lietotnes <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> no <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Atskaņot"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Apturēt"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Iepriekšējais ieraksts"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Nākamais ieraksts"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Atskaņot"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Atveriet lietotni <xliff:g id="APP_LABEL">%1$s</xliff:g>."</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Atskaņojiet failu “<xliff:g id="SONG_NAME">%1$s</xliff:g>” (izpildītājs: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) no lietotnes <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Atskaņojiet failu “<xliff:g id="SONG_NAME">%1$s</xliff:g>” no lietotnes <xliff:g id="APP_LABEL">%2$s</xliff:g>."</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Atsaukt"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Pārvietojiet savu ierīci tuvāk, lai atskaņotu mūziku ierīcē “<xliff:g id="DEVICENAME">%1$s</xliff:g>”"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Notiek atskaņošana ierīcē “<xliff:g id="DEVICENAME">%1$s</xliff:g>”"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktīva, pārbaudiet lietotni"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Netika atrasta"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Vadīkla nav pieejama"</string>
@@ -822,7 +829,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Atlasīta viena ierīce"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Atlasītas vairākas ierīces (kopā <xliff:g id="COUNT">%1$d</xliff:g>)"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(savienojums pārtraukts)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nevarēja izveidot savienojumu. Mēģiniet vēlreiz."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nevar pārslēgt. Pieskarieties, lai mēģinātu vēlreiz."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Savienošana pārī ar jaunu ierīci"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijas numurs"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versijas numurs ir kopēts starpliktuvē."</string>
@@ -887,8 +894,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Visu tīklu skatīšana"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Lai pārslēgtu tīklus, atvienojiet tīkla Ethernet vadu."</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Lai uzlabotu ierīces lietošanas iespējas, lietotnes un pakalpojumi joprojām varēs meklēt Wi‑Fi tīklus jebkurā laikā, pat ja Wi‑Fi būs izslēgts. Varat to mainīt Wi‑Fi meklēšanas iestatījumos. "<annotation id="link">"Mainīt"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Izslēgt lidojuma režīmu"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> pieprasa atļauju pievienot tālāk norādīto elementu ātrajiem iestatījumiem"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Pievienot elementu"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nepievienot elementu"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Lietotāja atlase"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Lietotnes, kas darbojas fonā"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Apturēt"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/tiles_states_strings.xml b/packages/SystemUI/res/values-lv/tiles_states_strings.xml
index ed0baf2..c5718f8 100644
--- a/packages/SystemUI/res/values-lv/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-lv/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Izslēgts"</item>
<item msgid="460891964396502657">"Ieslēgts"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Nav pieejams"</item>
+ <item msgid="5581384648880018330">"Izslēgts"</item>
+ <item msgid="8000850843692192257">"Ieslēgts"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index de05345..ae9f3c0 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Нема достапни уреди"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi не е поврзано"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Осветленост"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Преврти ги боите"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инверзија на боите"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Повеќе поставки"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Поставки на корисникот"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Зголемете го целиот екран"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Зголемувајте дел од екранот"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Префрли"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Копчето за пристапност го замени движењето за пристапност\n\n"<annotation id="link">"Прикажи поставки"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Допрете за функциите за пристапност. Приспособете или заменете го копчево во „Поставки“.\n\n"<annotation id="link">"Прикажи поставки"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Преместете го копчето до работ за да го сокриете привремено"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Премести горе лево"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Премести горе десно"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Поставки"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> од <xliff:g id="ARTIST_NAME">%2$s</xliff:g> е пуштено на <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> од <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Пушти"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Пауза"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Претходна песна"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Следна песна"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Пушти"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Отворете <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Пуштете <xliff:g id="SONG_NAME">%1$s</xliff:g> од <xliff:g id="ARTIST_NAME">%2$s</xliff:g> на <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Пуштете <xliff:g id="SONG_NAME">%1$s</xliff:g> на <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Врати"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Приближете се за да пуштите на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Се репродуцира на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивна, провери апликација"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не е најдено"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е достапна"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Избран е 1 уред"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Избрани се <xliff:g id="COUNT">%1$d</xliff:g> уреди"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(врската е прекината)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не може да се поврзе. Обидете се повторно."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Не се префрла. Допрете и обидете се пак."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спарете нов уред"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Број на верзија"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Бројот на верзијата е копиран во привремената меморија."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Прикажи ги сите"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"За промена на мрежата, прекинете ја врската со етернетот"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"За да се подобри доживувањето на уредот, апликациите и услугите може сѐ уште да скенираат за Wi‑Fi мрежи во секое време, дури и кога Wi‑Fi е исклучено. Може да го промените ова во поставките за „Скенирање за Wi-Fi“. "<annotation id="link">"Промени"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Исклучи го авионскиот режим"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> сака да ја додаде следнава плочка на „Брзите поставки“"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Додајте плочка"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Не додавајте плочка"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Изберете корисник"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Апликации се извршуваат во заднина"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Крај"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/tiles_states_strings.xml b/packages/SystemUI/res/values-mk/tiles_states_strings.xml
index 5c36715..fa484ae 100644
--- a/packages/SystemUI/res/values-mk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mk/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Исклучен"</item>
<item msgid="460891964396502657">"Вклучен"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Недостапно"</item>
+ <item msgid="5581384648880018330">"Исклучено"</item>
+ <item msgid="8000850843692192257">"Вклучено"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index e7a5c33..ea54bd0 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ഉപകരണങ്ങളൊന്നും ലഭ്യമല്ല"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"വൈഫൈ കണക്റ്റ് ചെയ്തിട്ടില്ല"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"തെളിച്ചം"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"നെഗറ്റീവ് ലുക്ക്"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"നിറം വിപരീതമാക്കൽ"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"കൂടുതൽ ക്രമീകരണങ്ങൾ"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ഉപയോക്തൃ ക്രമീകരണം"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"പൂർത്തിയാക്കി"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"സ്ക്രീൻ പൂർണ്ണമായും മാഗ്നിഫൈ ചെയ്യുക"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"സ്ക്രീനിന്റെ ഭാഗം മാഗ്നിഫൈ ചെയ്യുക"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"മാറുക"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"ഉപയോഗസഹായി ജെസ്ച്ചറിനെ മാറ്റി പകരം ഉപയോഗസഹായി ബട്ടൺ വന്നു\n\n"<annotation id="link">"ക്രമീകരണം കാണുക"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ഉപയോഗസഹായി ഫീച്ചർ തുറക്കാൻ ടാപ്പ് ചെയ്യൂ. ക്രമീകരണത്തിൽ ഈ ബട്ടൺ ഇഷ്ടാനുസൃതമാക്കാം, മാറ്റാം.\n\n"<annotation id="link">"ക്രമീകരണം കാണൂ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"തൽക്കാലം മറയ്ക്കുന്നതിന് ബട്ടൺ അരുകിലേക്ക് നീക്കുക"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"മുകളിൽ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"മുകളിൽ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"ക്രമീകരണം"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> എന്ന ആർട്ടിസ്റ്റിന്റെ <xliff:g id="SONG_NAME">%1$s</xliff:g> എന്ന ഗാനം <xliff:g id="APP_LABEL">%3$s</xliff:g> ആപ്പിൽ പ്ലേ ചെയ്യുന്നു"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>-ൽ <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"പ്ലേ ചെയ്യുക"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"താൽക്കാലികമായി നിർത്തുക"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"മുമ്പത്തെ ട്രാക്ക്"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"അടുത്ത ട്രാക്ക്"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"പ്ലേ ചെയ്യുക"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> തുറക്കുക"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> എന്ന ആർട്ടിസ്റ്റിന്റെ <xliff:g id="SONG_NAME">%1$s</xliff:g> എന്ന ഗാനം <xliff:g id="APP_LABEL">%3$s</xliff:g> ആപ്പിൽ പ്ലേ ചെയ്യുക"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> എന്ന ഗാനം <xliff:g id="APP_LABEL">%2$s</xliff:g> ആപ്പിൽ പ്ലേ ചെയ്യുക"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"പഴയപടിയാക്കുക"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിൽ പ്ലേ ചെയ്യാൻ അടുത്തേക്ക് നീക്കുക"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിൽ പ്ലേ ചെയ്യുന്നു"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"നിഷ്ക്രിയം, ആപ്പ് പരിശോധിക്കൂ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"കണ്ടെത്തിയില്ല"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"നിയന്ത്രണം ലഭ്യമല്ല"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"ഒരു ഉപകരണം തിരഞ്ഞെടുത്തു"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> ഉപകരണങ്ങൾ തിരഞ്ഞെടുത്തു"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(വിച്ഛേദിച്ചു)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"കണക്റ്റ് ചെയ്യാനായില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"മാറാനാകുന്നില്ല. വീണ്ടും ശ്രമിക്കാൻ ടാപ്പ് ചെയ്യുക."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"പുതിയ ഉപകരണവുമായി ജോടിയാക്കുക"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ബിൽഡ് നമ്പർ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ക്ലിപ്പ്ബോർഡിലേക്ക് ബിൽഡ് നമ്പർ പകർത്തി."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"എല്ലാം കാണുക"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"മറ്റ് നെറ്റ്വർക്കുകളിലേക്ക് മാറാൻ, ഇതർനെറ്റ് വിച്ഛേദിക്കുക"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"ഉപകരണ അനുഭവം മെച്ചപ്പെടുത്താൻ, വൈഫൈ ഓഫാക്കിയിരിക്കുമ്പോൾ പോലും ആപ്പുകൾക്കും സേവനങ്ങൾക്കും വൈഫൈ നെറ്റ്വർക്കുകൾ കണ്ടെത്താൻ ഏത് സമയത്തും സ്കാൻ ചെയ്യാനാകും. നിങ്ങൾക്ക് ഇത് വൈഫൈ സ്കാനിംഗ് ക്രമീകരണത്തിൽ മാറ്റാം. "<annotation id="link">"മാറ്റുക"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ഫ്ലൈറ്റ് മോഡ് ഓഫാക്കുക"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"ദ്രുത ക്രമീകരണത്തിലേക്ക് ഇനിപ്പറയുന്ന ടൈൽ ചേർക്കാൻ <xliff:g id="APPNAME">%1$s</xliff:g> ആവശ്യപ്പെടുന്നു"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ടൈൽ ചേർക്കുക"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ടൈൽ ചേർക്കരുത്"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ഉപയോക്താവിനെ തിരഞ്ഞെടുക്കൂ"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ആപ്പുകൾ പശ്ചാത്തലത്തിൽ റൺ ചെയ്യുന്നു"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"നിർത്തുക"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/tiles_states_strings.xml b/packages/SystemUI/res/values-ml/tiles_states_strings.xml
index 5cfd45a..0cca763 100644
--- a/packages/SystemUI/res/values-ml/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ml/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"ഓഫാണ്"</item>
<item msgid="460891964396502657">"ഓണാണ്"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"ലഭ്യമല്ല"</item>
+ <item msgid="5581384648880018330">"ഓഫാണ്"</item>
+ <item msgid="8000850843692192257">"ഓണാണ്"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index f324cc11..d4c924d 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Төхөөрөмж байхгүй"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi-д холбогдоогүй байна"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Тодрол"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Өнгийг урвуулах"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Өнгө урвуулах"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Бусад тохиргоо"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Хэрэглэгчийн тохиргоо"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Дууссан"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Бүтэн дэлгэцийг томруулах"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Дэлгэцийн нэг хэсгийг томруулах"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Сэлгэх"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Хандалтын товчлуурыг хандалтын зангаагаар сольсон\n\n"<annotation id="link">"Тохиргоо харах"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Хандалтын онцлогуудыг нээхийн тулд товшино уу. Энэ товчлуурыг Тохиргоо хэсэгт өөрчилж эсвэл солиорой.\n\n"<annotation id="link">"Тохиргоог харах"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Үүнийг түр нуухын тулд товчлуурыг зах руу зөөнө үү"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Зүүн дээш зөөх"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Баруун дээш зөөх"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Тохиргоо"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> дээр тоглуулж буй <xliff:g id="ARTIST_NAME">%2$s</xliff:g>-н <xliff:g id="SONG_NAME">%1$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>-н <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Тоглуулах"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Түр зогсоох"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Өмнөх бичлэг"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Дараагийн бичлэг"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Тоглуулах"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g>-г нээх"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>-н <xliff:g id="SONG_NAME">%1$s</xliff:g>-г <xliff:g id="APP_LABEL">%3$s</xliff:g> дээр тоглуулах"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g>-г <xliff:g id="APP_LABEL">%2$s</xliff:g> дээр тоглуулах"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Болих"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> дээр тоглуулахын тулд төхөөрөмжөө ойртуулна уу"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> дээр тоглуулж байна"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Идэвхгүй байна, аппыг шалгана уу"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Олдсонгүй"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Хяналт боломжгүй байна"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 төхөөрөмж сонгосон"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> төхөөрөмж сонгосон"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(салсан)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Холбогдож чадсангүй. Дахин оролдоно уу."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Сэлгэх боломжгүй. Дахин оролдохын тулд товшино уу."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Шинэ төхөөрөмж хослуулах"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Хийцийн дугаар"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Хийцийн дугаарыг түр санах ойд хуулсан."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Бүгдийг харах"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Сүлжээг сэлгэхийн тулд этернэтийг салгана уу"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Төхөөрөмжийн туршлагыг сайжруулахын тулд аппууд болон үйлчилгээнүүд нь Wi-Fi сүлжээг хүссэн үедээ буюу Wi-Fi-г унтраалттай байсан ч скан хийх боломжтой хэвээр байна. Та үүнийг Wi-Fi скан хийх тохиргоонд өөрчлөх боломжтой. "<annotation id="link">"Өөрчлөх"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Нислэгийн горимыг унтраах"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> нь дараах хавтанг Шуурхай тохиргоонд нэмэх хүсэлтэй байна"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Хавтан нэмэх"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Хавтанг бүү нэм"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Хэрэглэгч сонгох"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Ард ажиллаж байгаа аппууд"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Зогсоох"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/tiles_states_strings.xml b/packages/SystemUI/res/values-mn/tiles_states_strings.xml
index ba14927..41049d8 100644
--- a/packages/SystemUI/res/values-mn/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mn/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Унтраалттай"</item>
<item msgid="460891964396502657">"Асаалттай"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Боломжгүй"</item>
+ <item msgid="5581384648880018330">"Унтраалттай байна"</item>
+ <item msgid="8000850843692192257">"Асаалттай байна"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index e72d3c1..5b41bed 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"कोणतेही डिव्हाइसेस उपलब्ध नाहीत"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"वाय-फाय नाही"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"चमक"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"रंग उलटे करा"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"कलर इन्व्हर्जन"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"अधिक सेटिंग्ज"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"वापरकर्ता सेटिंग्ज"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"पूर्ण झाले"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"फुल स्क्रीन मॅग्निफाय करा"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रीनचा काही भाग मॅग्निफाय करा"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"स्विच करा"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"अॅक्सेसिबिलिटी जेश्चर हे आता अॅक्सेसिबिलिटी बटण आहे \n\n"<annotation id="link">"सेटिंग्ज पहा"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"अॅक्सेसिबिलिटी वैशिष्ट्ये उघडण्यासाठी, टॅप करा. सेटिंग्जमध्ये हे बटण कस्टमाइझ करा किंवा बदला.\n\n"<annotation id="link">"सेटिंग्ज पहा"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"बटण तात्पुरते लपवण्यासाठी ते कोपर्यामध्ये हलवा"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"वर डावीकडे हलवा"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"वर उजवीकडे हलवा"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिंग्ज"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> मध्ये <xliff:g id="ARTIST_NAME">%2$s</xliff:g> चे <xliff:g id="SONG_NAME">%1$s</xliff:g> प्ले होत आहे"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> पैकी <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"प्ले करा"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"थांबवा"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"मागील गाणे"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"पुढील गाणे"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"प्ले करणे"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> उघडा"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> मध्ये <xliff:g id="ARTIST_NAME">%2$s</xliff:g> चे <xliff:g id="SONG_NAME">%1$s</xliff:g> प्ले करा"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> मध्ये <xliff:g id="SONG_NAME">%1$s</xliff:g> प्ले करा"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"पहिल्यासारखे करा"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> वर प्ले करण्यासाठी जवळ जा"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> वर प्ले केला जात आहे"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय, ॲप तपासा"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"आढळले नाही"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"नियंत्रण उपलब्ध नाही"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"एक डिव्हाइस निवडले"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> डिव्हाइस निवडली आहेत"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(डिस्कनेक्ट केलेले)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"कनेक्ट करू शकलो नाही. पुन्हा प्रयत्न करा."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"स्विच करू शकत नाही. पुन्हा प्रयत्न करण्यासाठी टॅप करा."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नवीन डिव्हाइससोबत पेअर करा"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर क्लिपबोर्डवर कॉपी केला."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"सर्व पहा"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क स्विच करण्यासाठी, इथरनेट केबल डिस्कनेक्ट करा"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"डिव्हाइसच्या अनुभवामध्ये सुधारणा करण्यासाठी, वाय-फाय बंद असले तरीही ॲप्स आणि सेवा या कधीही वाय-फाय नेटवर्क स्कॅन करू शकतात. तुम्ही हे वाय-फाय स्कॅनिंग सेटिंग्जमध्ये बदलू शकता. "<annotation id="link">"बदला"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"विमान मोड बंद करा"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ला क्विक सेटिंग्जमध्ये पुढील टाइल जोडायची आहे"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"टाइल जोडा"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"टाइल जोडू नका"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"वापरकर्ता निवडा"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ॲप्स बॅकग्राउंडमध्ये रन होत आहेत"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"थांबवा"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/tiles_states_strings.xml b/packages/SystemUI/res/values-mr/tiles_states_strings.xml
index dbb7ed5..588c5ad 100644
--- a/packages/SystemUI/res/values-mr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-mr/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"बंद आहे"</item>
<item msgid="460891964396502657">"सुरू आहे"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"उपलब्ध नाही"</item>
+ <item msgid="5581384648880018330">"बंद आहे"</item>
+ <item msgid="8000850843692192257">"सुरू आहे"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 09b8241..1dc3873 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Tiada peranti tersedia"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi tidak disambungkan"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Kecerahan"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Songsangkan warna"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Penyongsangan warna"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Lagi tetapan"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Tetapan pengguna"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Selesai"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Besarkan skrin penuh"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Besarkan sebahagian skrin"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Tukar"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Butang kebolehaksesan menggantikan gerak isyarat kebolehaksesan\n\n"<annotation id="link">"Lihat tetapan"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Ketik untuk membuka ciri kebolehaksesan. Sesuaikan/gantikan butang ini dalam Tetapan.\n\n"<annotation id="link">"Lihat tetapan"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Gerakkan butang ke tepi untuk disembunyikan buat sementara waktu"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Alihkan ke atas sebelah kiri"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Alihkan ke atas sebelah kanan"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Tetapan"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> oleh <xliff:g id="ARTIST_NAME">%2$s</xliff:g> dimainkan daripada <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> daripada <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Main"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Jeda"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Lagu sebelumnya"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Lagu seterusnya"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Main"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Buka <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Mainkan <xliff:g id="SONG_NAME">%1$s</xliff:g> oleh <xliff:g id="ARTIST_NAME">%2$s</xliff:g> daripada <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Mainkan <xliff:g id="SONG_NAME">%1$s</xliff:g> daripada <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Buat asal"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Alihkan lebih dekat untuk bermain pada<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Dimainkan pada <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Tidak aktif, semak apl"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kawalan tidak tersedia"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 peranti dipilih"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> peranti dipilih"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(diputuskan sambungan)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Tidak boleh menyambung. Cuba lagi."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Tidak dapat menukar. Ketik untuk mencuba lagi."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Gandingkan peranti baharu"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nombor binaan"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nombor binaan disalin ke papan keratan."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Untuk menukar rangkaian, putuskan sambungan ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Untuk meningkatkan pengalaman peranti, apl dan perkhidmatan masih dapat melakukan imbasan untuk mengesan rangkaian Wi-Fi pada bila-bila masa, meskipun apabila Wi-Fi dimatikan. Anda boleh menukar tetapan ini dalam tetapan pengimbasan Wi-Fi. "<annotation id="link">"Tukar"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Matikan mod pesawat"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> mahu menambah jubin yang berikut kepada Tetapan Pantas"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Tambahkan jubin"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Jangan tambah jubin"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Pilih pengguna"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apl berjalan di latar"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Berhenti"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/tiles_states_strings.xml b/packages/SystemUI/res/values-ms/tiles_states_strings.xml
index b3ee999..60ce1f0 100644
--- a/packages/SystemUI/res/values-ms/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ms/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Mati"</item>
<item msgid="460891964396502657">"Hidup"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Tidak tersedia"</item>
+ <item msgid="5581384648880018330">"Mati"</item>
+ <item msgid="8000850843692192257">"Hidup"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 17fd70e..5ceadae 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ကိရိယာများ မရှိ"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi ချိတ်ဆက်ထားခြင်းမရှိပါ"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"အလင်းတောက်ပမှု"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"အရောင်ပြောင်းပြန်"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"အရောင်ပြောင်းပြန်ပြုလုပ်ရန်"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"နောက်ထပ် ဆက်တင်များ"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"အသုံးပြုသူ ဆက်တင်များ"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"ပြီးပါပြီ"</string>
@@ -529,7 +529,7 @@
<string name="notification_menu_gear_description" msgid="6429668976593634862">"အကြောင်းကြားချက် ထိန်းချုပ်မှုများ"</string>
<string name="notification_menu_snooze_description" msgid="4740133348901973244">"အကြောင်းကြားချက်များကို ဆိုင်းငံ့ရန် ရွေးချယ်စရာများ"</string>
<string name="notification_menu_snooze_action" msgid="5415729610393475019">"ကျွန်ုပ်ကို သတိပေးပါ"</string>
- <string name="snooze_undo" msgid="2738844148845992103">"တစ်ဆင့်နောက်ပြန်ရန်"</string>
+ <string name="snooze_undo" msgid="2738844148845992103">"နောက်ပြန်ရန်"</string>
<string name="snoozed_for_time" msgid="7586689374860469469">"<xliff:g id="TIME_AMOUNT">%1$s</xliff:g> ဆိုင်းငံ့ရန်"</string>
<plurals name="snoozeHourOptions" formatted="false" msgid="2066838694120718170">
<item quantity="other">%d နာရီ</item>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ဖန်သားပြင်အပြည့် ချဲ့သည်"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ဖန်သားပြင် တစ်စိတ်တစ်ပိုင်းကို ချဲ့ပါ"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ခလုတ်"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"အများသုံးစွဲနိုင်မှုခလုတ်က အများသုံးစွဲနိုင်မှုလက်ဟန်ကို အစားထိုးသည်\n\n"<annotation id="link">"ဆက်တင်များကို ကြည့်ပါ"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုများ ဖွင့်ရန် တို့ပါ။ ဆက်တင်များတွင် ဤခလုတ်ကို စိတ်ကြိုက်ပြင်ပါ (သို့) လဲပါ။\n\n"<annotation id="link">"ဆက်တင်များ ကြည့်ရန်"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ခလုတ်ကို ယာယီဝှက်ရန် အစွန်းသို့ရွှေ့ပါ"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ဘယ်ဘက်ထိပ်သို့ ရွှေ့ရန်"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ညာဘက်ထိပ်သို့ ရွှေ့ရန်"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"ဆက်တင်များ"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ၏ <xliff:g id="SONG_NAME">%1$s</xliff:g> ကို <xliff:g id="APP_LABEL">%3$s</xliff:g> တွင် ဖွင့်ထားသည်"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> အနက် <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"ဖွင့်ရန်"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"ခဏရပ်ရန်"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"ယခင် တစ်ပုဒ်"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"နောက်တစ်ပုဒ်"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ဖွင့်ခြင်း"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ကို ဖွင့်ပါ"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ၏ <xliff:g id="SONG_NAME">%1$s</xliff:g> ကို <xliff:g id="APP_LABEL">%3$s</xliff:g> တွင် ဖွင့်ပါ"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ကို <xliff:g id="APP_LABEL">%2$s</xliff:g> တွင် ဖွင့်ပါ"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"နောက်ပြန်ရန်"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> တွင်ဖွင့်ရန် အနီးသို့ရွှေ့ပါ"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> တွင်ဖွင့်ထားသည်"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ရပ်နေသည်၊ အက်ပ်ကို စစ်ဆေးပါ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"မတွေ့ပါ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ထိန်းချုပ်မှု မရနိုင်ပါ"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"စက်ပစ္စည်း ၁ ခုကို ရွေးချယ်ထားသည်"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"စက်ပစ္စည်း <xliff:g id="COUNT">%1$d</xliff:g> ခုကို ရွေးချယ်ထားသည်"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ချိတ်ဆက်မှု မရှိပါ)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ချိတ်ဆက်၍ မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ပြောင်း၍ မရပါ။ ပြန်စမ်းကြည့်ရန် တို့ပါ။"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"စက်အသစ် တွဲချိတ်ရန်"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"တည်ဆောက်မှုနံပါတ်"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"တည်ဆောက်မှုနံပါတ်ကို ကလစ်ဘုတ်သို့ မိတ္တူကူးပြီးပါပြီ။"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"အားလုံးကြည့်ရန်"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ကွန်ရက်ပြောင်းရန် အီသာနက်ကို ချိတ်ဆက်မှုဖြုတ်ပါ"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"စက်ပစ္စည်းကို ပိုမိုကောင်းမွန်စွာ အသုံးပြုနိုင်ရန် Wi-Fi ပိတ်ထားသည့်တိုင် အက်ပ်နှင့် ဝန်ဆောင်မှုများက Wi-Fi ကွန်ရက်များကို အချိန်မရွေး စကင်ဖတ်နိုင်သည်။ ၎င်းကို Wi-Fi ရှာဖွေခြင်း ဆက်တင်များတွင် ပြောင်းနိုင်သည်။ "<annotation id="link">"ပြောင်းရန်"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"လေယာဉ်ပျံမုဒ်ကို ပိတ်ရန်"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> က ‘အမြန် ဆက်တင်များ’ တွင် အောက်ပါအကွက်ငယ်ကို ထည့်လိုသည်"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"အကွက်ငယ် ထည့်ရန်"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"အကွက်ငယ် မထည့်ပါ"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"အသုံးပြုသူ ရွေးခြင်း"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"နောက်ခံတွင် ဖွင့်ထားသောအက်ပ်များ"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ရပ်ရန်"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/tiles_states_strings.xml b/packages/SystemUI/res/values-my/tiles_states_strings.xml
index 6c58ac3..7d2f20b 100644
--- a/packages/SystemUI/res/values-my/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-my/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"ပိတ်"</item>
<item msgid="460891964396502657">"ဖွင့်"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"မရနိုင်ပါ"</item>
+ <item msgid="5581384648880018330">"ပိတ်"</item>
+ <item msgid="8000850843692192257">"ဖွင့်"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 50a1bdb..5aa4dd2 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Ingen enheter er tilgjengelige"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi er ikke tilkoblet"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Lysstyrke"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverter farger"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Fargeinvertering"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Flere innstillinger"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Brukerinnstillinger"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Ferdig"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Forstørr hele skjermen"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Forstørr en del av skjermen"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Bytt"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Tilgjengelighet-knappen har erstattet tilgjengelighetsbevegelsen\n\n"<annotation id="link">"Se innstillingene"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Trykk for å åpne tilgj.funksjoner. Tilpass eller bytt knappen i Innstillinger.\n\n"<annotation id="link">"Se innstillingene"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Flytt knappen til kanten for å skjule den midlertidig"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Flytt til øverst til venstre"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Flytt til øverst til høyre"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Innstillinger"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> av <xliff:g id="ARTIST_NAME">%2$s</xliff:g> spilles av fra <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> av <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Spill av"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pause"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Forrige spor"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Neste spor"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Spill av"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Åpne <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Spill av <xliff:g id="SONG_NAME">%1$s</xliff:g> av <xliff:g id="ARTIST_NAME">%2$s</xliff:g> fra <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Spill av <xliff:g id="SONG_NAME">%1$s</xliff:g> fra <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Angre"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Flytt nærmere for å spille av på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Spilles av på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Sjekk appen"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ikke funnet"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrollen er utilgjengelig"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 enhet er valgt"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> enheter er valgt"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(frakoblet)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Kunne ikke koble til. Prøv på nytt."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Kan ikke bytte. Trykk for å prøve igjen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Koble til en ny enhet"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Delversjonsnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Delversjonsnummeret er kopiert til utklippstavlen."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"For å bytte nettverk, koble fra Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"For å forbedre brukeropplevelsen på enheten kan apper og tjenester søke etter Wi-Fi-nettverk når som helst – også når Wi-Fi er slått av. Du kan endre dette i innstillingene for Wi-Fi-skanning. "<annotation id="link">"Bytt"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Slå av flymodus"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vil legge til denne brikken i Hurtiginnstillinger"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Legg til brikke"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ikke legg til brikke"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Velg bruker"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apper som kjører i bakgrunnen"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stopp"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/tiles_states_strings.xml b/packages/SystemUI/res/values-nb/tiles_states_strings.xml
index a40e4a4..e512a84 100644
--- a/packages/SystemUI/res/values-nb/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-nb/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Av"</item>
<item msgid="460891964396502657">"På"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Utilgjengelig"</item>
+ <item msgid="5581384648880018330">"Av"</item>
+ <item msgid="8000850843692192257">"På"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 64881eb..afa8f1f 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"कुनै उपकरणहरू उपलब्ध छैन"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi जडान गरिएको छैन"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"उज्यालपन"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"रंग उल्टाउनुहोस्"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"कलर इन्भर्सन"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"थप सेटिङहरू"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"प्रयोगकर्तासम्बन्धी सेटिङ"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"भयो"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"पूरै स्क्रिन जुम इन गर्नुहोस्"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रिनको केही भाग म्याग्निफाइ गर्नुहोस्"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"बदल्नुहोस्"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"एक्सेसिबिलिटी इसाराका स्थानमा एक्सेसिबिलिटी बटन प्रयोग हुन थालेको छ\n\n"<annotation id="link">"सेटिङ हेर्नुहोस्"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"सर्वसुलभता कायम गर्ने सुविधा खोल्न ट्याप गर्नुहोस्। सेटिङमा गई यो बटन कस्टमाइज गर्नुहोस् वा बदल्नुहोस्।\n\n"<annotation id="link">"सेटिङ हेर्नुहोस्"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"यो बटन केही बेर नदेखिने पार्न किनारातिर सार्नुहोस्"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"सिरानको बायाँतिर सार्नुहोस्"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"सिरानको दायाँतिर सार्नुहोस्"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिङ"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> को <xliff:g id="SONG_NAME">%1$s</xliff:g> बोलको गीत <xliff:g id="APP_LABEL">%3$s</xliff:g> मा बज्दै छ"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> मध्ये <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"प्ले गर्नुहोस्"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"पज गर्नुहोस्"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"अघिल्लो ट्रयाक"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"अर्को ट्र्याक"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"प्ले गर्नुहोस्"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> खोल्नुहोस्"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> को <xliff:g id="SONG_NAME">%1$s</xliff:g> बोलको गीत <xliff:g id="APP_LABEL">%3$s</xliff:g> मा बजाउनुहोस्"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> बोलको गीत <xliff:g id="APP_LABEL">%2$s</xliff:g> मा बजाउनुहोस्"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"अन्डू गर्नुहोस्"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> मा प्ले गर्न आफ्नो डिभाइस नजिकै लैजानुहोस्"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> मा प्ले गरिँदै छ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय छ, एप जाँच गर्नु…"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"फेला परेन"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"नियन्त्रण उपलब्ध छैन"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"१ यन्त्र चयन गरियो"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> वटा यन्त्र चयन गरिए"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(डिस्कनेक्ट गरिएको छ)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"कनेक्ट गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"बदल्न सकिएन। फेरि प्रयास गर्न ट्याप गर्नुहोस्।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नयाँ डिभाइस कनेक्ट गर्नुहोस्"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नम्बर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नम्बर कपी गरी क्लिपबोर्डमा सारियो।"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"सबै नेटवर्क हेर्नुहोस्"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क बदल्न इथरनेट डिस्कनेक्ट गर्नुहोस्"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"डिभाइस प्रयोगको अनुभवमा गुणस्तर सुधार गर्न, एप तथा सेवाहरूले अझै पनि जुनसुकै बेला (Wi‑Fi अफ भएका बेलामा पनि) Wi‑Fi नेटवर्क खोज्न सक्छन्। तपाईं यसलाई Wi‑Fi स्क्यानिङका सेटिङमा गई परिवर्तन गर्न सक्नुहुन्छ। "<annotation id="link">"बदल्नुहोस्"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"हवाइजहाज मोड अफ गर्नुहोस्"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> द्रुत सेटिङमा निम्न टाइल हाल्न चाहन्छ"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"टाइल हाल्नुहोस्"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"टाइल नहाल्नुहोस्"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"प्रयोगकर्ता चयन गर्नु…"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"अहिले ब्याकग्राउन्डमा चलिरहेका एप"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"रोक्नुहोस्"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/tiles_states_strings.xml b/packages/SystemUI/res/values-ne/tiles_states_strings.xml
index 373044d..355df40 100644
--- a/packages/SystemUI/res/values-ne/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ne/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"अफ छ"</item>
<item msgid="460891964396502657">"अन छ"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"उपलब्ध छैन"</item>
+ <item msgid="5581384648880018330">"अफ छ"</item>
+ <item msgid="8000850843692192257">"अन छ"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 093ba95..09b278f 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Geen apparaten beschikbaar"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wifi niet verbonden"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Helderheid"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Kleuren omkeren"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Kleurinversie"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Meer instellingen"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Gebruikersinstellingen"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Klaar"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Volledig scherm vergroten"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Deel van het scherm vergroten"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Schakelen"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"De knop Toegankelijkheid vervangt het toegankelijkheidsgebaar\n\n"<annotation id="link">"Instellingen bekijken"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tik voor toegankelijkheidsfuncties. Wijzig of vervang deze knop via Instellingen.\n\n"<annotation id="link">"Naar Instellingen"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Knop naar de rand verplaatsen om deze tijdelijk te verbergen"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Naar linksboven verplaatsen"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Naar rechtsboven verplaatsen"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Instellingen"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> van <xliff:g id="ARTIST_NAME">%2$s</xliff:g> wordt afgespeeld via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> van <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Afspelen"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pauzeren"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Vorige track"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Volgende track"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Afspelen"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> openen"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> van <xliff:g id="ARTIST_NAME">%2$s</xliff:g> afspelen via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> afspelen via <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Ongedaan maken"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Ga dichter naar <xliff:g id="DEVICENAME">%1$s</xliff:g> toe om af te spelen"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Afspelen op <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactief, check de app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Niet gevonden"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Beheeroptie niet beschikbaar"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Eén apparaat geselecteerd"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> apparaten geselecteerd"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(verbinding verbroken)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Kan geen verbinding maken. Probeer het nog eens."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Kan niet schakelen. Tik om het opnieuw te proberen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Nieuw apparaat koppelen"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-nummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build-nummer naar klembord gekopieerd."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Alles tonen"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Verbreek de ethernetverbinding om van netwerk te wisselen"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Apps en services kunnen nog steeds op elk moment scannen op wifi-netwerken, zelfs als wifi uitstaat, om de apparaatfunctionaliteit te verbeteren. Je kunt dit aanpassen in de instellingen voor wifi-scannen. "<annotation id="link">"Wijzigen"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Vliegtuigmodus uitzetten"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wil de volgende tegel toevoegen aan Snelle instellingen"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Tegel toevoegen"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Tegel niet toevoegen"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Gebruiker selecteren"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps die op de achtergrond worden uitgevoerd"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stoppen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/tiles_states_strings.xml b/packages/SystemUI/res/values-nl/tiles_states_strings.xml
index 6d2ef5f..fa85b88 100644
--- a/packages/SystemUI/res/values-nl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-nl/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Uit"</item>
<item msgid="460891964396502657">"Aan"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Niet beschikbaar"</item>
+ <item msgid="5581384648880018330">"Uit"</item>
+ <item msgid="8000850843692192257">"Aan"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 931d696..0d0cea5 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"କୌଣସି ଡିଭାଇସ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ୱାଇ-ଫାଇ ସଂଯୋଜିତ ହୋଇନାହିଁ"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ଉଜ୍ଜ୍ୱଳତା"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ରଙ୍ଗ ଇନଭାର୍ଟ୍ କରନ୍ତୁ"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ରଙ୍ଗ ଇନଭାର୍ସନ"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"ଅଧିକ ସେଟିଂସ୍"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ଉପଯୋଗକର୍ତ୍ତା ସେଟିଂସ୍"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"ହୋଇଗଲା"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ସମ୍ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନକୁ ମ୍ୟାଗ୍ନିଫାଏ କରନ୍ତୁ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ସ୍କ୍ରିନର ଅଂଶ ମାଗ୍ନିଫାଏ କରନ୍ତୁ"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ସ୍ୱିଚ୍ କରନ୍ତୁ"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"ଆକ୍ସେସିବିଲିଟୀ ଜେଶ୍ଚରକୁ ଆକ୍ସେସିବିଲିଟୀ ବଟନରେ ପରିବର୍ତ୍ତନ କରାଯାଇଛି\n\n"<annotation id="link">"ସେଟିଂସ୍ ଦେଖନ୍ତୁ"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ଆକ୍ସେସିବିଲିଟୀ ଫିଚର ଖୋଲିବାକୁ ଟାପ କରନ୍ତୁ। ସେଟିଂସରେ ଏହି ବଟନକୁ କଷ୍ଟମାଇଜ କର କିମ୍ବା ବଦଳାଅ।\n\n"<annotation id="link">"ସେଟିଂସ ଦେଖନ୍ତୁ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ବଟନକୁ ଅସ୍ଥାୟୀ ଭାବେ ଲୁଚାଇବା ପାଇଁ ଏହାକୁ ଗୋଟିଏ ଧାରକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ଶୀର୍ଷ ବାମକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ଶୀର୍ଷ ଡାହାଣକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"ସେଟିଂସ୍"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ରୁ <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ଙ୍କ <xliff:g id="SONG_NAME">%1$s</xliff:g> ଚାଲୁଛି"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>ରୁ <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"ଚଲାନ୍ତୁ"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"ବିରତ କରନ୍ତୁ"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"ପୂର୍ବବର୍ତ୍ତୀ ଟ୍ରାକ"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"ପରବର୍ତ୍ତୀ ଟ୍ରାକ"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ଚଲାନ୍ତୁ"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ଖୋଲନ୍ତୁ"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ରୁ <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ଙ୍କ <xliff:g id="SONG_NAME">%1$s</xliff:g> ଚଲାନ୍ତୁ"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g>ରୁ <xliff:g id="SONG_NAME">%1$s</xliff:g> ଚଲାନ୍ତୁ"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"ପୂର୍ବବତ୍ କରନ୍ତୁ"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ରେ ଚଲାଇବା ପାଇଁ ନିକଟକୁ ଯାଆନ୍ତୁ"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ରେ ଚାଲୁଛି"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ନିଷ୍କ୍ରିୟ ଅଛି, ଆପ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ମିଳିଲା ନାହିଁ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ନିୟନ୍ତ୍ରଣ ଉପଲବ୍ଧ ନାହିଁ"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1ଟି ଡିଭାଇସ୍ ଚୟନ କରାଯାଇଛି"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g>ଟି ଡିଭାଇସ୍ ଚୟନ କରାଯାଇଛି"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ବିଚ୍ଛିନ୍ନ କରାଯାଇଛି)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ସଂଯୋଗ କରାଯାଇପାରିଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ସ୍ୱିଚ କରାଯାଇପାରିବ ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ନୂଆ ଡିଭାଇସକୁ ପେୟାର୍ କରନ୍ତୁ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ବିଲ୍ଡ ନମ୍ୱର"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"କ୍ଲିପବୋର୍ଡକୁ କପି କରାଯାଇଥିବା ବିଲ୍ଡ ନମ୍ୱର।"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"ସବୁ ଦେଖନ୍ତୁ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ନେଟୱାର୍କ ସ୍ୱିଚ୍ କରିବାକୁ, ଇଥରନେଟ୍ ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"ଡିଭାଇସ ଅନୁଭୂତିକୁ ଉନ୍ନତ କରିବା ପାଇଁ, ୱାଇ-ଫାଇ ବନ୍ଦ ଥିଲେ ମଧ୍ୟ ଆପ ଓ ସେବାଗୁଡ଼ିକ ଏବେ ବି ଯେ କୌଣସି ସମୟରେ ୱାଇ-ଫାଇ ନେଟୱାର୍କ ପାଇଁ ସ୍କାନ କରିପାରିବ। ଆପଣ ଏହାକୁ ୱାଇ-ଫାଇ ସ୍କାନିଂ ସେଟିଂସରେ ପରିବର୍ତ୍ତନ କରିପାରିବେ। "<annotation id="link">"ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ଏୟାରପ୍ଲେନ ମୋଡ ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> କ୍ୱିକ୍ ସେଟିଂସରେ ନିମ୍ନୋକ୍ତ ଟାଇଲ୍ ଯୋଗ କରିବାକୁ ଚାହେଁ"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ଟାଇଲ୍ ଯୋଗ କରନ୍ତୁ"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ଟାଇଲ୍ ଯୋଗ କର ନାହିଁ"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ଉପଯୋଗକର୍ତ୍ତା ଚୟନ କର"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ପୃଷ୍ଠପଟରେ ଚାଲୁଥିବା ଆପଗୁଡ଼ିକ"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ବନ୍ଦ କରନ୍ତୁ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/tiles_states_strings.xml b/packages/SystemUI/res/values-or/tiles_states_strings.xml
index 6b52d6e..bb94e0d 100644
--- a/packages/SystemUI/res/values-or/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-or/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"ବନ୍ଦ ଅଛି"</item>
<item msgid="460891964396502657">"ଚାଲୁ ଅଛି"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"ଉପଲବ୍ଧ ନାହିଁ"</item>
+ <item msgid="5581384648880018330">"ବନ୍ଦ ଅଛି"</item>
+ <item msgid="8000850843692192257">"ଚାଲୁ ଅଛି"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index d2b2cb5..902f36c 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ਕੋਈ ਡਿਵਾਈਸਾਂ ਉਪਲਬਧ ਨਹੀਂ"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ਵਾਈ-ਫਾਈ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਗਿਆ"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ਚਮਕ"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ਰੰਗ ਪਲਟਾਓ"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ਰੰਗ ਪਲਟਨਾ"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"ਹੋਰ ਸੈਟਿੰਗਾਂ"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ਵਰਤੋਂਕਾਰ ਸੈਟਿੰਗਾਂ"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"ਹੋ ਗਿਆ"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ਪੂਰੀ ਸਕ੍ਰੀਨ ਨੂੰ ਵੱਡਦਰਸ਼ੀ ਕਰੋ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ਸਕ੍ਰੀਨ ਦੇ ਹਿੱਸੇ ਨੂੰ ਵੱਡਾ ਕਰੋ"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ਸਵਿੱਚ"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"ਪਹੁੰਚਯੋਗਤਾ ਬਟਨ ਨੂੰ ਪਹੁੰਚਯੋਗਤਾ ਸੰਕੇਤ ਨਾਲ ਬਦਲ ਦਿੱਤਾ ਗਿਆ\n\n"<annotation id="link">"ਸੈਟਿੰਗਾਂ ਦੇਖੋ"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ। ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਇਹ ਬਟਨ ਵਿਉਂਤਬੱਧ ਕਰੋ ਜਾਂ ਬਦਲੋ।\n\n"<annotation id="link">"ਸੈਟਿੰਗਾਂ ਦੇਖੋ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ਬਟਨ ਨੂੰ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਲੁਕਾਉਣ ਲਈ ਕਿਨਾਰੇ \'ਤੇ ਲਿਜਾਓ"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ਉੱਪਰ ਵੱਲ ਖੱਬੇ ਲਿਜਾਓ"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ਉੱਪਰ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"ਸੈਟਿੰਗਾਂ"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ਤੋਂ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ਦਾ <xliff:g id="SONG_NAME">%1$s</xliff:g> ਚੱਲ ਰਿਹਾ ਹੈ"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> ਵਿੱਚੋਂ <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"ਚਲਾਓ"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"ਰੋਕੋ"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"ਪਿਛਲਾ ਟਰੈਕ"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"ਅਗਲਾ ਟਰੈਕ"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ਚਲਾਓ"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ਖੋਲ੍ਹੋ"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ਤੋਂ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ਦਾ <xliff:g id="SONG_NAME">%1$s</xliff:g> ਚਲਾਓ"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> ਤੋਂ <xliff:g id="SONG_NAME">%1$s</xliff:g> ਚਲਾਓ"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"ਅਣਕੀਤਾ ਕਰੋ"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> \'ਤੇ ਚਲਾਉਣ ਲਈ ਨੇੜੇ ਲਿਜਾਓ"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> \'ਤੇ ਚਲਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ਅਕਿਰਿਆਸ਼ੀਲ, ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ਨਹੀਂ ਮਿਲਿਆ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ਕੰਟਰੋਲ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ਡੀਵਾਈਸ ਨੂੰ ਚੁਣਿਆ ਗਿਆ"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> ਡੀਵਾਈਸਾਂ ਨੂੰ ਚੁਣਿਆ ਗਿਆ"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ਡਿਸਕਨੈਕਟ ਹੈ)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"ਬਦਲਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ਬਿਲਡ ਨੰਬਰ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ਬਿਲਡ ਨੰਬਰ ਨੂੰ ਕਲਿੱਪਬੋਰਡ \'ਤੇ ਕਾਪੀ ਕੀਤਾ ਗਿਆ।"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"ਸਭ ਦੇਖੋ"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ਨੈੱਟਵਰਕਾਂ ਨੂੰ ਬਦਲਣ ਲਈ, ਈਥਰਨੈੱਟ ਨੂੰ ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"ਡੀਵਾਈਸ ਦੇ ਅਨੁਭਵ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ, ਐਪਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਕਿਸੇ ਵੀ ਸਮੇਂ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕਾਂ ਲਈ ਸਕੈਨ ਕਰ ਸਕਦੀਆਂ ਹਨ, ਭਾਵੇਂ ਵਾਈ-ਫਾਈ ਬੰਦ ਹੀ ਕਿਉਂ ਨਾ ਹੋਵੇ। ਤੁਸੀਂ ਇਸ ਨੂੰ ਵਾਈ‑ਫਾਈ ਸਕੈਨਿੰਗ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਬਦਲ ਸਕਦੇ ਹੋ। "<annotation id="link">"ਬਦਲੋ"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ਹਵਾਈ-ਜਹਾਜ਼ ਮੋਡ ਬੰਦ ਕਰੋ"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ਅੱਗੇ ਦਿੱਤੀ ਟਾਇਲ ਨੂੰ ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰਨਾ ਚਾਹੁੰਦੀ ਹੈ"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ਟਾਇਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ਟਾਇਲ ਸ਼ਾਮਲ ਨਾ ਕਰੋ"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ਵਰਤੋਂਕਾਰ ਚੁਣੋ"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲ ਰਹੀਆਂ ਐਪਾਂ"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ਬੰਦ ਕਰੋ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/tiles_states_strings.xml b/packages/SystemUI/res/values-pa/tiles_states_strings.xml
index d44add8..2403141c 100644
--- a/packages/SystemUI/res/values-pa/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pa/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"ਬੰਦ"</item>
<item msgid="460891964396502657">"ਚਾਲੂ"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"ਅਣਉਪਲਬਧ"</item>
+ <item msgid="5581384648880018330">"ਬੰਦ"</item>
+ <item msgid="8000850843692192257">"ਚਾਲੂ"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 0e8b97e..3d09c50 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -252,7 +252,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Brak dostępnych urządzeń"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Brak połączenia z Wi-Fi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Jasność"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Odwróć kolory"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Odwrócenie kolorów"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Więcej ustawień"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Ustawienia użytkownika"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Gotowe"</string>
@@ -757,7 +757,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Powiększanie pełnego ekranu"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Powiększ część ekranu"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Przełącz"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Przycisk ułatwień dostępu zastąpił gest ułatwień dostępu\n\n"<annotation id="link">"Wyświetl ustawienia"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Kliknij, aby otworzyć ułatwienia dostępu. Dostosuj lub zmień ten przycisk w Ustawieniach.\n\n"<annotation id="link">"Wyświetl ustawienia"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Przesuń przycisk do krawędzi, aby ukryć go tymczasowo"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Przenieś w lewy górny róg"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Przenieś w prawy górny róg"</string>
@@ -810,10 +810,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Ustawienia"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"Aplikacja <xliff:g id="APP_LABEL">%3$s</xliff:g> odtwarza utwór <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>)"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> z <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Odtwórz"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Wstrzymaj"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Poprzedni utwór"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Następny utwór"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Odtwórz"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otwórz aplikację <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Odtwórz utwór <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) w aplikacji <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Odtwórz utwór <xliff:g id="SONG_NAME">%1$s</xliff:g> w aplikacji <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Cofnij"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Przysuń się bliżej, aby odtwarzać na urządzeniu <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Odtwarzam na urządzeniu <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Nieaktywny, sprawdź aplikację"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nie znaleziono"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Element jest niedostępny"</string>
@@ -828,7 +835,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Wybrano 1 urządzenie"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Wybrane urządzenia: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(odłączono)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nie udało się połączyć. Spróbuj ponownie."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nie można przełączyć. Spróbuj ponownie."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sparuj nowe urządzenie"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numer kompilacji"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numer kompilacji został skopiowany do schowka."</string>
@@ -893,8 +900,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Pokaż wszystko"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Aby przełączać sieci, odłącz Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Aby zapewnić Ci większy komfort korzystania z urządzenia, aplikacje i usługi mogą nadal wyszukiwać sieci Wi-Fi w pobliżu nawet wtedy, gdy Wi-Fi jest wyłączone. Możesz to zmienić w ustawieniach skanowania Wi-Fi. "<annotation id="link">"Zmień"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Wyłącz tryb samolotowy"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Aplikacja <xliff:g id="APPNAME">%1$s</xliff:g> chce dodać do Szybkich ustawień ten kafelek"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj kafelek"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nie dodawaj kafelka"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Wybierz użytkownika"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikacje działające w tle"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zatrzymaj"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/tiles_states_strings.xml b/packages/SystemUI/res/values-pl/tiles_states_strings.xml
index 4d7ed15..30026e8 100644
--- a/packages/SystemUI/res/values-pl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pl/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Wyłączony"</item>
<item msgid="460891964396502657">"Włączony"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Brak dostępu"</item>
+ <item msgid="5581384648880018330">"Wyłączono"</item>
+ <item msgid="8000850843692192257">"Włączono"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 90cac8a..e166fa4 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Não há dispositivos disponíveis"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi não conectado"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brilho"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverter cores"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversão de cores"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Mais configurações"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Config. do usuário"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Concluído"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar toda a tela"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte da tela"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Trocar"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"O botão de acessibilidade substituiu o gesto de acessibilidade\n\n"<annotation id="link">"Veja as configurações"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toque para abrir os recursos de acessibilidade. Personalize ou substitua o botão nas Configurações.\n\n"<annotation id="link">"Ver configurações"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mova o botão para a borda para ocultá-lo temporariamente"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover para o canto superior esquerdo"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover para o canto superior direito"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Configurações"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"Tocando <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> no app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Iniciar"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pausar"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Faixa anterior"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Próxima faixa"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Iniciar"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abrir <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Tocar <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> no app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Tocar <xliff:g id="SONG_NAME">%1$s</xliff:g> no app <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Desfazer"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Aproxime os dispositivos para ouvir música no <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Reproduzido em <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selecionado"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> dispositivos selecionados"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(sem conexão)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Não foi possível conectar. Tente novamente."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Não foi possível mudar. Toque para tentar novamente."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desconecte o cabo Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para melhorar a experiência no dispositivo, os apps e serviços ainda podem procurar redes Wi-Fi a qualquer momento, mesmo quando o Wi-Fi estiver desativado. Você pode mudar essa opção nas configurações de busca por Wi-Fi. "<annotation id="link">"Mudar"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desativar modo avião"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"O app <xliff:g id="APPNAME">%1$s</xliff:g> quer adicionar o bloco a seguir às Configurações rápidas"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adicionar bloco"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicionar bloco"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecionar usuário"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps em execução em segundo plano"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
index ca1ef44..f874dd4 100644
--- a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Desativado"</item>
<item msgid="460891964396502657">"Ativado"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Indisponível"</item>
+ <item msgid="5581384648880018330">"Desativado"</item>
+ <item msgid="8000850843692192257">"Ativado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index e2d8433..808dd2b 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Sem dispositivos disponíveis"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi não ligado"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brilho"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverter cores"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversão de cores"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Mais definições"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Definições do utilizador"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Concluído"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar o ecrã inteiro"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte do ecrã"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Mudar"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"O botão Acessibilidade substituiu o gesto de acessibilidade\n\n"<annotation id="link">"Ver definições"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toque para abrir funcionalidades de acessibilidade. Personal. ou substitua botão em Defin.\n\n"<annotation id="link">"Ver defin."</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mova o botão para a extremidade para o ocultar temporariamente"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover p/ parte sup. esquerda"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover parte superior direita"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Definições"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> em reprodução a partir da app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Reproduzir"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pausar"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Faixa anterior"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Faixa seguinte"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproduzir"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abrir <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Reproduzir <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> a partir da app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Reproduzir <xliff:g id="SONG_NAME">%1$s</xliff:g> a partir da app <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Anular"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Aproxime-se para reproduzir no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"A reproduzir no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inativa. Consulte a app."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado."</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"O controlo está indisponível"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selecionado"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> dispositivos selecionados"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desligado)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Não foi possível ligar. Tente novamente."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Não é possível mudar. Toque para tentar novamente."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sincronize o novo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da compilação"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da compilação copiado para a área de transferência."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Veja tudo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desligue a Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para melhorar a experiência do dispositivo, as apps e os serviços podem continuar a procurar redes Wi-Fi em qualquer altura, mesmo quando o Wi-Fi está desativado. Pode alterar esta opção nas definições de procura de Wi-Fi. "<annotation id="link">"Alterar"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desative o modo de avião"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"A app <xliff:g id="APPNAME">%1$s</xliff:g> pretende adicionar o seguinte mosaico às Definições rápidas"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adicionar mosaico"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicion. mosaico"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecione utilizador"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps em execução em segundo plano"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
index 632db66..1e426e1 100644
--- a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Desativado"</item>
<item msgid="460891964396502657">"Ativado"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Indisponível"</item>
+ <item msgid="5581384648880018330">"Desligado"</item>
+ <item msgid="8000850843692192257">"Ligado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 90cac8a..e166fa4 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Não há dispositivos disponíveis"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi não conectado"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brilho"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverter cores"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversão de cores"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Mais configurações"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Config. do usuário"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Concluído"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar toda a tela"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte da tela"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Trocar"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"O botão de acessibilidade substituiu o gesto de acessibilidade\n\n"<annotation id="link">"Veja as configurações"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toque para abrir os recursos de acessibilidade. Personalize ou substitua o botão nas Configurações.\n\n"<annotation id="link">"Ver configurações"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mova o botão para a borda para ocultá-lo temporariamente"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover para o canto superior esquerdo"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover para o canto superior direito"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Configurações"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"Tocando <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> no app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Iniciar"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pausar"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Faixa anterior"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Próxima faixa"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Iniciar"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abrir <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Tocar <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> no app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Tocar <xliff:g id="SONG_NAME">%1$s</xliff:g> no app <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Desfazer"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Aproxime os dispositivos para ouvir música no <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Reproduzido em <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selecionado"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> dispositivos selecionados"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(sem conexão)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Não foi possível conectar. Tente novamente."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Não foi possível mudar. Toque para tentar novamente."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desconecte o cabo Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para melhorar a experiência no dispositivo, os apps e serviços ainda podem procurar redes Wi-Fi a qualquer momento, mesmo quando o Wi-Fi estiver desativado. Você pode mudar essa opção nas configurações de busca por Wi-Fi. "<annotation id="link">"Mudar"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Desativar modo avião"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"O app <xliff:g id="APPNAME">%1$s</xliff:g> quer adicionar o bloco a seguir às Configurações rápidas"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adicionar bloco"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Não adicionar bloco"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecionar usuário"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Apps em execução em segundo plano"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/tiles_states_strings.xml b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
index ca1ef44..f874dd4 100644
--- a/packages/SystemUI/res/values-pt/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Desativado"</item>
<item msgid="460891964396502657">"Ativado"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Indisponível"</item>
+ <item msgid="5581384648880018330">"Desativado"</item>
+ <item msgid="8000850843692192257">"Ativado"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 5c89fb1..0fdd176 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -251,7 +251,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Niciun dispozitiv disponibil"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Rețeaua Wi-Fi nu este conectată"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminozitate"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inversați culorile"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversarea culorilor"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Mai multe setări"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Setări de utilizator"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Terminat"</string>
@@ -752,7 +752,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Măriți tot ecranul"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Măriți o parte a ecranului"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Comutator"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Butonul de accesibilitate a înlocuit gestul de accesibilitate\n\n"<annotation id="link">"Vedeți setările"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Atingeți pentru a deschide funcțiile de accesibilitate. Personalizați sau înlocuiți butonul în Setări.\n\n"<annotation id="link">"Afișați setările"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mutați butonul spre margine pentru a-l ascunde temporar"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mutați în stânga sus"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mutați în dreapta sus"</string>
@@ -804,10 +804,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Setări"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> de la <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se redă în <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> din <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Redați"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Întrerupeți"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Melodia anterioară"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Melodia următoare"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Redați"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Deschideți <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Redați <xliff:g id="SONG_NAME">%1$s</xliff:g> de la <xliff:g id="ARTIST_NAME">%2$s</xliff:g> în <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Redați <xliff:g id="SONG_NAME">%1$s</xliff:g> în <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Anulați"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Apropiați-vă pentru a reda pe <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Se redă pe <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verificați aplicația"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nu s-a găsit"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Comanda este indisponibilă"</string>
@@ -822,7 +829,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"S-a selectat un dispozitiv"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"S-au selectat <xliff:g id="COUNT">%1$d</xliff:g> dispozitive"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(deconectat)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nu s-a putut conecta. Reîncercați."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nu se poate comuta. Atingeți pentru a încerca din nou."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Asociați un nou dispozitiv"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numărul versiunii"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numărul versiunii s-a copiat în clipboard."</string>
@@ -887,8 +894,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Afișează-le pe toate"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pentru a schimba rețeaua, deconectați ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Pentru a îmbunătăți experiența cu dispozitivul, aplicațiile și serviciile pot să caute în continuare rețele Wi‑Fi chiar și atunci când conexiunea Wi-Fi este dezactivată. Puteți să schimbați acest aspect din setările pentru căutarea de rețele Wi-Fi. "<annotation id="link">"Schimbați"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Dezactivați modul Avion"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vrea să adauge următorul card la Setări rapide"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adăugați un card"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nu adăugați un card"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Alegeți utilizatorul"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplicațiile rulează în fundal"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Opriți"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/tiles_states_strings.xml b/packages/SystemUI/res/values-ro/tiles_states_strings.xml
index eea69f8..c63e7fe 100644
--- a/packages/SystemUI/res/values-ro/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ro/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Dezactivat"</item>
<item msgid="460891964396502657">"Activat"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Indisponibil"</item>
+ <item msgid="5581384648880018330">"Dezactivat"</item>
+ <item msgid="8000850843692192257">"Activat"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index ecff557..2b06d10 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -252,7 +252,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Нет доступных устройств"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Нет подключения к сети Wi-Fi."</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яркость"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Обратные цвета"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инверсия цветов"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Настройки"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Пользовательские настройки"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
@@ -757,7 +757,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Увеличение всего экрана"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увеличить часть экрана"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Переключить"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Жест заменен на кнопку специальных возможностей\n\n"<annotation id="link">"Открыть настройки"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Нажмите, чтобы открыть спец. возможности. Настройте или замените эту кнопку в настройках.\n\n"<annotation id="link">"Настройки"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Чтобы временно скрыть кнопку, переместите ее к краю экрана"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Перенести в левый верхний угол"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Перенести в правый верхний угол"</string>
@@ -810,10 +810,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Настройки"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"Воспроизводится медиафайл \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" (исполнитель: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) из приложения \"<xliff:g id="APP_LABEL">%3$s</xliff:g>\"."</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> из <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Воспроизвести"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Приостановить"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Предыдущий трек"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Следующий трек"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Воспроизведение"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Открыть приложение \"<xliff:g id="APP_LABEL">%1$s</xliff:g>\""</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Воспроизвести медиафайл \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" (исполнитель: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) из приложения \"<xliff:g id="APP_LABEL">%3$s</xliff:g>\""</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Воспроизвести медиафайл \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" из приложения \"<xliff:g id="APP_LABEL">%2$s</xliff:g>\""</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Отменить"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Чтобы включить музыку на устройстве \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\", подойдите к нему ближе."</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Воспроизводится на устройстве \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\"."</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Нет ответа. Проверьте приложение."</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не найдено."</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Управление недоступно"</string>
@@ -828,7 +835,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Выбрано 1 устройство"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Выбрано устройств: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(нет подключения)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не удалось подключиться. Повторите попытку."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Не удается переключиться. Нажмите, чтобы повторить попытку."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Подключить новое устройство"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер сборки"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номер сборки скопирован в буфер обмена."</string>
@@ -893,8 +900,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Показать все"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Чтобы переключиться между сетями, отключите кабель Ethernet."</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Чтобы улучшать работу устройства, приложения и сервисы могут искать беспроводные сети в любое время, даже если вы отключили Wi‑Fi. Чтобы запретить это, отключите поиск сетей Wi‑Fi. "<annotation id="link">"Открыть настройки"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Отключить режим полета"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Приложение \"<xliff:g id="APPNAME">%1$s</xliff:g>\" хочет добавить в меню \"Быстрые настройки\" указанный параметр."</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Добавить параметр"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Не добавлять"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Выберите профиль"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Приложения, работающие в фоновом режиме"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Остановить"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/tiles_states_strings.xml b/packages/SystemUI/res/values-ru/tiles_states_strings.xml
index 6bc486b..ae31f32 100644
--- a/packages/SystemUI/res/values-ru/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ru/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Отключен"</item>
<item msgid="460891964396502657">"Включен"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Недоступно"</item>
+ <item msgid="5581384648880018330">"Отключено"</item>
+ <item msgid="8000850843692192257">"Включено"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index b24db63..bdd41a5 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"උපාංග නොතිබේ"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi සම්බන්ධ නොවීය"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"දීප්තිමත් බව"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"වර්ණ යටිකුරු කරන්න"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"වර්ණ අපවර්තනය"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"තව සැකසීම්"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"පරිශීලක සැකසීම්"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"නිමයි"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"පූර්ණ තිරය විශාලනය කරන්න"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"තිරයේ කොටසක් විශාලනය කරන්න"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ස්විචය"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"ප්රවේශ්යතා බොත්තම ප්රවේශ්යතා ඉංගිතය ප්රතිස්ථාපනය කළේය\n\n"<annotation id="link">"සැකසීම් බලන්න"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ප්රවේශ්යතා විශේෂාංග විවෘත කිරීමට තට්ටු කරන්න. සැකසීම් තුළ මෙම බොත්තම අභිරුචිකරණය හෝ ප්රතිස්ථාපනය කරන්න.\n\n"<annotation id="link">"සැකසීම් බලන්න"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"එය තාවකාලිකව සැඟවීමට බොත්තම දාරයට ගෙන යන්න"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ඉහළ වමට ගෙන යන්න"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ඉහළ දකුණට ගෙන යන්න"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"සැකසීම්"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>ගේ <xliff:g id="SONG_NAME">%1$s</xliff:g> ගීතය <xliff:g id="APP_LABEL">%3$s</xliff:g> වෙතින් ධාවනය වෙමින් පවතී"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>කින් <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"වාදනය කරන්න"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"විරාම ගන්වන්න"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"පෙර ඛණ්ඩය"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"ඊළඟ ඛණ්ඩය"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"වාදනය කරන්න"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> විවෘත කරන්න"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>ගේ <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%3$s</xliff:g> වෙතින් වාදනය කරන්න"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%2$s</xliff:g> වෙතින් වාදනය කරන්න"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"පසුගමනය කරන්න"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> හි වාදනය කිරීමට වඩාත් ළං වන්න"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> හි වාදනය කරමින්"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"අක්රියයි, යෙදුම පරීක්ෂා කරන්න"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"හමු නොවිණි"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"පාලනය ලබා ගත නොහැකිය"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"උපාංග 1ක් තෝරන ලදී"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"උපාංග <xliff:g id="COUNT">%1$d</xliff:g>ක් තෝරන ලදී"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(විසන්ධි විය)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"සම්බන්ධ වීමට නොහැකි විය. නැවත උත්සාහ කරන්න."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"මාරු කිරීමට නොහැකිය. නැවත උත්සාහ කිරීමට තට්ටු කරන්න."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"නව උපාංගය යුගල කරන්න"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"නිමැවුම් අංකය"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"නිමැවුම් අංකය පසුරු පුවරුවට පිටපත් කරන ලදි."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"සියල්ල බලන්න"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ජාල මාරු කිරීමට, ඊතර්නෙට් විසන්ධි කරන්න"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"උපාංග අත්දැකීම වැඩි දියුණු කිරිමට, Wi‑Fi ක්රියාවිරහිත විට පවා, ඕනෑම අවස්ථාවක Wi‑Fi ජාල සඳහා ස්කෑන් කිරීමට යෙදුම් සහ සේවාවලට හැකිය. ඔබට මෙය Wi‑Fi ස්කෑන් කිරීමේ සැකසීම් තුළ වෙනස් කළ හැකිය. "<annotation id="link">"වෙනස් කරන්න"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ගුවන් යානා ප්රකාරය ක්රියාවිරහිත කරන්න"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> හට ක්ෂණික සැකසීම් වෙත පහත ටයිල් එක් කිරීමට අවශ්යයි"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ටයිල් එක් කරන්න"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ටයිල් එක් නොකරන්න"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"පරිශීලක තෝරන්න"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"පසුබිමින් ධාවනය වෙමින් පවතින යෙදුම්"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"නවත්වන්න"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/tiles_states_strings.xml b/packages/SystemUI/res/values-si/tiles_states_strings.xml
index 9445457..fa78ccc 100644
--- a/packages/SystemUI/res/values-si/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-si/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"ක්රියාවිරහිතයි"</item>
<item msgid="460891964396502657">"ක්රියාත්මකයි"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"නොමැත"</item>
+ <item msgid="5581384648880018330">"ක්රියාවිරහිතයි"</item>
+ <item msgid="8000850843692192257">"ක්රියාත්මකයි"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 5ab4026..0838f65 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -252,7 +252,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nie sú k dispozícii žiadne zariadenia"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Sieť Wi‑Fi nie je pripojená"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Jas"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverzia farieb"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzia farieb"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Ďalšie nastavenia"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Používateľské nastavenia"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Hotovo"</string>
@@ -757,7 +757,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Zväčšenie celej obrazovky"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zväčšiť časť obrazovky"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Prepnúť"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Tlačidlo dostupnosti nahradilo gesto dostupnosti\n\n"<annotation id="link">"Zobraziť nastavenia"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Funkcie dostupnosti otvoríte klepnutím. Tlačidlo prispôsobte alebo nahraďte v Nastav.\n\n"<annotation id="link">"Zobraz. nast."</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Ak chcete tlačidlo dočasne skryť, presuňte ho k okraju"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Presunúť doľava nahor"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Presunúť doprava nahor"</string>
@@ -810,10 +810,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavenia"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> sa prehráva z aplikácie <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> z <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Prehrať"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pozastaviť"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Predchádzajúca skladba"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Ďalšia skladba"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Prehrať"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otvoriť <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Prehrať skladbu <xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> z aplikácie <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Prehrať skladbu <xliff:g id="SONG_NAME">%1$s</xliff:g> z aplikácie <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Späť"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Ak chcete prehrávať v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>, priblížte sa"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Prehráva sa v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktívne, preverte aplikáciu"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nenájdené"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládač nie je k dispozícii"</string>
@@ -828,7 +835,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 vybrané zariadenie"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Počet vybraných zariadení: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(odpojené)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nepodarilo sa pripojiť. Skúste to znova."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nedá sa prepnúť. Zopakujte klepnutím."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovať nové zariadenie"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo zostavy"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Číslo zostavy bolo skopírované do schránky."</string>
@@ -893,8 +900,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Zobraziť všetko"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ak chcete prepnúť siete, odpojte ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Aplikácie a služby môžu kedykoľvek vyhľadávať siete Wi‑Fi (a to aj vtedy, keď je pripojenie Wi‑Fi vypnuté), čím zlepšujú prostredie v zariadení. Môžete to zmeniť v nastaveniach vyhľadávania sietí Wi‑Fi. "<annotation id="link">"Zmeniť"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Vypnúť režim v lietadle"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Aplikácia <xliff:g id="APPNAME">%1$s</xliff:g> chce pridať do rýchlych nastavení túto kartu"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Pridať kartu"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nepridať kartu"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Vyberte používateľa"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikácie spustené na pozadí"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ukončiť"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/tiles_states_strings.xml b/packages/SystemUI/res/values-sk/tiles_states_strings.xml
index b7d37c8..1920f04 100644
--- a/packages/SystemUI/res/values-sk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sk/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Vypnuté"</item>
<item msgid="460891964396502657">"Zapnuté"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Nedostupné"</item>
+ <item msgid="5581384648880018330">"Vypnuté"</item>
+ <item msgid="8000850843692192257">"Zapnuté"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index f00bf38..e497d51 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -252,7 +252,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Na voljo ni nobene naprave"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Povezava Wi-Fi ni vzpostavljena"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Svetlost"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverzija barv"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija barv"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Več nastavitev"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Uporabniške nastavitve"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Končano"</string>
@@ -757,7 +757,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Povečanje celotnega zaslona"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Povečava dela zaslona"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Stikalo"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Gumb za funkcije za ljudi s posebnimi potrebami je zamenjal pripadajočo potezo.\n\n"<annotation id="link">"Ogled nastavitev"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dotaknite se za funkcije za ljudi s posebnimi potrebami. Ta gumb lahko prilagodite ali zamenjate v nastavitvah.\n\n"<annotation id="link">"Ogled nastavitev"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Če želite gumb začasno skriti, ga premaknite ob rob."</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Premakni zgoraj levo"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Premakni zgoraj desno"</string>
@@ -810,10 +810,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavitve"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"Skladba <xliff:g id="SONG_NAME">%1$s</xliff:g> izvajalca <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se predvaja iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> od <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Predvajaj"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Začasno zaustavi"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Prejšnja skladba"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Naslednja skladba"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Predvajaj"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Odpri aplikacijo <xliff:g id="APP_LABEL">%1$s</xliff:g>."</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Predvajaj skladbo <xliff:g id="SONG_NAME">%1$s</xliff:g> izvajalca <xliff:g id="ARTIST_NAME">%2$s</xliff:g> iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Predvajaj skladbo <xliff:g id="SONG_NAME">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_LABEL">%2$s</xliff:g>."</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Razveljavi"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Za predvajanje v napravi <xliff:g id="DEVICENAME">%1$s</xliff:g> bolj približajte telefon."</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Predvajanje v napravi <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, poglejte aplikacijo"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ni mogoče najti"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolnik ni na voljo"</string>
@@ -828,7 +835,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Izbrana je ena naprava"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Izbranih je toliko naprav: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(povezava je prekinjena)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Povezave ni bilo mogoče vzpostaviti. Poskusite znova."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Preklop ni mogoč. Če želite poskusiti znova, se dotaknite."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Seznanitev nove naprave"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Delovna različica"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Delovna različica je bila kopirana v odložišče."</string>
@@ -893,8 +900,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Prikaz vseh omrežij"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Če želite preklopiti omrežje, prekinite ethernetno povezavo."</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Za izboljšano izkušnjo pri uporabi naprave lahko aplikacije in storitve kadar koli iščejo omrežja Wi‑Fi, tudi ko je Wi‑Fi izklopljen. To lahko spremenite v nastavitvah iskanja omrežij Wi-Fi. "<annotation id="link">"Spremeni"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Izklopi način za letalo"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Aplikacija <xliff:g id="APPNAME">%1$s</xliff:g> želi dodati to ploščico v hitre nastavitve."</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj ploščico"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne dodaj ploščice"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Izberite uporabnika"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikacije z izvajanjem v ozadju"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ustavi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/tiles_states_strings.xml b/packages/SystemUI/res/values-sl/tiles_states_strings.xml
index 28e3917..924ec58 100644
--- a/packages/SystemUI/res/values-sl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sl/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Izklopljeno"</item>
<item msgid="460891964396502657">"Vklopljeno"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Ni na voljo"</item>
+ <item msgid="5581384648880018330">"Izklopljeno"</item>
+ <item msgid="8000850843692192257">"Vklopljeno"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 413bcec..d6d5047 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Nuk ofrohet për përdorim asnjë pajisje"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi nuk është lidhur"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ndriçimi"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Shkëmbe ngjyrat"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Anasjellja e ngjyrës"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Cilësime të tjera"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Cilësimet e përdoruesit"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"U krye"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Zmadho ekranin e plotë"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zmadho një pjesë të ekranit"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Ndërro"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Butoni i qasshmërisë zëvendësoi gjestin e qasshmërisë\n\n"<annotation id="link">"Shiko cilësimet"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Trokit dhe hap veçoritë e qasshmërisë. Modifiko ose ndërro butonin te \"Cilësimet\".\n\n"<annotation id="link">"Shih cilësimet"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Zhvendose butonin në skaj për ta fshehur përkohësisht"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Zhvendos lart majtas"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Zhvendos lart djathtas"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Cilësimet"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> nga <xliff:g id="ARTIST_NAME">%2$s</xliff:g> po luhet nga <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> nga <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Luaj"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Vendos në pauzë"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Pjesa muzikore e mëparshme"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Pjesa tjetër muzikore"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Luaj"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Hap <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Luaj <xliff:g id="SONG_NAME">%1$s</xliff:g> nga <xliff:g id="ARTIST_NAME">%2$s</xliff:g> nga <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Luaj <xliff:g id="SONG_NAME">%1$s</xliff:g> nga <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Zhbëj"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Afrohu për të luajtur në <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Po luhet në <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Joaktive, kontrollo aplikacionin"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Nuk u gjet"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolli është i padisponueshëm"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 pajisje e zgjedhur"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> pajisje të zgjedhura"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(shkëputur)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nuk mund të lidhej. Provo sërish."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nuk mund të ndërrohet. Trokit për të provuar përsëri."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Çifto pajisjen e re"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numri i ndërtimit"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numri i ndërtimit u kopjua te kujtesa e fragmenteve"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Shiko të gjitha"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Për të ndërruar rrjetet, shkëput Ethernet-in"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Për të përmirësuar përvojën e pajisjes, aplikacionet dhe shërbimet mund të vazhdojnë të skanojnë për rrjete Wi-Fi në çdo kohë, edhe kur Wi-Fi është joaktiv. Mund ta ndryshosh këtë te cilësimet e skanimit të Wi-Fi. "<annotation id="link">"Ndrysho"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Çaktivizo modalitetin e aeroplanit"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> dëshiron të shtojë pllakëzën e mëposhtme te \"Cilësimet e shpejta\""</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Shto një pllakëz"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Mos e shto pllakëzën"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Zgjidh përdoruesin"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Aplikacionet që ekzekutohen në sfond"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ndalo"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/tiles_states_strings.xml b/packages/SystemUI/res/values-sq/tiles_states_strings.xml
index 6643e04..34879ce 100644
--- a/packages/SystemUI/res/values-sq/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sq/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Joaktiv"</item>
<item msgid="460891964396502657">"Aktiv"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Nuk ofrohet"</item>
+ <item msgid="5581384648880018330">"Joaktiv"</item>
+ <item msgid="8000850843692192257">"Aktiv"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index b5cd94b..dae3070 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -251,7 +251,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Није доступан ниједан уређај"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"WiFi није повезан"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Осветљеност"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Обрни боје"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инверзија боја"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Још подешавања"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Корисничка подешавања"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
@@ -752,7 +752,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Увећајте цео екран"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увећајте део екрана"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Пређи"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Дугме Приступачност је заменило покрет за приступачност\n\n"<annotation id="link">"Прикажи подешавања"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Додирните за функције приступачности. Прилагодите или замените ово дугме у Подешавањима.\n\n"<annotation id="link">"Подешавања"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Померите дугме до ивице да бисте га привремено сакрили"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Премести горе лево"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Премести горе десно"</string>
@@ -804,10 +804,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Подешавања"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> извођача <xliff:g id="ARTIST_NAME">%2$s</xliff:g> се пушта из апликације <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> од <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Пусти"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Паузирај"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Претходна песма"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Следећа песма"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Пусти"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Отворите <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Пустите <xliff:g id="SONG_NAME">%1$s</xliff:g> извођача <xliff:g id="ARTIST_NAME">%2$s</xliff:g> из апликације <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Пустите <xliff:g id="SONG_NAME">%1$s</xliff:g> из апликације <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Опозови"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Приближите да бисте пуштали музику на: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Пушта се на: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно. Видите апликацију"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Није пронађено"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Контрола није доступна"</string>
@@ -822,7 +829,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Изабран је 1 уређај"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Изабраних уређаја: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(веза је прекинута)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Повезивање није успело. Пробајте поново."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Пребацивање није успело. Пробајте поново."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Упари нови уређај"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Број верзије"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Број верзије је копиран у привремену меморију."</string>
@@ -887,8 +894,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Погледајте све"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Да бисте променили мрежу, прекините етернет везу"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Ради бољег доживљаја уређаја, апликације и услуге и даље могу да траже WiFi мреже у било ком тренутку, чак и када је WiFi искључен. То можете да промените у подешавањима WiFi скенирања. "<annotation id="link">"Промените"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Искључите режим рада у авиону"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> жели да дода следећу плочицу у Брза подешавања"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Додај плочицу"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Не додај плочицу"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Изаберите корисника"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Апликације покренуте у позадини"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Заустави"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/tiles_states_strings.xml b/packages/SystemUI/res/values-sr/tiles_states_strings.xml
index 63542da..855b84b 100644
--- a/packages/SystemUI/res/values-sr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sr/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Искључено"</item>
<item msgid="460891964396502657">"Укључено"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Недоступно"</item>
+ <item msgid="5581384648880018330">"Искључено"</item>
+ <item msgid="8000850843692192257">"Укључено"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 1bae752..668e7d3 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Inga tillgängliga enheter"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Ej ansluten till wifi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ljusstyrka"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invertera färger"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Färginvertering"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Fler inställningar"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Användarinställningar"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Klart"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Förstora hela skärmen"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Förstora en del av skärmen"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Reglage"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Tillgänglighetsknappen har ersatt tillgänglighetsrörelsen\n\n"<annotation id="link">"Visa inställningarna"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tryck för att öppna tillgänglighetsfunktioner. Anpassa/ersätt knappen i Inställningar.\n\n"<annotation id="link">"Inställningar"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Flytta knappen till kanten för att dölja den tillfälligt"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Flytta högst upp till vänster"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Flytta högst upp till höger"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Inställningar"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> med <xliff:g id="ARTIST_NAME">%2$s</xliff:g> spelas upp från <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> av <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Spela upp"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pausa"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Föregående spår"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Nästa spår"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Spela upp"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Öppna <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Spela upp <xliff:g id="SONG_NAME">%1$s</xliff:g> med <xliff:g id="ARTIST_NAME">%2$s</xliff:g> från <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Spela upp <xliff:g id="SONG_NAME">%1$s</xliff:g> från <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Ångra"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Flytta närmare för att spela upp på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Spelas upp på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv, kolla appen"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Hittades inte"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Styrning är inte tillgänglig"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 enhet har valts"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> enheter har valts"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(frånkopplad)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Det gick inte att ansluta. Försök igen."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Misslyckat byte. Tryck och försök igen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parkoppla en ny enhet"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versionsnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versionsnumret har kopierats till urklipp."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Visa alla"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Koppla bort Ethernet för att växla nätverk"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"I syfte att förbättra upplevelsen med enheten kan appar och tjänster fortfarande söka efter wifi-nätverk när som helst, även om wifi har inaktiverats. "<annotation id="link">"Ändra"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Inaktivera flygplansläge"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vill lägga till följande ruta i snabbinställningarna"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Lägg till ruta"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Lägg inte till ruta"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Välj användare"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Appar som körs i bakgrunden"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stoppa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/tiles_states_strings.xml b/packages/SystemUI/res/values-sv/tiles_states_strings.xml
index e009e0b..b071b91 100644
--- a/packages/SystemUI/res/values-sv/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sv/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Av"</item>
<item msgid="460891964396502657">"På"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Inte tillgänglig"</item>
+ <item msgid="5581384648880018330">"Av"</item>
+ <item msgid="8000850843692192257">"På"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index c4e9540..fad086ad 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Hakuna vifaa vilivyopatikana"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi haijaunganishwa"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ung\'avu"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Pindua rangi"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ugeuzaji rangi"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Mipangilio zaidi"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Mipangilio ya mtumiaji"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Nimemaliza"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Kuza skrini nzima"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Kuza sehemu ya skrini"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Swichi"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Kitufe cha zana za ufikivu kimechukua nafasi ya ishara ya ufikivu\n\n"<annotation id="link">"Angalia mipangilio"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Gusa ili ufungue vipengele vya ufikivu. Weka mapendeleo au ubadilishe kitufe katika Mipangilio.\n\n"<annotation id="link">"Angalia mipangilio"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Sogeza kitufe kwenye ukingo ili ukifiche kwa muda"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Sogeza juu kushoto"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Sogeza juu kulia"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Mipangilio"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ulioimbwa na <xliff:g id="ARTIST_NAME">%2$s</xliff:g> unacheza katika <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> kati ya <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Cheza"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Simamisha"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Wimbo uliotangulia"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Wimbo unaofuata"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Cheza"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Fungua <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Cheza <xliff:g id="SONG_NAME">%1$s</xliff:g> ulioimbwa na <xliff:g id="ARTIST_NAME">%2$s</xliff:g> katika <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Cheza <xliff:g id="SONG_NAME">%1$s</xliff:g> katika <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Tendua"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Sogea karibu ili ucheze kwenye <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Inacheza kwenye <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Haitumiki, angalia programu"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Hakipatikani"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kidhibiti hakipatikani"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Umechagua kifaa 1"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Umechagua vifaa <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(imetenganishwa)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Imeshindwa kuunganisha. Jaribu tena."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Imeshindwa kubadilisha. Gusa ili ujaribu tena."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Oanisha kifaa kipya"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nambari ya muundo"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nambari ya muundo imewekwa kwenye ubao wa kunakili."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Angalia yote"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ili kubadili mitandao, tenganisha ethaneti"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Ili kuboresha hali ya matumizi ya kifaa, programu na huduma bado zinaweza kutafuta mitandao ya Wi‑Fi wakati wowote, hata wakati umezima Wi‑Fi. Unaweza kubadilisha mipangilio hii katika mipangilio ya kutafuta Wi-Fi. "<annotation id="link">"Badilisha"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Zima hali ya ndegeni"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ingependa kuongeza kigae kifuatacho kwenye Mipangilio ya Haraka"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ongeza kigae"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Usiongeze kigae"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Chagua mtumiaji"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Programu zinazotumika chinichini"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Simamisha"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/tiles_states_strings.xml b/packages/SystemUI/res/values-sw/tiles_states_strings.xml
index beabdc4..a92c7f9 100644
--- a/packages/SystemUI/res/values-sw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sw/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Imezimwa"</item>
<item msgid="460891964396502657">"Imewashwa"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Haipatikani"</item>
+ <item msgid="5581384648880018330">"Imezimwa"</item>
+ <item msgid="8000850843692192257">"Imewashwa"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index f8af3a6..10912be 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"சாதனங்கள் இல்லை"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"வைஃபை இணைக்கப்படவில்லை"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ஒளிர்வு"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"வண்ணங்களை மாற்று"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"கலர் இன்வெர்ஷன்"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"அமைப்பில் மாற்று"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"பயனர் அமைப்புகள்"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"முடிந்தது"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"முழுத்திரையைப் பெரிதாக்கும்"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"திரையின் ஒரு பகுதியைப் பெரிதாக்கும்"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ஸ்விட்ச்"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"அணுகல்தன்மை பட்டன் இப்போது அணுகல்தன்மை சைகையாக மாற்றப்பட்டுள்ளது\n\n"<annotation id="link">"அமைப்புகளில் காண்க"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"அணுகல்தன்மை அம்சத்தை திறக்க தட்டவும். அமைப்பில் பட்டனை பிரத்தியேகமாக்கலாம்/மாற்றலாம்.\n\n"<annotation id="link">"அமைப்பில் காண்க"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"பட்டனைத் தற்காலிகமாக மறைக்க ஓரத்திற்கு நகர்த்தும்"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"மேலே இடதுபுறத்திற்கு நகர்த்து"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"மேலே வலதுபுறத்திற்கு நகர்த்து"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"அமைப்புகள்"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> இன் <xliff:g id="SONG_NAME">%1$s</xliff:g> பாடல் <xliff:g id="APP_LABEL">%3$s</xliff:g> ஆப்ஸில் பிளேயாகிறது"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> / <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"பிளே செய்"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"இடைநிறுத்து"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"முந்தைய டிராக்"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"அடுத்த டிராக்"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"இயக்குதல்"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ஆப்ஸைத் திறங்கள்"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> இன் <xliff:g id="SONG_NAME">%1$s</xliff:g> பாடலை <xliff:g id="APP_LABEL">%3$s</xliff:g> ஆப்ஸில் பிளேசெய்"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="SONG_NAME">%1$s</xliff:g> பாடலை <xliff:g id="APP_LABEL">%2$s</xliff:g> ஆப்ஸில் பிளேசெய்"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"செயல்தவிர்"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்தில் பிளே செய்ய உங்கள் சாதனத்தை அருகில் எடுத்துச் செல்லவும்"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்தில் பிளே ஆகிறது"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"செயலில் இல்லை , சரிபார்க்கவும்"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"இல்லை"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"கட்டுப்பாடு இல்லை"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 சாதனம் தேர்ந்தெடுக்கப்பட்டுள்ளது"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> சாதனங்கள் தேர்ந்தெடுக்கப்பட்டுள்ளன"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(துண்டிக்கப்பட்டது)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"இணைக்க முடியவில்லை. மீண்டும் முயலவும்."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"இணைக்க முடியவில்லை. மீண்டும் முயல தட்டவும்."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"புதிய சாதனத்தை இணைத்தல்"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"பதிப்பு எண்"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"பதிப்பு எண் கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"அனைத்தையும் காட்டு"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"நெட்வொர்க்குகளை மாற்ற ஈதர்நெட் இணைப்பைத் துண்டிக்கவும்"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"சாதன அனுபவத்தை மேம்படுத்த, வைஃபை ஆஃப் செய்யப்பட்டிருந்தாலும்கூட எந்த நேரத்திலும் ஆப்ஸும் சேவைகளும் வைஃபை நெட்வொர்க்குகளைத் தேடலாம். வைஃபை ஸ்கேனிங் அமைப்புகளில் இதை மாற்றிக் கொள்ளலாம். "<annotation id="link">"மாற்று"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"விமானப் பயன்முறையை முடக்கும்"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"விரைவு அமைப்புகளில் பின்வரும் கட்டத்தைச் சேர்க்க <xliff:g id="APPNAME">%1$s</xliff:g> ஆப்ஸ் விரும்புகிறது"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"கட்டத்தைச் சேர்"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"கட்டத்தை சேர்க்காதே"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"பயனரைத் தேர்வுசெய்க"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"பின்னணியில் இயங்கும் ஆப்ஸ்"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"நிறுத்து"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta/tiles_states_strings.xml b/packages/SystemUI/res/values-ta/tiles_states_strings.xml
index 9f2a2e9..f3ba1a1 100644
--- a/packages/SystemUI/res/values-ta/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ta/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"முடக்கப்பட்டுள்ளது"</item>
<item msgid="460891964396502657">"இயக்கப்பட்டுள்ளது"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"கிடைக்கவில்லை"</item>
+ <item msgid="5581384648880018330">"ஆஃப்"</item>
+ <item msgid="8000850843692192257">"ஆன்"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 77d076d..abba928 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"పరికరాలు ఏవీ అందుబాటులో లేవు"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi‑Fi కనెక్ట్ కాలేదు"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ప్రకాశం"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"కలర్ మార్పిడి"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"కలర్ మార్పిడి"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"మరిన్ని సెట్టింగ్లు"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"యూజర్ సెట్టింగ్లు"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"పూర్తయింది"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ఫుల్ స్క్రీన్ను మ్యాగ్నిఫై చేయండి"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"స్క్రీన్లో భాగాన్ని మాగ్నిఫై చేయండి"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"స్విచ్ చేయి"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"యాక్సెసిబిలిటీ బటన్, యాక్సెసిబిలిటీ సంజ్ఞను భర్తీ చేసింది\n\n"<annotation id="link">"సెట్టింగ్లను చూడండి"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"యాక్సెసిబిలిటీ ఫీచర్లను తెరవడానికి ట్యాప్ చేయండి. సెట్టింగ్లలో ఈ బటన్ను అనుకూలీకరించండి లేదా రీప్లేస్ చేయండి.\n\n"<annotation id="link">"వీక్షణ సెట్టింగ్లు"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"తాత్కాలికంగా దానిని దాచడానికి బటన్ను చివరకు తరలించండి"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ఎగువ ఎడమ వైపునకు తరలించు"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ఎగువ కుడి వైపునకు తరలించు"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"సెట్టింగ్లు"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> పాడిన <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%3$s</xliff:g> నుండి ప్లే అవుతోంది"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>లో <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"ప్లే చేయండి"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"పాజ్ చేయండి"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"మునుపటి ట్రాక్"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"తర్వాతి ట్రాక్"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ప్లే చేయండి"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g>ను తెరవండి"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> నుండి <xliff:g id="ARTIST_NAME">%2$s</xliff:g> పాడిన <xliff:g id="SONG_NAME">%1$s</xliff:g>ను ప్లే చేయండి"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> నుండి <xliff:g id="SONG_NAME">%1$s</xliff:g>ను ప్లే చేయండి"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"చర్య రద్దు"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g>లో ప్లే చేయడానికి దగ్గరగా వెళ్లండి"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g>లో ప్లే అవుతోంది"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ఇన్యాక్టివ్, యాప్ చెక్ చేయండి"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"కనుగొనబడలేదు"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"కంట్రోల్ అందుబాటులో లేదు"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 పరికరం ఎంచుకోబడింది"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> పరికరాలు ఎంచుకోబడ్డాయి"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(డిస్కనెక్ట్ అయ్యింది)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"కనెక్ట్ చేయడం సాధ్యపడలేదు. మళ్లీ ట్రై చేయండి."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"స్విచ్ చేయడం సాధ్యం కాదు. మళ్ళీ ట్రై చేయడానికి ట్యాప్ చేయండి."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"కొత్త పరికరాన్ని పెయిర్ చేయండి"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"బిల్డ్ నంబర్"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"బిల్డ్ నంబర్, క్లిప్బోర్డ్కు కాపీ చేయబడింది."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"అన్నీ చూడండి"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"నెట్వర్క్లను మార్చడానికి, ఈథర్నెట్ను డిస్కనెక్ట్ చేయండి"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"పరికర అనుభవాన్ని మెరుగుపరచడానికి, Wi‑Fi ఆఫ్లో ఉన్నప్పుడు కూడా, ఏ సమయంలో అయినా ఇప్పటికీ Wi‑Fi నెట్వర్క్ల కోసం యాప్లు, సర్వీస్లు స్కాన్ చేయగలవు. మీరు దీనిని Wi‑Fi స్కానింగ్ సెట్టింగ్లలో మార్చవచ్చు. "<annotation id="link">"మార్చండి"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"విమానం మోడ్ను ఆఫ్ చేయండి"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"కింది టైల్ను క్విక్ సెట్టింగ్లకు జోడించడానికి <xliff:g id="APPNAME">%1$s</xliff:g> అనుమతి కోరుతోంది"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"టైల్ను జోడించండి"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"టైల్ను జోడించవద్దు"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"యూజర్ను ఎంచుకోండి"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"యాప్లు బ్యాక్గ్రౌండ్లో రన్ అవుతున్నాయి"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ఆపివేయండి"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/tiles_states_strings.xml b/packages/SystemUI/res/values-te/tiles_states_strings.xml
index c23436f..bed919f 100644
--- a/packages/SystemUI/res/values-te/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-te/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"ఆఫ్"</item>
<item msgid="460891964396502657">"ఆన్"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"అందుబాటులో లేదు"</item>
+ <item msgid="5581384648880018330">"ఆఫ్లో ఉంది"</item>
+ <item msgid="8000850843692192257">"ఆన్లో ఉంది"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 15215e3..a586f76f 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"ไม่มีอุปกรณ์ที่สามารถใช้ได้"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ไม่ได้เชื่อมต่อ Wi-Fi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ความสว่าง"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"กลับสี"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"การกลับสี"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"การตั้งค่าเพิ่มเติม"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"การตั้งค่าของผู้ใช้"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"เสร็จสิ้น"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ขยายเป็นเต็มหน้าจอ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ขยายบางส่วนของหน้าจอ"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"เปลี่ยน"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"ปุ่มการช่วยเหลือพิเศษแทนที่ท่าทางสัมผัสการช่วยเหลือพิเศษแล้ว\n\n"<annotation id="link">"ดูการตั้งค่า"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"แตะเพื่อเปิดฟีเจอร์การช่วยเหลือพิเศษ ปรับแต่งหรือแทนที่ปุ่มนี้ในการตั้งค่า\n\n"<annotation id="link">"ดูการตั้งค่า"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ย้ายปุ่มไปที่ขอบเพื่อซ่อนชั่วคราว"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ย้ายไปด้านซ้ายบน"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ย้ายไปด้านขวาบน"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"การตั้งค่า"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"กำลังเปิดเพลง <xliff:g id="SONG_NAME">%1$s</xliff:g> ของ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> จาก <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> จาก <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"เล่น"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"หยุดชั่วคราว"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"แทร็กก่อนหน้า"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"เพลงถัดไป"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"เล่น"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"เปิด <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"เปิดเพลง <xliff:g id="SONG_NAME">%1$s</xliff:g> ของ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> จาก <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"เปิดเพลง <xliff:g id="SONG_NAME">%1$s</xliff:g> จาก <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"เลิกทำ"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"ขยับเข้ามาใกล้ขึ้นเพื่อเล่นใน <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"กำลังเล่นใน <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"ไม่มีการใช้งาน โปรดตรวจสอบแอป"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"ไม่พบ"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"ใช้การควบคุมไม่ได้"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"เลือกอุปกรณ์ไว้ 1 รายการ"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"เลือกอุปกรณ์ไว้ <xliff:g id="COUNT">%1$d</xliff:g> รายการ"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ยกเลิกการเชื่อมต่อแล้ว)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"เชื่อมต่อไม่ได้ ลองใหม่"</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"เปลี่ยนไม่ได้ แตะเพื่อลองอีกครั้ง"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"จับคู่อุปกรณ์ใหม่"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"หมายเลขบิลด์"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"คัดลอกหมายเลขบิลด์ไปยังคลิปบอร์ดแล้ว"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"ดูทั้งหมด"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ตัดการเชื่อมต่ออีเทอร์เน็ตเพื่อสลับเครือข่าย"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"เพื่อปรับปรุงประสบการณ์การใช้อุปกรณ์ แอปและบริการต่างๆ จะยังคงสแกนหาเครือข่าย Wi‑Fi ได้ทุกเมื่อแม้ว่า Wi‑Fi จะปิดอยู่ คุณเปลี่ยนตัวเลือกนี้ได้ในการตั้งค่าการสแกนหา Wi-Fi "<annotation id="link">"เปลี่ยน"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ปิดโหมดบนเครื่องบิน"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ต้องการเพิ่มชิ้นส่วนต่อไปนี้ในการตั้งค่าด่วน"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"เพิ่มชิ้นส่วน"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ไม่ต้องเพิ่มชิ้นส่วน"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"เลือกผู้ใช้"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"แอปที่ทำงานอยู่เบื้องหลัง"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"หยุด"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/tiles_states_strings.xml b/packages/SystemUI/res/values-th/tiles_states_strings.xml
index 850fb7c..d5591b2 100644
--- a/packages/SystemUI/res/values-th/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-th/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"ปิด"</item>
<item msgid="460891964396502657">"เปิด"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"ไม่พร้อมใช้งาน"</item>
+ <item msgid="5581384648880018330">"ปิด"</item>
+ <item msgid="8000850843692192257">"เปิด"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index a944124..42eed44 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Walang available na mga device"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Hindi nakakonekta sa Wi-Fi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"I-invert ang mga kulay"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Pag-invert ng kulay"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Higit pang setting"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Mga setting ng user"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Tapos na"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"I-magnify ang buong screen"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"I-magnify ang isang bahagi ng screen"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Switch"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Pinalitan ng button ng accessibility ang galaw ng accessibility\n\n"<annotation id="link">"Tingnan ang mga setting"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"I-tap, buksan mga feature ng accessibility. I-customize o palitan button sa Mga Setting.\n\n"<annotation id="link">"Tingnan ang mga setting"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Ilipat ang button sa gilid para pansamantala itong itago"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Ilipat sa kaliwa sa itaas"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Ilipat sa kanan sa itaas"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Mga Setting"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"Nagpe-play ang <xliff:g id="SONG_NAME">%1$s</xliff:g> ni/ng <xliff:g id="ARTIST_NAME">%2$s</xliff:g> mula sa <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> sa <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"I-play"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"I-pause"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Nakaraang track"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Susunod na track"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"I-play"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Buksan ang <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"I-play ang <xliff:g id="SONG_NAME">%1$s</xliff:g> ni/ng <xliff:g id="ARTIST_NAME">%2$s</xliff:g> mula sa <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"I-play ang <xliff:g id="SONG_NAME">%1$s</xliff:g> mula sa <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"I-undo"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Lumapit pa para mag-play sa <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Nagpe-play sa <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Hindi aktibo, tingnan ang app"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Hindi nahanap"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Hindi available ang kontrol"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 device ang napili"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> (na) device ang napili"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(nadiskonekta)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Hindi makakonekta. Subukan ulit."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Hindi makalipat. I-tap para subukan ulit."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Magpares ng bagong device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero ng build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nakopya sa clipboard ang numero ng build."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Tingnan lahat"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para lumipat ng network, idiskonekta ang ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para pahusayin ang karanasan sa device, puwede pa ring mag-scan ng mga Wi-Fi network ang mga app at serbisyo anumang oras, kahit habang naka-off ang Wi‑Fi. Mababago mo ito sa mga setting ng pag-scan ng Wi-Fi. "<annotation id="link">"Baguhin"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"I-off ang airplane mode"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Gustong idagdag ng <xliff:g id="APPNAME">%1$s</xliff:g> ang sumusunod na tile sa Mga Mabilisang Setting"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Idagdag ang tile"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Huwag idagdag"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Pumili ng user"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Mga app na tumatakbo sa background"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Ihinto"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/tiles_states_strings.xml b/packages/SystemUI/res/values-tl/tiles_states_strings.xml
index dbf54ec..c601d2f 100644
--- a/packages/SystemUI/res/values-tl/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-tl/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Naka-off"</item>
<item msgid="460891964396502657">"Naka-on"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Hindi available"</item>
+ <item msgid="5581384648880018330">"Naka-off"</item>
+ <item msgid="8000850843692192257">"Naka-on"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 98b15d9..f79420e 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Kullanılabilir cihaz yok"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Kablosuz ağ bağlı değil"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Parlaklık"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Renkleri çevir"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Rengi ters çevirme"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Diğer ayarlar"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Kullanıcı ayarları"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Bitti"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Tam ekran büyütme"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekranın bir parçasını büyütün"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Geç"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Erişilebilirlik hareketi, Erişilebilirlik düğmesi ile değiştirildi\n\n"<annotation id="link">"Ayarları görüntüle"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Erişilebilirlik özelliklerini açmak için dokunun. Bu düğmeyi Ayarlar\'dan özelleştirin veya değiştirin.\n\n"<annotation id="link">"Ayarları göster"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Düğmeyi geçici olarak gizlemek için kenara taşıyın"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Sol üste taşı"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Sağ üste taşı"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Ayarlar"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> uygulamasından <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, <xliff:g id="SONG_NAME">%1$s</xliff:g> şarkısı çalıyor"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Çal"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Duraklat"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Önceki parça"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Sonraki parça"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Oynat"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> uygulamasını aç"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> uygulamasından <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, <xliff:g id="SONG_NAME">%1$s</xliff:g> şarkısını çal"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> uygulamasından <xliff:g id="SONG_NAME">%1$s</xliff:g> şarkısını çal"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Geri al"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında çalmak için yaklaşın"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında çalınıyor"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Devre dışı, uygulamaya bakın"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Bulunamadı"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol kullanılamıyor"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 cihaz seçildi"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> cihaz seçildi"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(bağlantı kesildi)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Bağlanılamadı. Tekrar deneyin."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Geçiş yapılamıyor. Tekrar denemek için dokunun."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yeni cihaz eşle"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Derleme numarası"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Derleme numarası panoya kopyalandı."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Tümünü göster"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ağ değiştirmek için ethernet bağlantısını kesin"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Uygulamalar ve hizmetler, cihaz deneyimini iyileştirmek için Kablosuz özelliği kapalı bile olsa kablosuz ağlar herhangi bir zamanda tarayabilir. Bunu kablosuz ağ taraması ayarlarından değiştirebilirsiniz. "<annotation id="link">"Değiştir"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Uçak modunu kapat"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> aşağıdaki kartı Hızlı Ayarlar\'a eklemek istiyor"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Kart ekle"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Kart ekleme"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Kullanıcı seçin"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Arka planda çalışan uygulamalar"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Durdur"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/tiles_states_strings.xml b/packages/SystemUI/res/values-tr/tiles_states_strings.xml
index 9eded7c..17ce6b3 100644
--- a/packages/SystemUI/res/values-tr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-tr/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Kapalı"</item>
<item msgid="460891964396502657">"Açık"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Kullanılamıyor"</item>
+ <item msgid="5581384648880018330">"Kapalı"</item>
+ <item msgid="8000850843692192257">"Açık"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 6535ecb..17a3ce8 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -252,7 +252,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Немає пристроїв"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi не під’єднано"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яскравість"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Інвертовані кольори"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Інверсія кольорів"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Більше налаштувань"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Налаштування користувача"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
@@ -757,7 +757,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Збільшення всього екрана"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Збільшити частину екрана"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Перемкнути"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Замість жесту спеціальних можливостей тепер використовується кнопка\n\n"<annotation id="link">"Переглянути налаштування"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Кнопка спеціальних можливостей. Змініть або замініть її в Налаштуваннях.\n\n"<annotation id="link">"Переглянути налаштування"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Щоб тимчасово сховати кнопку, перемістіть її на край екрана"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Перемістити ліворуч угору"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Перемістити праворуч угору"</string>
@@ -810,10 +810,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Налаштування"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"Пісня \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\", яку виконує <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, грає в додатку <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> з <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Відтворити"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Призупинити"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Попередня композиція"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Наступна композиція"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Відтворення"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Відкрити додаток <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Увімкнути пісню \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\", яку виконує <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, у додатку <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Увімкнути пісню \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" у додатку <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Відмінити"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Щоб відтворити на пристрої <xliff:g id="DEVICENAME">%1$s</xliff:g>, наблизьтеся до нього"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Відтворюється на пристрої <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, перейдіть у додаток"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Не знайдено"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Елемент керування недоступний"</string>
@@ -828,7 +835,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Вибрано 1 пристрій"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Вибрано пристроїв: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(від’єднано)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не вдалося підключитися. Повторіть спробу."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Не вдалося змінити підключення. Натисніть, щоб повторити спробу."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Підключити новий пристрій"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер складання"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номер складання скопійовано в буфер обміну."</string>
@@ -893,8 +900,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Показати все"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Щоб вибрати іншу мережу, від’єднайте кабель Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Щоб користуватися пристроєм було зручніше, додатки й сервіси можуть шукати бездротові мережі, навіть якщо Wi-Fi вимкнено. Це налаштування можна змінити в параметрах пошуку мереж Wi-Fi. "<annotation id="link">"Змінити"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Вимкнути режим польоту"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"Додаток <xliff:g id="APPNAME">%1$s</xliff:g> хоче додати такий параметр у меню швидких налаштувань:"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Додати параметр"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Не додавати параметр"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Виберіть користувача"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Додатки, що працюють у фоновому режимі"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Зупинити"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/tiles_states_strings.xml b/packages/SystemUI/res/values-uk/tiles_states_strings.xml
index c9da2b4..6f9ef21 100644
--- a/packages/SystemUI/res/values-uk/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-uk/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Вимкнено"</item>
<item msgid="460891964396502657">"Увімкнено"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Недоступно"</item>
+ <item msgid="5581384648880018330">"Вимкнено"</item>
+ <item msgid="8000850843692192257">"Увімкнено"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 0c46c17..350aaba 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"کوئی آلات دستیاب نہیں ہیں"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi سے منسلک نہیں ہے"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"چمکیلا پن"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"رنگ پلٹیں"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"رنگوں کی تقلیب"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"مزید ترتیبات"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"صارف کی ترتیبات"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"ہو گیا"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"فُل اسکرین کو بڑا کریں"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"اسکرین کا حصہ بڑا کریں"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"سوئچ کریں"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"ایکسیسبیلٹی بٹن کو ایکسیسبیلٹی اشارے سے بدل دیا گیا\n\n"<annotation id="link">"ترتیبات دیکھیں"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ایکسیسبیلٹی خصوصیات کھولنے کے لیے تھپتھپائیں۔ ترتیبات میں اس بٹن کو حسب ضرورت بنائیں یا تبدیل کریں۔\n\n"<annotation id="link">"ترتیبات ملاحظہ کریں"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"عارضی طور پر بٹن کو چھپانے کے لئے اسے کنارے پر لے جائیں"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"اوپر بائیں جانب لے جائیں"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"اوپر دائیں جانب لے جائيں"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"ترتیبات"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> سے <xliff:g id="ARTIST_NAME">%2$s</xliff:g> کا <xliff:g id="SONG_NAME">%1$s</xliff:g> چل رہا ہے"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> از <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"چلائیں"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"روکیں"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"پچھلا ٹریک"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"اگلا ٹریک"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"چلائیں"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> کھولیں"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> سے <xliff:g id="ARTIST_NAME">%2$s</xliff:g> کا <xliff:g id="SONG_NAME">%1$s</xliff:g> چلائیں"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> سے <xliff:g id="SONG_NAME">%1$s</xliff:g> چلائیں"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"کالعدم کریں"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g> پر چلانے کے لیے قریب کریں"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> پر چل رہا ہے"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"غیر فعال، ایپ چیک کریں"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"نہیں ملا"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"کنٹرول دستیاب نہیں ہے"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 آلہ منتخب کیا گیا"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> آلات منتخب کیے گئے"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(غیر منسلک ہے)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"منسلک نہیں ہو سکا۔ پھر کوشش کریں۔"</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"سوئچ نہیں کر سکتے۔ دوبارہ کوشش کرنے کے لیے تھپتھپائیں۔"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"نئے آلہ کا جوڑا بنائیں"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"بلڈ نمبر"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"بلڈ نمبر کلپ بورڈ میں کاپی ہو گیا۔"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"سبھی دیکھیں"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"نیٹ ورکس پر سوئچ کرنے کیلئے، ایتھرنیٹ غیر منسلک کریں"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"آلے کے تجربے کو بہتر بنانے کے لیے، Wi‑Fi کے آف ہونے پر بھی ایپس اور سروسز کسی بھی وقت Wi‑Fi نیٹ ورکس اسکین کر سکتی ہیں۔ آپ اسے Wi‑Fi اسکیننگ کی ترتیبات میں تبدیل کر سکتے ہیں۔ "<annotation id="link">"تبدیل کریں"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"ہوائی جہاز وضع آف کریں"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> درج ذیل ٹائل کو فوری ترتیبات میں شامل کرنا چاہتی ہے"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ٹائل شامل کریں"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ٹائل شامل نہ کریں"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"صارف منتخب کریں"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"ایپس پس منظر میں چل رہی ہیں"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"روکیں"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/tiles_states_strings.xml b/packages/SystemUI/res/values-ur/tiles_states_strings.xml
index 217d445..3284fc5 100644
--- a/packages/SystemUI/res/values-ur/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-ur/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"آف"</item>
<item msgid="460891964396502657">"آن"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"غیر دستیاب"</item>
+ <item msgid="5581384648880018330">"آف"</item>
+ <item msgid="8000850843692192257">"آن"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 8ef5264..277f1c3 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Qurilmalar topilmadi"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi tarmoqqa ulanmagan"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Yorqinlik"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Teskari ranglar"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ranglarni akslantirish"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Boshqa sozlamalar"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Foydalanuvchi sozlamalari"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Tayyor"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ekranni toʻliq kattalashtirish"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekran qismini kattalashtirish"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Almashtirish"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Maxsus imkoniyatlar tugmasi maxsus imkoniyatlar ishorasini almashtirdi\n\n"<annotation id="link">"Sozlamalarni ochish"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Maxsus imkoniyatlarni ochish uchun bosing Sozlamalardan moslay yoki almashtira olasiz.\n\n"<annotation id="link">"Sozlamalar"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Vaqtinchalik berkitish uchun tugmani qirra tomon suring"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Yuqori chapga surish"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Yuqori oʻngga surish"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Sozlamalar"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ilovasida ijro etilmoqda: <xliff:g id="SONG_NAME">%1$s</xliff:g> – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> / <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Ijro"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Pauza"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Avvalgi trek"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Keyingi trek"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Ijro"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ilovasini ochish"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ilovasida ijro etish: <xliff:g id="SONG_NAME">%1$s</xliff:g> – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> ilovasida ijro etilmoqda: <xliff:g id="SONG_NAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Qaytarish"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"<xliff:g id="DEVICENAME">%1$s</xliff:g>da ijro etish uchun yaqinroq keling"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"<xliff:g id="DEVICENAME">%1$s</xliff:g> qurilmasida ijro qilinmoqda"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Nofaol. Ilovani tekshiring"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Topilmadi"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Boshqarish imkonsiz"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ta qurilma tanlandi"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> ta qurilma tanlandi"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(uzildi)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ulanmadi. Qayta urining."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Xatolik. Qayta urinish uchun bosing."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yangi qurilmani ulash"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nashr raqami"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nashr raqami vaqtinchalik xotiraga nusxalandi."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Hammasi"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Boshqa tarmoqqa almashish uchun Ethernet tarmogʻini uzing"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Qurilma ishlashini yaxshilash uchun ilova va xizmatlar hatto Wi-Fi yoqilmaganda ham istalgan vaqt Wi-Fi tarmoqlarni qidirishi mumkin. Buni taqiqlash uchun Wi-Fi tarmoqlarni qidirish funksiyasini faolsizlantiring. "<annotation id="link">"Sozlamalarni ochish"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Parvoz rejimini faolsizlantirish"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ilovasi Tezkor sozlamalarga quyidagi tugmani kiritmoqchi"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Tugma kiritish"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Tugma kiritilmasin"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Foydalanuvchini tanlang"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Orqa fonda ishlayotgan ilovalar"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/tiles_states_strings.xml b/packages/SystemUI/res/values-uz/tiles_states_strings.xml
index 0fd077c..47bcf4d 100644
--- a/packages/SystemUI/res/values-uz/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-uz/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Oʻchiq"</item>
<item msgid="460891964396502657">"Yoniq"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Bandman"</item>
+ <item msgid="5581384648880018330">"Oʻchiq"</item>
+ <item msgid="8000850843692192257">"Yoniq"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 245defb..1c1557e 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Không có thiết bị nào"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Chưa kết nối với Wi-Fi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Độ sáng"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Đảo ngược màu"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Đảo màu"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Chế độ cài đặt khác"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Cài đặt người dùng"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Xong"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Phóng to toàn màn hình"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Phóng to một phần màn hình"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Chuyển"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Nút hỗ trợ tiếp cận đã thay thế cử chỉ hỗ trợ tiếp cận\n\n"<annotation id="link">"Xem chế độ cài đặt"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Nhấn để mở bộ tính năng hỗ trợ tiếp cận. Tuỳ chỉnh/thay thế nút này trong phần Cài đặt.\n\n"<annotation id="link">"Xem chế độ cài đặt"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Di chuyển nút sang cạnh để ẩn nút tạm thời"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Chuyển lên trên cùng bên trái"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Chuyển lên trên cùng bên phải"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Cài đặt"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"Đang phát <xliff:g id="SONG_NAME">%1$s</xliff:g> của <xliff:g id="ARTIST_NAME">%2$s</xliff:g> trên <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Phát"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Tạm dừng"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Bản nhạc trước"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Bản nhạc tiếp theo"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Phát"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Mở <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Phát <xliff:g id="SONG_NAME">%1$s</xliff:g> của <xliff:g id="ARTIST_NAME">%2$s</xliff:g> trên <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Phát <xliff:g id="SONG_NAME">%1$s</xliff:g> trên <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Hủy"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Đưa thiết bị đến gần hơn để phát trên <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Đang phát trên <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Không hoạt động, hãy kiểm tra ứng dụng"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Không tìm thấy"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Không có chức năng điều khiển"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Đã chọn 1 thiết bị"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Đã chọn <xliff:g id="COUNT">%1$d</xliff:g> thiết bị"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(đã ngắt kết nối)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Không thể kết nối. Hãy thử lại."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Không thể chuyển đổi. Hãy nhấn để thử lại."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Ghép nối thiết bị mới"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Số bản dựng"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Đã sao chép số bản dựng vào bảng nhớ tạm."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Xem tất cả"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Để chuyển mạng, hãy rút cáp Ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Để cải thiện trải nghiệm khi dùng thiết bị, các ứng dụng và dịch vụ vẫn có thể quét tìm mạng Wi‑Fi bất cứ lúc nào, ngay cả khi Wi‑Fi tắt. Bạn có thể thay đổi chế độ này trong phần cài đặt tính năng Quét tìm Wi‑Fi. "<annotation id="link">"Thay đổi"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Tắt chế độ trên máy bay"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> muốn thêm ô bên dưới vào trình đơn Cài đặt nhanh"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Thêm ô"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Không thêm ô"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Chọn người dùng"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Các ứng dụng chạy trong nền"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Dừng"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/tiles_states_strings.xml b/packages/SystemUI/res/values-vi/tiles_states_strings.xml
index 72ffc6d..ecc3223 100644
--- a/packages/SystemUI/res/values-vi/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-vi/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Đang tắt"</item>
<item msgid="460891964396502657">"Đang bật"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Không hoạt động"</item>
+ <item msgid="5581384648880018330">"Đang tắt"</item>
+ <item msgid="8000850843692192257">"Đang bật"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 2e9ba10..efd24bc 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"没有可用设备"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"未连接到 WLAN 网络"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"亮度"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"反色"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"颜色反转"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"更多设置"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"用户设置"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"完成"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"放大整个屏幕"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"放大部分屏幕"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"切换"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"“无障碍”按钮已取代无障碍手势\n\n"<annotation id="link">"查看设置"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"点按即可打开无障碍功能。您可在“设置”中自定义或更换此按钮。\n\n"<annotation id="link">"查看设置"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"将按钮移到边缘,即可暂时将其隐藏"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"移至左上角"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"移至右上角"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"设置"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"正在通过<xliff:g id="APP_LABEL">%3$s</xliff:g>播放<xliff:g id="ARTIST_NAME">%2$s</xliff:g>的《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> / <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"播放"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"暂停"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"上一首"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"下一首"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"播放"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"打开<xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"通过<xliff:g id="APP_LABEL">%3$s</xliff:g>播放<xliff:g id="ARTIST_NAME">%2$s</xliff:g>的《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"通过<xliff:g id="APP_LABEL">%2$s</xliff:g>播放《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"撤消"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"移近一点以在“<xliff:g id="DEVICENAME">%1$s</xliff:g>”上播放"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"正在“<xliff:g id="DEVICENAME">%1$s</xliff:g>”上播放"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"无效,请检查应用"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"未找到"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"控件不可用"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"已选择 1 个设备"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"已选择 <xliff:g id="COUNT">%1$d</xliff:g> 个设备"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(已断开连接)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"无法连接。请重试。"</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"无法切换。点按即可重试。"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"与新设备配对"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本号"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"已将版本号复制到剪贴板。"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切换网络,请断开以太网连接"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"为了提升设备的使用体验,即使 WLAN 已关闭,应用和服务仍可以随时扫描 WLAN 网络。您可以在 WLAN 扫描设置中更改此设置。"<annotation id="link">"更改"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"关闭飞行模式"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"“<xliff:g id="APPNAME">%1$s</xliff:g>”希望将以下图块添加到“快捷设置”"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"添加图块"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"不添加图块"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"选择用户"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"正在在后台运行的应用"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
index 7912813..43de98e 100644
--- a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml
@@ -153,8 +153,8 @@
</string-array>
<string-array name="tile_states_qr_code_scanner">
<item msgid="7435143266149257618">"不可用"</item>
- <item msgid="3301403109049256043">"关闭"</item>
- <item msgid="8878684975184010135">"开启"</item>
+ <item msgid="3301403109049256043">"已关闭"</item>
+ <item msgid="8878684975184010135">"已开启"</item>
</string-array>
<string-array name="tile_states_alarm">
<item msgid="4936533380177298776">"不可用"</item>
@@ -163,7 +163,12 @@
</string-array>
<string-array name="tile_states_onehanded">
<item msgid="8189342855739930015">"不可用"</item>
- <item msgid="146088982397753810">"关闭"</item>
- <item msgid="460891964396502657">"开启"</item>
+ <item msgid="146088982397753810">"已关闭"</item>
+ <item msgid="460891964396502657">"已开启"</item>
+ </string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"不可用"</item>
+ <item msgid="5581384648880018330">"已关闭"</item>
+ <item msgid="8000850843692192257">"已开启"</item>
</string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 7550a73..e7cb583 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"沒有可用裝置"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"未連線至 Wi-Fi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"亮度"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"反轉顏色"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"色彩反轉"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"更多設定"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"使用者設定"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"完成"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"放大成個畫面"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"放大部分螢幕畫面"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"切換"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"無障礙功能按鈕已取代無障礙手勢\n\n"<annotation id="link">"查看設定"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"㩒一下就可以開無障礙功能。喺「設定」度自訂或者取代呢個按鈕。\n\n"<annotation id="link">"查看設定"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"將按鈕移到邊緣即可暫時隱藏"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"移去左上方"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"移去右上方"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"正在透過 <xliff:g id="APP_LABEL">%3$s</xliff:g> 播放 <xliff:g id="ARTIST_NAME">%2$s</xliff:g> 的《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"播放"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"暫停"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"上一首曲目"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"下一首曲目"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"播放"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"開啟 <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"在 <xliff:g id="APP_LABEL">%3$s</xliff:g> 播放 <xliff:g id="ARTIST_NAME">%2$s</xliff:g> 的《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"在 <xliff:g id="APP_LABEL">%2$s</xliff:g> 播放《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"復原"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"移近一點以在 <xliff:g id="DEVICENAME">%1$s</xliff:g> 上播放"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"正在 <xliff:g id="DEVICENAME">%1$s</xliff:g> 上播放"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"已停用,請檢查應用程式"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"找不到"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制功能"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"已選取 1 部裝置"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 部裝置"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(已中斷連線)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"無法連線,請再試一次。"</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"無法切換,輕按即可重試。"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"版本號碼已複製到剪貼簿。"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"顯示全部"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切換網絡,請中斷以太網連線"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"為改善裝置的使用體驗,應用程式和服務仍可隨時掃瞄 Wi-Fi 網絡 (即使 Wi-Fi 已關閉)。您可在 Wi-Fi 掃瞄設定中變更此設定。"<annotation id="link">"變更"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"關閉飛行模式"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"「<xliff:g id="APPNAME">%1$s</xliff:g>」想在「快速設定」選單新增以下圖塊"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"新增圖塊"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"不要新增圖塊"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"選取使用者"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"正在背景中執行的應用程式"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
index 5f1b350..637fb4c 100644
--- a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"關閉"</item>
<item msgid="460891964396502657">"開啟"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"無法使用"</item>
+ <item msgid="5581384648880018330">"關閉"</item>
+ <item msgid="8000850843692192257">"開啟"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index a771098..11e4ac6 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"沒有可用裝置"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"未連線至 Wi-Fi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"亮度"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"反轉顏色"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"色彩反轉"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"更多設定"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"使用者設定"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"完成"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"放大整個螢幕畫面"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"放大局部螢幕畫面"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"切換"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"無障礙工具按鈕已取代無障礙手勢\n\n"<annotation id="link">"查看設定"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"輕觸即可開啟無障礙功能。你可以前往「設定」自訂或更換這個按鈕。\n\n"<annotation id="link">"查看設定"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"將按鈕移到邊緣處即可暫時隱藏"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"移到左上方"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"移到右上方"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"系統正透過「<xliff:g id="APP_LABEL">%3$s</xliff:g>」播放<xliff:g id="ARTIST_NAME">%2$s</xliff:g>的〈<xliff:g id="SONG_NAME">%1$s</xliff:g>〉"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>,共 <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"播放"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"暫停"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"上一首"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"下一首"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"播放"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"開啟「<xliff:g id="APP_LABEL">%1$s</xliff:g>」"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"透過「<xliff:g id="APP_LABEL">%3$s</xliff:g>」播放<xliff:g id="ARTIST_NAME">%2$s</xliff:g>的〈<xliff:g id="SONG_NAME">%1$s</xliff:g>〉"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"透過「<xliff:g id="APP_LABEL">%2$s</xliff:g>」播放〈<xliff:g id="SONG_NAME">%1$s</xliff:g>〉"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"復原"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"如要在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放,請靠近這部裝置"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"正在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"無效,請查看應用程式"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"找不到控制項"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制項"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"已選取 1 部裝置"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 部裝置"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(連線中斷)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"無法連線,請再試一次。"</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"無法切換,輕觸即可重試。"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"已將版本號碼複製到剪貼簿。"</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切換網路,請中斷乙太網路連線"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"為提升裝置的使用體驗,應用程式和服務仍可隨時掃描 Wi‑Fi 網路,即使 Wi-Fi 連線功能處於關閉狀態時亦然。你可以前往「掃描 Wi-Fi」設定進行變更。"<annotation id="link">"變更"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"關閉飛航模式"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"「<xliff:g id="APPNAME">%1$s</xliff:g>」想在快速設定選單新增以下設定方塊"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"新增設定方塊"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"不要新增設定方塊"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"選取使用者"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"目前在背景執行的應用程式"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
index 3d81fc8..266cf5d 100644
--- a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"已關閉"</item>
<item msgid="460891964396502657">"已開啟"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"無法使用"</item>
+ <item msgid="5581384648880018330">"已關閉"</item>
+ <item msgid="8000850843692192257">"已開啟"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 64920b2..8c7f030 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -250,7 +250,7 @@
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Ayikho idivayisi etholakalayo"</string>
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"I-Wi-Fi ayixhunyiwe"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ukugqama"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Faka imibala"</string>
+ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ukuguqulwa kombala"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Izilungiselelo eziningi"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Amasethingi womsebenzisi"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Kwenziwe"</string>
@@ -747,7 +747,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Khulisa isikrini esigcwele"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Khulisa ingxenye eyesikrini"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Iswishi"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Inkinobho yokufinyeleleka ishintshaniswe ngokuthinta kokufinyeleleka\n\n"<annotation id="link">"Buka amasethingi"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Thepha ukuze uvule izakhi zokufinyelela. Enza ngendlela oyifisayo noma shintsha le nkinobho Kumasethingi.\n\n"<annotation id="link">"Buka amasethingi"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Hambisa inkinobho onqenqemeni ukuze uyifihle okwesikhashana"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Hamba phezulu kwesokunxele"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Hamba phezulu ngakwesokudla"</string>
@@ -798,10 +798,17 @@
<string name="controls_media_settings_button" msgid="5815790345117172504">"Izilungiselelo"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"I-<xliff:g id="SONG_NAME">%1$s</xliff:g> ka-<xliff:g id="ARTIST_NAME">%2$s</xliff:g> idlala kusuka ku-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> ku-<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
+ <string name="controls_media_button_play" msgid="2705068099607410633">"Dlala"</string>
+ <string name="controls_media_button_pause" msgid="8614887780950376258">"Misa"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Ithrekhi yangaphambilini"</string>
+ <string name="controls_media_button_next" msgid="6662636627525947610">"Ithrekhi elandelayo"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Dlala"</string>
<string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Vula i-<xliff:g id="APP_LABEL">%1$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Dlala i-<xliff:g id="SONG_NAME">%1$s</xliff:g> ka-<xliff:g id="ARTIST_NAME">%2$s</xliff:g> kusuka ku-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
<string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Dlala i-<xliff:g id="SONG_NAME">%1$s</xliff:g> kusuka ku-<xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
+ <string name="media_transfer_undo" msgid="1895606387620728736">"Hlehlisa"</string>
+ <string name="media_move_closer_to_transfer" msgid="1628426856415585141">"Sondeza eduze ukudlala ku-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+ <string name="media_transfer_playing" msgid="3760048096352107789">"Idlala ku-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
<string name="controls_error_timeout" msgid="794197289772728958">"Akusebenzi, hlola uhlelo lokusebenza"</string>
<string name="controls_error_removed" msgid="6675638069846014366">"Ayitholakali"</string>
<string name="controls_error_removed_title" msgid="1207794911208047818">"Ukulawula akutholakali"</string>
@@ -816,7 +823,7 @@
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"idivayisi ekhethiwe e-1"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"amadivayisi akhethiwe angu-<xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(inqamukile)"</string>
- <string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ayikwazanga ukuxhumeka. Zama futhi."</string>
+ <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Akukwazi ukushintsha. Thepha ukuze uzame futhi."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bhangqa idivayisi entsha"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Yakha inombolo"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Yakha inombolo ekopishelwe kubhodi yokunamathisela."</string>
@@ -881,8 +888,11 @@
<string name="see_all_networks" msgid="3773666844913168122">"Bona konke"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ukuze ushintshe amanethiwekhi, nqamula i-ethernet"</string>
<string name="wifi_scan_notify_message" msgid="3753839537448621794">"Ukuze kuthuthukiswe ukuzizwela kwedivayisi, ama-app namasevisi kusengakwazi ukuskena amanethiwekhi we-Wi-Fi noma kunini, ngisho noma i-Wi-Fi ivaliwe, Ungashintsha lokhu kumasethingi Wokuskena i-Wi-Fi. "<annotation id="link">"Shintsha"</annotation></string>
+ <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Vala imodi yendiza"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"I-<xliff:g id="APPNAME">%1$s</xliff:g> ifuna ukwengeza ithayela elilandelayo Kumasethingi Asheshayo"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Engeza ithayela"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ungafaki ithayela"</string>
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Khetha umsebenzisi"</string>
+ <string name="fgs_manager_dialog_title" msgid="656091833603337197">"Ama-app ayaqhubeka ngemuva"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Misa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/tiles_states_strings.xml b/packages/SystemUI/res/values-zu/tiles_states_strings.xml
index a124c9e..9cac4ae 100644
--- a/packages/SystemUI/res/values-zu/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-zu/tiles_states_strings.xml
@@ -166,4 +166,9 @@
<item msgid="146088982397753810">"Valiwe"</item>
<item msgid="460891964396502657">"Vuliwe"</item>
</string-array>
+ <string-array name="tile_states_fgsmanager">
+ <item msgid="3054341646818213094">"Akutholakali"</item>
+ <item msgid="5581384648880018330">"Valiwe"</item>
+ <item msgid="8000850843692192257">"Vuliwe"</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 843c69f..b12db5d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -969,6 +969,10 @@
<dimen name="qs_media_enabled_seekbar_vertical_padding">28dp</dimen>
<dimen name="qs_media_disabled_seekbar_vertical_padding">29dp</dimen>
+ <!-- Sizes for alternate session-based layout -->
+ <dimen name="qs_media_session_enabled_seekbar_vertical_padding">15dp</dimen>
+ <dimen name="qs_media_session_disabled_seekbar_vertical_padding">16dp</dimen>
+
<!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
<dimen name="qs_aa_media_rec_album_size_collapsed">72dp</dimen>
<dimen name="qs_aa_media_rec_album_size_expanded">76dp</dimen>
@@ -977,13 +981,18 @@
<dimen name="qs_aa_media_rec_album_margin_vert">4dp</dimen>
<dimen name="qq_aa_media_rec_header_text_size">16sp</dimen>
- <!-- Media tap-to-transfer chip -->
+ <!-- Media tap-to-transfer chip for sender device -->
<dimen name="media_ttt_chip_outer_padding">16dp</dimen>
<dimen name="media_ttt_text_size">16sp</dimen>
- <dimen name="media_ttt_icon_size">16dp</dimen>
+ <dimen name="media_ttt_icon_size">24dp</dimen>
+ <dimen name="media_ttt_loading_size">20dp</dimen>
<dimen name="media_ttt_undo_button_vertical_padding">8dp</dimen>
<dimen name="media_ttt_undo_button_vertical_negative_margin">-8dp</dimen>
+ <!-- Media tap-to-transfer chip for receiver device -->
+ <dimen name="media_ttt_chip_size_receiver">100dp</dimen>
+ <dimen name="media_ttt_icon_size_receiver">95dp</dimen>
+
<!-- Window magnification -->
<dimen name="magnification_border_drag_size">35dp</dimen>
<dimen name="magnification_outer_border_margin">15dp</dimen>
@@ -1259,6 +1268,8 @@
<!-- Internet dialog related dimensions -->
<dimen name="internet_dialog_corner_radius">24dp</dimen>
+ <!-- Width of progress bar -->
+ <dimen name="internet_dialog_progress_bar_width">152dp</dimen>
<!-- End margin of network layout -->
<dimen name="internet_dialog_network_layout_margin">16dp</dimen>
<!-- Size of switch bar in internet dialog -->
@@ -1308,4 +1319,7 @@
<dimen name="dream_overlay_status_bar_height">80dp</dimen>
<dimen name="dream_overlay_status_bar_margin">40dp</dimen>
<dimen name="dream_overlay_status_icon_margin">8dp</dimen>
+ <!-- Height of the area at the top of the dream overlay to allow dragging down the notifications
+ shade. -->
+ <dimen name="dream_overlay_notifications_drag_area_height">100dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 99508a5..8482044 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -465,10 +465,6 @@
<string name="accessibility_quick_settings_flashlight_changed_off">Flashlight turned off.</string>
<!-- Announcement made when the flashlight state changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_flashlight_changed_on">Flashlight turned on.</string>
- <!-- Announcement made when the color inversion state changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_color_inversion_changed_off">Color inversion turned off.</string>
- <!-- Announcement made when the color inversion state changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_color_inversion_changed_on">Color inversion turned on.</string>
<!-- Announcement made when the hotspot state changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_hotspot_changed_off">Mobile hotspot turned off.</string>
<!-- Announcement made when the hotspot state changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -1277,6 +1273,10 @@
<!-- [CHAR LIMIT=NONE] Importance Tuner setting title -->
<string name="tuner_full_importance_settings">Power notification controls</string>
+
+ <!-- [CHAR LIMIT=NONE] Notification camera based rotation enabled description -->
+ <string name="rotation_lock_camera_rotation_on">On - Face-based</string>
+
<string name="power_notification_controls_description">With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications.
\n\n<b>Level 5</b>
\n- Show at the top of the notification list
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 9358349..18bfb52 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -581,6 +581,23 @@
<item name="android:scaleType">centerInside</item>
</style>
+ <style name="MediaPlayer.SessionAction"
+ parent="@android:style/Widget.Material.Button.Borderless.Small">
+ <item name="android:background">@drawable/qs_media_light_source</item>
+ <item name="android:tint">?android:attr/textColorPrimary</item>
+ <item name="android:stateListAnimator">@anim/media_button_state_list_animator</item>
+ <item name="android:paddingTop">12dp</item>
+ <item name="android:paddingStart">12dp</item>
+ <item name="android:paddingEnd">12dp</item>
+ <item name="android:paddingBottom">12dp</item>
+ <item name="android:scaleType">centerInside</item>
+ </style>
+
+ <style name="MediaPlayer.SessionAction.Primary" parent="MediaPlayer.SessionAction">
+ <item name="android:background">@drawable/qs_media_round_button_background</item>
+ <item name="android:backgroundTint">@color/media_player_solid_button_bg</item>
+ </style>
+
<style name="MediaPlayer.OutlineButton">
<item name="android:background">@drawable/qs_media_button_background</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index 3cd090e..2d5080e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -246,10 +246,6 @@
if (mPausingTasks.contains(openingTasks.get(i).getContainer())) {
++pauseMatches;
}
- if (openingTasks.get(i).getContainer().equals(mPausingTasks.get(i))) {
- // In this case, we are "returning" to an already running app, so just consume
- // the merge and do nothing.
- }
}
if (pauseMatches > 0) {
if (pauseMatches != mPausingTasks.size()) {
@@ -275,9 +271,9 @@
t.reparent(target.leash.mSurfaceControl, mInfo.getRootLeash());
t.setLayer(target.leash.mSurfaceControl, layer);
t.hide(target.leash.mSurfaceControl);
- t.apply();
targets[i] = target;
}
+ t.apply();
recents.onTasksAppeared(targets);
return true;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index b84cb19..b5ea498 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -32,9 +32,14 @@
import android.app.AlertDialog;
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BlendMode;
import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
+import android.os.UserManager;
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
@@ -70,6 +75,7 @@
import com.android.internal.util.UserIcons;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.settingslib.Utils;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
@@ -760,11 +766,11 @@
private ViewGroup mView;
private ViewGroup mUserSwitcherViewGroup;
private KeyguardSecurityViewFlipper mViewFlipper;
- private ImageView mUserIconView;
private TextView mUserSwitcher;
private FalsingManager mFalsingManager;
private UserSwitcherController mUserSwitcherController;
private KeyguardUserSwitcherPopupMenu mPopup;
+ private Resources mResources;
@Override
public void init(@NonNull ViewGroup v, @NonNull GlobalSettings globalSettings,
@@ -775,6 +781,7 @@
mViewFlipper = viewFlipper;
mFalsingManager = falsingManager;
mUserSwitcherController = userSwitcherController;
+ mResources = v.getContext().getResources();
if (mUserSwitcherViewGroup == null) {
LayoutInflater.from(v.getContext()).inflate(
@@ -784,9 +791,8 @@
mUserSwitcherViewGroup = mView.findViewById(R.id.keyguard_bouncer_user_switcher);
}
- mUserIconView = mView.findViewById(R.id.user_icon);
- Drawable icon = UserIcons.getDefaultUserIcon(v.getContext().getResources(), 0, false);
- mUserIconView.setImageDrawable(icon);
+ Drawable userIcon = findUserIcon(KeyguardUpdateMonitor.getCurrentUser());
+ ((ImageView) mView.findViewById(R.id.user_icon)).setImageDrawable(userIcon);
updateSecurityViewLocation();
@@ -802,6 +808,14 @@
}
}
+ private Drawable findUserIcon(int userId) {
+ Bitmap userIcon = UserManager.get(mView.getContext()).getUserIcon(userId);
+ if (userIcon != null) {
+ return new BitmapDrawable(userIcon);
+ }
+ return UserIcons.getDefaultUserIcon(mResources, userId, false);
+ }
+
@Override
public void startAppearAnimation(SecurityMode securityMode) {
// IME insets animations handle alpha and translation
@@ -824,8 +838,7 @@
return;
}
- int yTranslation = mView.getContext().getResources().getDimensionPixelSize(
- R.dimen.disappear_y_translation);
+ int yTranslation = mResources.getDimensionPixelSize(R.dimen.disappear_y_translation);
AnimatorSet anims = new AnimatorSet();
ObjectAnimator yAnim = ObjectAnimator.ofFloat(mView, View.TRANSLATION_Y, yTranslation);
@@ -840,21 +853,70 @@
String currentUserName = mUserSwitcherController.getCurrentUserName();
mUserSwitcher.setText(currentUserName);
+ final UserRecord currentUser = getCurrentUser();
ViewGroup anchor = mView.findViewById(R.id.user_switcher_anchor);
BaseUserAdapter adapter = new BaseUserAdapter(mUserSwitcherController) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
UserRecord item = getItem(position);
- TextView view = (TextView) convertView;
+ FrameLayout view = (FrameLayout) convertView;
if (view == null) {
- view = (TextView) LayoutInflater.from(parent.getContext()).inflate(
+ view = (FrameLayout) LayoutInflater.from(parent.getContext()).inflate(
R.layout.keyguard_bouncer_user_switcher_item,
parent,
false);
}
- view.setText(getName(parent.getContext(), item));
+ TextView textView = (TextView) view.getChildAt(0);
+ textView.setText(getName(parent.getContext(), item));
+ Drawable icon = null;
+ if (item.picture != null) {
+ icon = new BitmapDrawable(item.picture);
+ } else {
+ icon = getDrawable(item, view.getContext());
+ }
+ int iconSize = view.getResources().getDimensionPixelSize(
+ R.dimen.bouncer_user_switcher_item_icon_size);
+ int iconPadding = view.getResources().getDimensionPixelSize(
+ R.dimen.bouncer_user_switcher_item_icon_padding);
+ icon.setBounds(0, 0, iconSize, iconSize);
+ textView.setCompoundDrawablePadding(iconPadding);
+ textView.setCompoundDrawablesRelative(icon, null, null, null);
+
+ if (item == currentUser) {
+ textView.setBackground(view.getContext().getDrawable(
+ R.drawable.bouncer_user_switcher_item_selected_bg));
+ } else {
+ textView.setBackground(null);
+ }
return view;
}
+
+ private Drawable getDrawable(UserRecord item, Context context) {
+ Drawable drawable;
+ if (item.isCurrent && item.isGuest) {
+ drawable = context.getDrawable(R.drawable.ic_avatar_guest_user);
+ } else {
+ drawable = getIconDrawable(context, item);
+ }
+
+ int iconColor;
+ if (item.isSwitchToEnabled) {
+ iconColor = Utils.getColorAttrDefaultColor(context,
+ com.android.internal.R.attr.colorAccentPrimaryVariant);
+ } else {
+ iconColor = context.getResources().getColor(
+ R.color.kg_user_switcher_restricted_avatar_icon_color,
+ context.getTheme());
+ }
+ drawable.setTint(iconColor);
+
+ Drawable bg = context.getDrawable(R.drawable.kg_bg_avatar);
+ bg.setTintBlendMode(BlendMode.DST);
+ bg.setTint(Utils.getColorAttrDefaultColor(context,
+ com.android.internal.R.attr.colorSurfaceVariant));
+ drawable = new LayerDrawable(new Drawable[]{bg, drawable});
+ return drawable;
+ }
};
if (adapter.getCount() < 2) {
@@ -876,7 +938,8 @@
public void onItemClick(AdapterView parent, View view, int pos, long id) {
if (mFalsingManager.isFalseTap(LOW_PENALTY)) return;
- UserRecord user = adapter.getItem(pos);
+ // Subtract one for the header
+ UserRecord user = adapter.getItem(pos - 1);
if (!user.isCurrent) {
adapter.onUserListItemClicked(user);
}
@@ -888,6 +951,16 @@
});
}
+ private UserRecord getCurrentUser() {
+ for (int i = 0; i < mUserSwitcherController.getUsers().size(); ++i) {
+ UserRecord userRecord = mUserSwitcherController.getUsers().get(i);
+ if (userRecord.isCurrent) {
+ return userRecord;
+ }
+ }
+ return null;
+ }
+
/**
* Each view will get half the width. Yes, it would be easier to use something other than
* FrameLayout but it was too disruptive to downstream projects to change.
@@ -901,8 +974,7 @@
@Override
public void updateSecurityViewLocation() {
- if (mView.getContext().getResources().getConfiguration().orientation
- == Configuration.ORIENTATION_PORTRAIT) {
+ if (mResources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
updateViewGravity(mViewFlipper, Gravity.CENTER_HORIZONTAL);
updateViewGravity(mUserSwitcherViewGroup, Gravity.CENTER_HORIZONTAL);
mUserSwitcherViewGroup.setTranslationY(0);
@@ -912,8 +984,7 @@
// Attempt to reposition a bit higher to make up for this frame being a bit lower
// on the device
- int yTrans = mView.getContext().getResources().getDimensionPixelSize(
- R.dimen.status_bar_height);
+ int yTrans = mResources.getDimensionPixelSize(R.dimen.status_bar_height);
mUserSwitcherViewGroup.setTranslationY(-yTrans);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherPopupMenu.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherPopupMenu.java
index 7b6ce3e..efa5558 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherPopupMenu.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherPopupMenu.java
@@ -18,6 +18,8 @@
import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.drawable.ShapeDrawable;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ListPopupWindow;
@@ -32,15 +34,6 @@
public class KeyguardUserSwitcherPopupMenu extends ListPopupWindow {
private Context mContext;
private FalsingManager mFalsingManager;
- private int mLastHeight = -1;
- private View.OnLayoutChangeListener mLayoutListener = (v, l, t, r, b, ol, ot, or, ob) -> {
- int height = -v.getMeasuredHeight() + getAnchorView().getHeight();
- if (height != mLastHeight) {
- mLastHeight = height;
- setVerticalOffset(height);
- KeyguardUserSwitcherPopupMenu.super.show();
- }
- };
public KeyguardUserSwitcherPopupMenu(@NonNull Context context,
@NonNull FalsingManager falsingManager) {
@@ -49,7 +42,7 @@
mFalsingManager = falsingManager;
Resources res = mContext.getResources();
setBackgroundDrawable(
- res.getDrawable(R.drawable.keyguard_user_switcher_popup_bg, context.getTheme()));
+ res.getDrawable(R.drawable.bouncer_user_switcher_popup_bg, context.getTheme()));
setModal(true);
setOverlapAnchor(true);
}
@@ -63,8 +56,20 @@
super.show();
ListView listView = getListView();
- // This will force the popupwindow to show upward instead of drop down
- listView.addOnLayoutChangeListener(mLayoutListener);
+ listView.setVerticalScrollBarEnabled(false);
+ listView.setHorizontalScrollBarEnabled(false);
+
+ // Creates a transparent spacer between items
+ ShapeDrawable shape = new ShapeDrawable();
+ shape.setAlpha(0);
+ listView.setDivider(shape);
+ listView.setDividerHeight(mContext.getResources().getDimensionPixelSize(
+ R.dimen.bouncer_user_switcher_popup_divider_height));
+
+ int height = mContext.getResources().getDimensionPixelSize(
+ R.dimen.bouncer_user_switcher_popup_header_height);
+ listView.addHeaderView(createSpacer(height), null, false);
+ listView.addFooterView(createSpacer(height), null, false);
listView.setOnTouchListener((v, ev) -> {
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
@@ -72,11 +77,19 @@
}
return false;
});
+ super.show();
}
- @Override
- public void dismiss() {
- getListView().removeOnLayoutChangeListener(mLayoutListener);
- super.dismiss();
+ private View createSpacer(int height) {
+ return new View(mContext) {
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(1, height);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ }
+ };
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
index e7f6374..7fdb5ea 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
@@ -33,7 +33,7 @@
* - sends sensor rect updates to fingerprint drawable
* - optionally can override dozeTimeTick to adjust views for burn-in mitigation
*/
-abstract class UdfpsAnimationView extends FrameLayout {
+public abstract class UdfpsAnimationView extends FrameLayout {
// mAlpha takes into consideration the status bar expansion amount to fade out icon when
// the status bar is expanded
private int mAlpha;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
deleted file mode 100644
index 73e3aec..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import android.annotation.NonNull;
-import android.graphics.PointF;
-import android.graphics.RectF;
-
-import com.android.systemui.Dumpable;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
-import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener;
-import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
-import com.android.systemui.util.ViewController;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Handles:
- * 1. registering for listeners when its view is attached and unregistering on view detached
- * 2. pausing udfps when fingerprintManager may still be running but we temporarily want to hide
- * the affordance. this allows us to fade the view in and out nicely (see shouldPauseAuth)
- * 3. sending events to its view including:
- * - illumination events
- * - sensor position changes
- * - doze time event
- */
-abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
- extends ViewController<T> implements Dumpable {
- @NonNull final StatusBarStateController mStatusBarStateController;
- @NonNull final PanelExpansionStateManager mPanelExpansionStateManager;
- @NonNull final SystemUIDialogManager mDialogManager;
- @NonNull final DumpManager mDumpManger;
-
- boolean mNotificationShadeVisible;
-
- protected UdfpsAnimationViewController(
- T view,
- @NonNull StatusBarStateController statusBarStateController,
- @NonNull PanelExpansionStateManager panelExpansionStateManager,
- @NonNull SystemUIDialogManager dialogManager,
- @NonNull DumpManager dumpManager) {
- super(view);
- mStatusBarStateController = statusBarStateController;
- mPanelExpansionStateManager = panelExpansionStateManager;
- mDialogManager = dialogManager;
- mDumpManger = dumpManager;
- }
-
- abstract @NonNull String getTag();
-
- @Override
- protected void onViewAttached() {
- mPanelExpansionStateManager.addExpansionListener(mPanelExpansionListener);
- mDialogManager.registerListener(mDialogListener);
- mDumpManger.registerDumpable(getDumpTag(), this);
- }
-
- @Override
- protected void onViewDetached() {
- mPanelExpansionStateManager.removeExpansionListener(mPanelExpansionListener);
- mDialogManager.unregisterListener(mDialogListener);
- mDumpManger.unregisterDumpable(getDumpTag());
- }
-
- /**
- * in some cases, onViewAttached is called for the newly added view using an instance of
- * this controller before onViewDetached is called on the previous view, so we must have a
- * unique dump tag per instance of this class
- * @return a unique tag for this instance of this class
- */
- private String getDumpTag() {
- return getTag() + " (" + this + ")";
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("mNotificationShadeVisible=" + mNotificationShadeVisible);
- pw.println("shouldPauseAuth()=" + shouldPauseAuth());
- pw.println("isPauseAuth=" + mView.isPauseAuth());
- }
-
- /**
- * Returns true if the fingerprint manager is running but we want to temporarily pause
- * authentication.
- */
- boolean shouldPauseAuth() {
- return mNotificationShadeVisible
- || mDialogManager.shouldHideAffordance();
- }
-
- /**
- * Send pause auth update to our view.
- */
- void updatePauseAuth() {
- if (mView.setPauseAuth(shouldPauseAuth())) {
- mView.postInvalidate();
- }
- }
-
- /**
- * Send sensor position change to our view. This rect contains paddingX and paddingY.
- */
- void onSensorRectUpdated(RectF sensorRect) {
- mView.onSensorRectUpdated(sensorRect);
- }
-
- /**
- * Send dozeTimeTick to view in case it wants to handle its burn-in offset.
- */
- void dozeTimeTick() {
- if (mView.dozeTimeTick()) {
- mView.postInvalidate();
- }
- }
-
- /**
- * @return the amount of translation needed if the view currently requires the user to touch
- * somewhere other than the exact center of the sensor. For example, this can happen
- * during guided enrollment.
- */
- PointF getTouchTranslation() {
- return new PointF(0, 0);
- }
-
- /**
- * X-Padding to add to left and right of the sensor rectangle area to increase the size of our
- * window to draw within.
- * @return
- */
- int getPaddingX() {
- return 0;
- }
-
- /**
- * Y-Padding to add to top and bottom of the sensor rectangle area to increase the size of our
- * window to draw within.
- */
- int getPaddingY() {
- return 0;
- }
-
- /**
- * Udfps has started illuminating and the fingerprint manager is working on authenticating.
- */
- void onIlluminationStarting() {
- mView.onIlluminationStarting();
- mView.postInvalidate();
- }
-
- /**
- * Udfps has stopped illuminating and the fingerprint manager is no longer attempting to
- * authenticate.
- */
- void onIlluminationStopped() {
- mView.onIlluminationStopped();
- mView.postInvalidate();
- }
-
- /**
- * Whether to listen for touches outside of the view.
- */
- boolean listenForTouchesOutsideView() {
- return false;
- }
-
- /**
- * Called on touches outside of the view if listenForTouchesOutsideView returns true
- */
- void onTouchOutsideView() { }
-
- private final PanelExpansionListener mPanelExpansionListener = new PanelExpansionListener() {
- @Override
- public void onPanelExpansionChanged(
- float fraction, boolean expanded, boolean tracking) {
- // Notification shade can be expanded but not visible (fraction: 0.0), for example
- // when a heads-up notification (HUN) is showing.
- mNotificationShadeVisible = expanded && fraction > 0f;
- mView.onExpansionChanged(fraction);
- updatePauseAuth();
- }
- };
-
- private final SystemUIDialogManager.Listener mDialogListener =
- (shouldHide) -> updatePauseAuth();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
new file mode 100644
index 0000000..c33cd8d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.biometrics
+
+import android.graphics.PointF
+import android.graphics.RectF
+import com.android.systemui.Dumpable
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
+import com.android.systemui.util.ViewController
+import java.io.FileDescriptor
+import java.io.PrintWriter
+
+/**
+ * Handles:
+ * 1. registering for listeners when its view is attached and unregistering on view detached
+ * 2. pausing udfps when fingerprintManager may still be running but we temporarily want to hide
+ * the affordance. this allows us to fade the view in and out nicely (see shouldPauseAuth)
+ * 3. sending events to its view including:
+ * - illumination events
+ * - sensor position changes
+ * - doze time event
+ */
+abstract class UdfpsAnimationViewController<T : UdfpsAnimationView>(
+ view: T,
+ protected val statusBarStateController: StatusBarStateController,
+ protected val panelExpansionStateManager: PanelExpansionStateManager,
+ protected val dialogManager: SystemUIDialogManager,
+ private val dumpManager: DumpManager
+) : ViewController<T>(view), Dumpable {
+
+ protected abstract val tag: String
+
+ private val view: T
+ get() = mView!!
+
+ private val dialogListener = SystemUIDialogManager.Listener { updatePauseAuth() }
+
+ private val panelExpansionListener =
+ PanelExpansionListener { fraction, expanded, tracking ->
+ // Notification shade can be expanded but not visible (fraction: 0.0), for example
+ // when a heads-up notification (HUN) is showing.
+ notificationShadeVisible = expanded && fraction > 0f
+ view.onExpansionChanged(fraction)
+ updatePauseAuth()
+ }
+
+ /** If the notification shade is visible. */
+ var notificationShadeVisible: Boolean = false
+
+ /**
+ * The amount of translation needed if the view currently requires the user to touch
+ * somewhere other than the exact center of the sensor. For example, this can happen
+ * during guided enrollment.
+ */
+ open val touchTranslation: PointF = PointF(0f, 0f)
+
+ /**
+ * X-Padding to add to left and right of the sensor rectangle area to increase the size of our
+ * window to draw within.
+ */
+ open val paddingX: Int = 0
+
+ /**
+ * Y-Padding to add to top and bottom of the sensor rectangle area to increase the size of our
+ * window to draw within.
+ */
+ open val paddingY: Int = 0
+
+ override fun onViewAttached() {
+ panelExpansionStateManager.addExpansionListener(panelExpansionListener)
+ dialogManager.registerListener(dialogListener)
+ dumpManager.registerDumpable(dumpTag, this)
+ }
+
+ override fun onViewDetached() {
+ panelExpansionStateManager.removeExpansionListener(panelExpansionListener)
+ dialogManager.unregisterListener(dialogListener)
+ dumpManager.unregisterDumpable(dumpTag)
+ }
+
+ /**
+ * in some cases, onViewAttached is called for the newly added view using an instance of
+ * this controller before onViewDetached is called on the previous view, so we must have a
+ * unique [dumpTag] per instance of this class.
+ */
+ private val dumpTag = "$tag ($this)"
+
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
+ pw.println("mNotificationShadeVisible=$notificationShadeVisible")
+ pw.println("shouldPauseAuth()=" + shouldPauseAuth())
+ pw.println("isPauseAuth=" + view.isPauseAuth)
+ }
+
+ /**
+ * Returns true if the fingerprint manager is running, but we want to temporarily pause
+ * authentication.
+ */
+ open fun shouldPauseAuth(): Boolean {
+ return notificationShadeVisible || dialogManager.shouldHideAffordance()
+ }
+
+ /**
+ * Send pause auth update to our view.
+ */
+ fun updatePauseAuth() {
+ if (view.setPauseAuth(shouldPauseAuth())) {
+ view.postInvalidate()
+ }
+ }
+
+ /**
+ * Send sensor position change to our view. This rect contains paddingX and paddingY.
+ */
+ fun onSensorRectUpdated(sensorRect: RectF) {
+ view.onSensorRectUpdated(sensorRect)
+ }
+
+ /**
+ * Send dozeTimeTick to view in case it wants to handle its burn-in offset.
+ */
+ fun dozeTimeTick() {
+ if (view.dozeTimeTick()) {
+ view.postInvalidate()
+ }
+ }
+
+ /**
+ * Udfps has started illuminating and the fingerprint manager is working on authenticating.
+ */
+ fun onIlluminationStarting() {
+ view.onIlluminationStarting()
+ view.postInvalidate()
+ }
+
+ /**
+ * Udfps has stopped illuminating and the fingerprint manager is no longer attempting to
+ * authenticate.
+ */
+ fun onIlluminationStopped() {
+ view.onIlluminationStopped()
+ view.postInvalidate()
+ }
+
+ /**
+ * Whether to listen for touches outside of the view.
+ */
+ open fun listenForTouchesOutsideView(): Boolean = false
+
+ /**
+ * Called on touches outside of the view if listenForTouchesOutsideView returns true
+ */
+ open fun onTouchOutsideView() {}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.java
deleted file mode 100644
index 70be907..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-import androidx.annotation.Nullable;
-
-/**
- * Class that coordinates non-HBM animations during BiometricPrompt.
- *
- * Currently doesn't draw anything.
- *
- * Note that {@link AuthBiometricUdfpsView} also shows UDFPS animations. At some point we should
- * de-dupe this if necessary.
- */
-public class UdfpsBpView extends UdfpsAnimationView {
- private UdfpsFpDrawable mFingerprintDrawable;
-
- public UdfpsBpView(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- // Drawable isn't ever added to the view, so we don't currently show anything
- mFingerprintDrawable = new UdfpsFpDrawable(mContext);
- }
-
- @Override
- UdfpsDrawable getDrawable() {
- return mFingerprintDrawable;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.kt
new file mode 100644
index 0000000..6607915
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.biometrics
+
+import android.content.Context
+import android.util.AttributeSet
+
+/**
+ * Class that coordinates non-HBM animations during BiometricPrompt.
+ *
+ * Currently doesn't draw anything.
+ *
+ * Note that [AuthBiometricUdfpsView] also shows UDFPS animations. At some point we should
+ * de-dupe this if necessary.
+ */
+class UdfpsBpView(context: Context, attrs: AttributeSet?) : UdfpsAnimationView(context, attrs) {
+
+ // Drawable isn't ever added to the view, so we don't currently show anything
+ private val fingerprintDrawable: UdfpsFpDrawable = UdfpsFpDrawable(context)
+
+ override fun getDrawable(): UdfpsDrawable = fingerprintDrawable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java
deleted file mode 100644
index 3732100..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import android.annotation.NonNull;
-
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
-import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
-
-/**
- * Class that coordinates non-HBM animations for biometric prompt.
- */
-class UdfpsBpViewController extends UdfpsAnimationViewController<UdfpsBpView> {
- protected UdfpsBpViewController(
- @NonNull UdfpsBpView view,
- @NonNull StatusBarStateController statusBarStateController,
- @NonNull PanelExpansionStateManager panelExpansionStateManager,
- @NonNull SystemUIDialogManager systemUIDialogManager,
- @NonNull DumpManager dumpManager) {
- super(view, statusBarStateController, panelExpansionStateManager,
- systemUIDialogManager, dumpManager);
- }
-
- @Override
- @NonNull String getTag() {
- return "UdfpsBpViewController";
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt
new file mode 100644
index 0000000..4cd40d2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.biometrics
+
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
+
+/**
+ * Class that coordinates non-HBM animations for biometric prompt.
+ */
+class UdfpsBpViewController(
+ view: UdfpsBpView,
+ statusBarStateController: StatusBarStateController,
+ panelExpansionStateManager: PanelExpansionStateManager,
+ systemUIDialogManager: SystemUIDialogManager,
+ dumpManager: DumpManager
+) : UdfpsAnimationViewController<UdfpsBpView>(
+ view,
+ statusBarStateController,
+ panelExpansionStateManager,
+ systemUIDialogManager,
+ dumpManager
+) {
+ override val tag = "UdfpsBpViewController"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 1da9f21..fd7ae32 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -24,15 +24,11 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.graphics.PixelFormat;
-import android.graphics.Point;
import android.graphics.RectF;
-import android.hardware.biometrics.BiometricOverlayConstants;
import android.hardware.biometrics.SensorLocationInternal;
import android.hardware.display.DisplayManager;
import android.hardware.fingerprint.FingerprintManager;
@@ -42,24 +38,21 @@
import android.os.Handler;
import android.os.PowerManager;
import android.os.Process;
-import android.os.RemoteException;
import android.os.Trace;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.Log;
-import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
-import android.view.Surface;
import android.view.VelocityTracker;
import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeReceiver;
@@ -95,7 +88,7 @@
* controls/manages all UDFPS sensors. In other words, a single controller is registered with
* {@link com.android.server.biometrics.sensors.fingerprint.FingerprintService}, and interfaces such
* as {@link FingerprintManager#onPointerDown(int, int, int, float, float)} or
- * {@link IUdfpsOverlayController#showUdfpsOverlay(int)} should all have
+ * {@link IUdfpsOverlayController#showUdfpsOverlay} should all have
* {@code sensorId} parameters.
*/
@SuppressWarnings("deprecation")
@@ -132,11 +125,11 @@
@NonNull private final SystemClock mSystemClock;
@NonNull private final UnlockedScreenOffAnimationController
mUnlockedScreenOffAnimationController;
+ @NonNull private final LatencyTracker mLatencyTracker;
@VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener;
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
// sensors, this, in addition to a lot of the code here, will be updated.
@VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
- private final WindowManager.LayoutParams mCoreLayoutParams;
// Tracks the velocity of a touch to help filter out the touches that move too fast.
@Nullable private VelocityTracker mVelocityTracker;
@@ -150,9 +143,8 @@
// TODO: We should probably try to make touch/illumination things more of a FSM
private boolean mGoodCaptureReceived;
- @Nullable private UdfpsView mView;
// The current request from FingerprintService. Null if no current request.
- @Nullable ServerRequest mServerRequest;
+ @Nullable UdfpsControllerOverlay mOverlay;
// The fingerprint AOD trigger doesn't provide an ACTION_UP/ACTION_CANCEL event to tell us when
// to turn off high brightness mode. To get around this limitation, the state of the AOD
@@ -164,7 +156,7 @@
private Runnable mAodInterruptRunnable;
private boolean mOnFingerDown;
private boolean mAttemptedToDismissKeyguard;
- private Set<Callback> mCallbacks = new HashSet<>();
+ private final Set<Callback> mCallbacks = new HashSet<>();
@VisibleForTesting
public static final VibrationAttributes VIBRATION_ATTRIBUTES =
@@ -193,67 +185,20 @@
}
};
- /**
- * Keeps track of state within a single FingerprintService request. Note that this state
- * persists across configuration changes, etc, since it is considered a single request.
- *
- * TODO: Perhaps we can move more global variables into here
- */
- private static class ServerRequest {
- // Reason the overlay has been requested. See IUdfpsOverlayController for definitions.
- final int mRequestReason;
- @NonNull final IUdfpsOverlayControllerCallback mCallback;
- @Nullable final UdfpsEnrollHelper mEnrollHelper;
-
- ServerRequest(int requestReason, @NonNull IUdfpsOverlayControllerCallback callback,
- @Nullable UdfpsEnrollHelper enrollHelper) {
- mRequestReason = requestReason;
- mCallback = callback;
- mEnrollHelper = enrollHelper;
- }
-
- void onEnrollmentProgress(int remaining) {
- if (mEnrollHelper != null) {
- mEnrollHelper.onEnrollmentProgress(remaining);
- }
- }
-
- void onAcquiredGood() {
- if (mEnrollHelper != null) {
- mEnrollHelper.animateIfLastStep();
- }
- }
-
- void onEnrollmentHelp() {
- if (mEnrollHelper != null) {
- mEnrollHelper.onEnrollmentHelp();
- }
- }
-
- void onUserCanceled() {
- try {
- mCallback.onUserCanceled();
- } catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
- }
- }
- }
-
public class UdfpsOverlayController extends IUdfpsOverlayController.Stub {
@Override
public void showUdfpsOverlay(int sensorId, int reason,
@NonNull IUdfpsOverlayControllerCallback callback) {
- mFgExecutor.execute(() -> {
- final UdfpsEnrollHelper enrollHelper;
- if (reason == BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
- || reason == BiometricOverlayConstants.REASON_ENROLL_ENROLLING) {
- enrollHelper = new UdfpsEnrollHelper(mContext, mFingerprintManager, reason);
- } else {
- enrollHelper = null;
- }
- mServerRequest = new ServerRequest(reason, callback, enrollHelper);
- updateOverlay();
- });
+ mFgExecutor.execute(
+ () -> UdfpsController.this.showUdfpsOverlay(new UdfpsControllerOverlay(
+ mContext, mFingerprintManager, mInflater, mWindowManager,
+ mAccessibilityManager, mStatusBarStateController,
+ mPanelExpansionStateManager, mKeyguardViewManager,
+ mKeyguardUpdateMonitor, mDialogManager, mDumpManager,
+ mLockscreenShadeTransitionController, mConfigurationController,
+ mSystemClock, mKeyguardStateController,
+ mUnlockedScreenOffAnimationController, mSensorProps, mHbmProvider,
+ reason, callback, UdfpsController.this::onTouch)));
}
@Override
@@ -266,57 +211,55 @@
+ "mKeyguardUpdateMonitor.isFingerprintDetectionRunning()=true");
}
- mServerRequest = null;
- updateOverlay();
+ UdfpsController.this.hideUdfpsOverlay();
});
}
@Override
public void onAcquiredGood(int sensorId) {
mFgExecutor.execute(() -> {
- if (mView == null) {
- Log.e(TAG, "Null view when onAcquiredGood for sensorId: " + sensorId);
+ if (mOverlay == null) {
+ Log.e(TAG, "Null request when onAcquiredGood for sensorId: " + sensorId);
return;
}
mGoodCaptureReceived = true;
- mView.stopIllumination();
- if (mServerRequest != null) {
- mServerRequest.onAcquiredGood();
- } else {
- Log.e(TAG, "Null serverRequest when onAcquiredGood");
+ final UdfpsView view = mOverlay.getOverlayView();
+ if (view != null) {
+ view.stopIllumination();
}
+ mOverlay.onAcquiredGood();
});
}
@Override
public void onEnrollmentProgress(int sensorId, int remaining) {
mFgExecutor.execute(() -> {
- if (mServerRequest == null) {
+ if (mOverlay == null) {
Log.e(TAG, "onEnrollProgress received but serverRequest is null");
return;
}
- mServerRequest.onEnrollmentProgress(remaining);
+ mOverlay.onEnrollmentProgress(remaining);
});
}
@Override
public void onEnrollmentHelp(int sensorId) {
mFgExecutor.execute(() -> {
- if (mServerRequest == null) {
+ if (mOverlay == null) {
Log.e(TAG, "onEnrollmentHelp received but serverRequest is null");
return;
}
- mServerRequest.onEnrollmentHelp();
+ mOverlay.onEnrollmentHelp();
});
}
@Override
public void setDebugMessage(int sensorId, String message) {
mFgExecutor.execute(() -> {
- if (mView == null) {
+ if (mOverlay == null || mOverlay.isHiding()) {
return;
}
- mView.setDebugMessage(message);
+ mOverlay.getOverlayView().setDebugMessage(message);
});
}
}
@@ -341,14 +284,13 @@
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (mServerRequest != null
- && mServerRequest.mRequestReason != REASON_AUTH_KEYGUARD
+ if (mOverlay != null
+ && mOverlay.getRequestReason() != REASON_AUTH_KEYGUARD
&& Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
Log.d(TAG, "ACTION_CLOSE_SYSTEM_DIALOGS received, mRequestReason: "
- + mServerRequest.mRequestReason);
- mServerRequest.onUserCanceled();
- mServerRequest = null;
- updateOverlay();
+ + mOverlay.getRequestReason());
+ mOverlay.cancel();
+ hideUdfpsOverlay();
}
}
};
@@ -357,23 +299,12 @@
* Forwards touches to the udfps controller / view
*/
public boolean onTouch(MotionEvent event) {
- if (mView == null) {
+ if (mOverlay == null || mOverlay.isHiding()) {
return false;
}
- return onTouch(mView, event, false);
+ return onTouch(mOverlay.getOverlayView(), event, false);
}
- @SuppressLint("ClickableViewAccessibility")
- private final UdfpsView.OnTouchListener mOnTouchListener = (view, event) ->
- onTouch(view, event, true);
-
- @SuppressLint("ClickableViewAccessibility")
- private final UdfpsView.OnHoverListener mOnHoverListener = (view, event) ->
- onTouch(view, event, true);
-
- private final AccessibilityManager.TouchExplorationStateChangeListener
- mTouchExplorationStateChangeListener = enabled -> updateTouchListener();
-
/**
* @param x coordinate
* @param y coordinate
@@ -387,15 +318,15 @@
return udfpsView.isWithinSensorArea(x, y);
}
- if (mView == null || mView.getAnimationViewController() == null) {
+ if (mOverlay == null || mOverlay.getAnimationViewController() == null) {
return false;
}
- return !mView.getAnimationViewController().shouldPauseAuth()
+ return !mOverlay.getAnimationViewController().shouldPauseAuth()
&& getSensorLocation().contains(x, y);
}
- private boolean onTouch(View view, MotionEvent event, boolean fromUdfpsView) {
+ private boolean onTouch(@NonNull View view, @NonNull MotionEvent event, boolean fromUdfpsView) {
UdfpsView udfpsView = (UdfpsView) view;
final boolean isIlluminationRequested = udfpsView.isIlluminationRequested();
boolean handled = false;
@@ -419,6 +350,7 @@
boolean withinSensorArea =
isWithinSensorArea(udfpsView, event.getX(), event.getY(), fromUdfpsView);
if (withinSensorArea) {
+ mLatencyTracker.onActionStart(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
Trace.beginAsyncSection("UdfpsController.e2e.onPointerDown", 0);
Log.v(TAG, "onTouch | action down");
// The pointer that causes ACTION_DOWN is always at index 0.
@@ -492,7 +424,7 @@
}
} else {
Log.v(TAG, "onTouch | finger outside");
- onFingerUp();
+ onFingerUp(udfpsView);
}
}
Trace.endSection();
@@ -509,7 +441,7 @@
}
Log.v(TAG, "onTouch | finger up");
mAttemptedToDismissKeyguard = false;
- onFingerUp();
+ onFingerUp(udfpsView);
mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
Trace.endSection();
break;
@@ -521,8 +453,8 @@
}
private boolean shouldTryToDismissKeyguard() {
- return mView.getAnimationViewController() != null
- && mView.getAnimationViewController() instanceof UdfpsKeyguardViewController
+ return mOverlay != null
+ && mOverlay.getAnimationViewController() instanceof UdfpsKeyguardViewController
&& mKeyguardStateController.canDismissLockScreen()
&& !mAttemptedToDismissKeyguard;
}
@@ -554,7 +486,8 @@
@NonNull ConfigurationController configurationController,
@NonNull SystemClock systemClock,
@NonNull UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
- @NonNull SystemUIDialogManager dialogManager) {
+ @NonNull SystemUIDialogManager dialogManager,
+ @NonNull LatencyTracker latencyTracker) {
mContext = context;
mExecution = execution;
mVibrator = vibrator;
@@ -582,6 +515,7 @@
mConfigurationController = configurationController;
mSystemClock = systemClock;
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
+ mLatencyTracker = latencyTracker;
mSensorProps = findFirstUdfps();
// At least one UDFPS sensor exists
@@ -596,17 +530,6 @@
return Unit.INSTANCE;
});
- mCoreLayoutParams = new WindowManager.LayoutParams(
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
- 0 /* flags set in computeLayoutParams() */,
- PixelFormat.TRANSLUCENT);
- mCoreLayoutParams.setTitle(TAG);
- mCoreLayoutParams.setFitInsetsTypes(0);
- mCoreLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
- mCoreLayoutParams.layoutInDisplayCutoutMode =
- WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- mCoreLayoutParams.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
-
mFingerprintManager.setUdfpsOverlayController(new UdfpsOverlayController());
final IntentFilter filter = new IntentFilter();
@@ -644,8 +567,11 @@
@Override
public void dozeTimeTick() {
- if (mView != null) {
- mView.dozeTimeTick();
+ if (mOverlay != null) {
+ final UdfpsView view = mOverlay.getOverlayView();
+ if (view != null) {
+ view.dozeTimeTick();
+ }
}
}
@@ -664,233 +590,63 @@
location.sensorLocationY + location.sensorRadius);
}
- private void updateOverlay() {
- mExecution.assertIsMainThread();
-
- if (mServerRequest != null) {
- showUdfpsOverlay(mServerRequest);
- } else {
+ private void redrawOverlay() {
+ UdfpsControllerOverlay overlay = mOverlay;
+ if (overlay != null) {
hideUdfpsOverlay();
+ showUdfpsOverlay(overlay);
}
}
- private boolean shouldRotate(@Nullable UdfpsAnimationViewController animation) {
- if (!(animation instanceof UdfpsKeyguardViewController)) {
- // always rotate view if we're not on the keyguard
- return true;
- }
-
- // on the keyguard, make sure we don't rotate if we're going to sleep or not occluded
- if (mKeyguardUpdateMonitor.isGoingToSleep() || !mKeyguardStateController.isOccluded()) {
- return false;
- }
-
- return true;
- }
-
- private WindowManager.LayoutParams computeLayoutParams(
- @Nullable UdfpsAnimationViewController animation) {
- final int paddingX = animation != null ? animation.getPaddingX() : 0;
- final int paddingY = animation != null ? animation.getPaddingY() : 0;
-
- mCoreLayoutParams.flags = Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
- if (animation != null && animation.listenForTouchesOutsideView()) {
- mCoreLayoutParams.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
- }
-
- // Default dimensions assume portrait mode.
- final SensorLocationInternal location = mSensorProps.getLocation();
- mCoreLayoutParams.x = location.sensorLocationX - location.sensorRadius - paddingX;
- mCoreLayoutParams.y = location.sensorLocationY - location.sensorRadius - paddingY;
- mCoreLayoutParams.height = 2 * location.sensorRadius + 2 * paddingX;
- mCoreLayoutParams.width = 2 * location.sensorRadius + 2 * paddingY;
-
- Point p = new Point();
- // Gets the size based on the current rotation of the display.
- mContext.getDisplay().getRealSize(p);
-
- // Transform dimensions if the device is in landscape mode
- switch (mContext.getDisplay().getRotation()) {
- case Surface.ROTATION_90:
- if (!shouldRotate(animation)) {
- Log.v(TAG, "skip rotating udfps location ROTATION_90");
- break;
- } else {
- Log.v(TAG, "rotate udfps location ROTATION_90");
- }
- mCoreLayoutParams.x = location.sensorLocationY - location.sensorRadius
- - paddingX;
- mCoreLayoutParams.y = p.y - location.sensorLocationX - location.sensorRadius
- - paddingY;
- break;
-
- case Surface.ROTATION_270:
- if (!shouldRotate(animation)) {
- Log.v(TAG, "skip rotating udfps location ROTATION_270");
- break;
- } else {
- Log.v(TAG, "rotate udfps location ROTATION_270");
- }
- mCoreLayoutParams.x = p.x - location.sensorLocationY - location.sensorRadius
- - paddingX;
- mCoreLayoutParams.y = location.sensorLocationX - location.sensorRadius
- - paddingY;
- break;
-
- default:
- // Do nothing to stay in portrait mode.
- // Keyguard is always in portrait mode.
- }
- // avoid announcing window title
- mCoreLayoutParams.accessibilityTitle = " ";
- return mCoreLayoutParams;
- }
-
-
private void onOrientationChanged() {
// When the configuration changes it's almost always necessary to destroy and re-create
// the overlay's window to pass it the new LayoutParams.
// Hiding the overlay will destroy its window. It's safe to hide the overlay regardless
// of whether it is already hidden.
final boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateAuth();
- hideUdfpsOverlay();
// If the overlay needs to be shown, this will re-create and show the overlay with the
// updated LayoutParams. Otherwise, the overlay will remain hidden.
- updateOverlay();
+ redrawOverlay();
if (wasShowingAltAuth) {
mKeyguardViewManager.showGenericBouncer(true);
}
}
- private void showUdfpsOverlay(@NonNull ServerRequest request) {
+ private void showUdfpsOverlay(@NonNull UdfpsControllerOverlay overlay) {
mExecution.assertIsMainThread();
- final int reason = request.mRequestReason;
- if (mView == null) {
- try {
- Log.v(TAG, "showUdfpsOverlay | adding window reason=" + reason);
-
- mView = (UdfpsView) mInflater.inflate(R.layout.udfps_view, null, false);
- mOnFingerDown = false;
- mView.setSensorProperties(mSensorProps);
- mView.setHbmProvider(mHbmProvider);
- UdfpsAnimationViewController<?> animation = inflateUdfpsAnimation(reason);
- mAttemptedToDismissKeyguard = false;
- if (animation != null) {
- animation.init();
- mView.setAnimationViewController(animation);
- }
- mOrientationListener.enable();
-
- // This view overlaps the sensor area, so prevent it from being selectable
- // during a11y.
- if (reason == BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
- || reason == BiometricOverlayConstants.REASON_ENROLL_ENROLLING
- || reason == BiometricOverlayConstants.REASON_AUTH_BP) {
- mView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
- }
-
- mWindowManager.addView(mView, computeLayoutParams(animation));
- mAccessibilityManager.addTouchExplorationStateChangeListener(
- mTouchExplorationStateChangeListener);
- updateTouchListener();
- } catch (RuntimeException e) {
- Log.e(TAG, "showUdfpsOverlay | failed to add window", e);
- }
+ mOverlay = overlay;
+ if (overlay.show(this)) {
+ Log.v(TAG, "showUdfpsOverlay | adding window reason="
+ + overlay.getRequestReason());
+ mOnFingerDown = false;
+ mAttemptedToDismissKeyguard = false;
+ mOrientationListener.enable();
} else {
Log.v(TAG, "showUdfpsOverlay | the overlay is already showing");
}
}
- @Nullable
- private UdfpsAnimationViewController<?> inflateUdfpsAnimation(int reason) {
- switch (reason) {
- case BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR:
- case BiometricOverlayConstants.REASON_ENROLL_ENROLLING:
- UdfpsEnrollView enrollView = (UdfpsEnrollView) mInflater.inflate(
- R.layout.udfps_enroll_view, null);
- mView.addView(enrollView);
- enrollView.updateSensorLocation(mSensorProps);
- return new UdfpsEnrollViewController(
- enrollView,
- mServerRequest.mEnrollHelper,
- mStatusBarStateController,
- mPanelExpansionStateManager,
- mDialogManager,
- mDumpManager
- );
- case BiometricOverlayConstants.REASON_AUTH_KEYGUARD:
- UdfpsKeyguardView keyguardView = (UdfpsKeyguardView)
- mInflater.inflate(R.layout.udfps_keyguard_view, null);
- mView.addView(keyguardView);
- return new UdfpsKeyguardViewController(
- keyguardView,
- mStatusBarStateController,
- mPanelExpansionStateManager,
- mKeyguardViewManager,
- mKeyguardUpdateMonitor,
- mDumpManager,
- mLockscreenShadeTransitionController,
- mConfigurationController,
- mSystemClock,
- mKeyguardStateController,
- mUnlockedScreenOffAnimationController,
- mDialogManager,
- this
- );
- case BiometricOverlayConstants.REASON_AUTH_BP:
- // note: empty controller, currently shows no visual affordance
- UdfpsBpView bpView = (UdfpsBpView) mInflater.inflate(R.layout.udfps_bp_view, null);
- mView.addView(bpView);
- return new UdfpsBpViewController(
- bpView,
- mStatusBarStateController,
- mPanelExpansionStateManager,
- mDialogManager,
- mDumpManager
- );
- case BiometricOverlayConstants.REASON_AUTH_OTHER:
- case BiometricOverlayConstants.REASON_AUTH_SETTINGS:
- UdfpsFpmOtherView authOtherView = (UdfpsFpmOtherView)
- mInflater.inflate(R.layout.udfps_fpm_other_view, null);
- mView.addView(authOtherView);
- return new UdfpsFpmOtherViewController(
- authOtherView,
- mStatusBarStateController,
- mPanelExpansionStateManager,
- mDialogManager,
- mDumpManager
- );
- default:
- Log.e(TAG, "Animation for reason " + reason + " not supported yet");
- return null;
- }
- }
-
private void hideUdfpsOverlay() {
mExecution.assertIsMainThread();
- if (mView != null) {
- Log.v(TAG, "hideUdfpsOverlay | removing window");
+ if (mOverlay != null) {
// Reset the controller back to its starting state.
- onFingerUp();
- boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateAuth();
- mWindowManager.removeView(mView);
- mView.setOnTouchListener(null);
- mView.setOnHoverListener(null);
- mView.setAnimationViewController(null);
- if (wasShowingAltAuth) {
+ final UdfpsView oldView = mOverlay.getOverlayView();
+ if (oldView != null) {
+ onFingerUp(oldView);
+ }
+ final boolean removed = mOverlay.hide();
+ if (mKeyguardViewManager.isShowingAlternateAuth()) {
mKeyguardViewManager.resetAlternateAuth(true);
}
- mAccessibilityManager.removeTouchExplorationStateChangeListener(
- mTouchExplorationStateChangeListener);
- mView = null;
+ Log.v(TAG, "hideUdfpsOverlay | removing window: " + removed);
} else {
Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden");
}
+ mOverlay = null;
mOrientationListener.disable();
}
@@ -954,7 +710,9 @@
* the user lifts their finger.
*/
void onCancelUdfps() {
- onFingerUp();
+ if (mOverlay != null && mOverlay.getOverlayView() != null) {
+ onFingerUp(mOverlay.getOverlayView());
+ }
if (!mIsAodInterruptActive) {
return;
}
@@ -971,12 +729,12 @@
private void onFingerDown(int x, int y, float minor, float major) {
mExecution.assertIsMainThread();
- if (mView == null) {
- Log.w(TAG, "Null view in onFingerDown");
+ if (mOverlay == null) {
+ Log.w(TAG, "Null request in onFingerDown");
return;
}
- if (mView.getAnimationViewController() instanceof UdfpsKeyguardViewController
+ if (mOverlay.getAnimationViewController() instanceof UdfpsKeyguardViewController
&& !mStatusBarStateController.isDozing()) {
mKeyguardBypassController.setUserHasDeviceEntryIntent(true);
}
@@ -991,25 +749,26 @@
mOnFingerDown = true;
mFingerprintManager.onPointerDown(mSensorProps.sensorId, x, y, minor, major);
Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0);
- Trace.beginAsyncSection("UdfpsController.e2e.startIllumination", 0);
- mView.startIllumination(() -> {
- mFingerprintManager.onUiReady(mSensorProps.sensorId);
- Trace.endAsyncSection("UdfpsController.e2e.startIllumination", 0);
- });
+
+ final UdfpsView view = mOverlay.getOverlayView();
+ if (view != null) {
+ Trace.beginAsyncSection("UdfpsController.e2e.startIllumination", 0);
+ view.startIllumination(() -> {
+ mFingerprintManager.onUiReady(mSensorProps.sensorId);
+ mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
+ Trace.endAsyncSection("UdfpsController.e2e.startIllumination", 0);
+ });
+ }
for (Callback cb : mCallbacks) {
cb.onFingerDown();
}
}
- private void onFingerUp() {
+ private void onFingerUp(@NonNull UdfpsView view) {
mExecution.assertIsMainThread();
mActivePointerId = -1;
mGoodCaptureReceived = false;
- if (mView == null) {
- Log.w(TAG, "Null view in onFingerUp");
- return;
- }
if (mOnFingerDown) {
mFingerprintManager.onPointerUp(mSensorProps.sensorId);
for (Callback cb : mCallbacks) {
@@ -1017,22 +776,8 @@
}
}
mOnFingerDown = false;
- if (mView.isIlluminationRequested()) {
- mView.stopIllumination();
- }
- }
-
- private void updateTouchListener() {
- if (mView == null) {
- return;
- }
-
- if (mAccessibilityManager.isTouchExplorationEnabled()) {
- mView.setOnHoverListener(mOnHoverListener);
- mView.setOnTouchListener(null);
- } else {
- mView.setOnHoverListener(null);
- mView.setOnTouchListener(mOnTouchListener);
+ if (view.isIlluminationRequested()) {
+ view.stopIllumination();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
new file mode 100644
index 0000000..e091250
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics
+
+import android.annotation.SuppressLint
+import android.annotation.UiThread
+import android.content.Context
+import android.graphics.PixelFormat
+import android.graphics.Point
+import android.hardware.biometrics.BiometricOverlayConstants
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
+import android.hardware.biometrics.BiometricOverlayConstants.ShowReason
+import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.fingerprint.FingerprintManager
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
+import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
+import android.os.RemoteException
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.MotionEvent
+import android.view.Surface
+import android.view.View
+import android.view.WindowManager
+import android.view.accessibility.AccessibilityManager
+import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener
+import androidx.annotation.LayoutRes
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.R
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.LockscreenShadeTransitionController
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.time.SystemClock
+
+private const val TAG = "UdfpsControllerOverlay"
+
+/**
+ * Keeps track of the overlay state and UI resources associated with a single FingerprintService
+ * request. This state can persist across configuration changes via the [show] and [hide]
+ * methods.
+ */
+@UiThread
+class UdfpsControllerOverlay(
+ private val context: Context,
+ fingerprintManager: FingerprintManager,
+ private val inflater: LayoutInflater,
+ private val windowManager: WindowManager,
+ private val accessibilityManager: AccessibilityManager,
+ private val statusBarStateController: StatusBarStateController,
+ private val panelExpansionStateManager: PanelExpansionStateManager,
+ private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val dialogManager: SystemUIDialogManager,
+ private val dumpManager: DumpManager,
+ private val transitionController: LockscreenShadeTransitionController,
+ private val configurationController: ConfigurationController,
+ private val systemClock: SystemClock,
+ private val keyguardStateController: KeyguardStateController,
+ private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
+ private val sensorProps: FingerprintSensorPropertiesInternal,
+ private var hbmProvider: UdfpsHbmProvider,
+ @ShowReason val requestReason: Int,
+ private val controllerCallback: IUdfpsOverlayControllerCallback,
+ private val onTouch: (View, MotionEvent, Boolean) -> Boolean
+) {
+ /** The view, when [isShowing], or null. */
+ var overlayView: UdfpsView? = null
+ private set
+
+ private var overlayTouchListener: TouchExplorationStateChangeListener? = null
+
+ private val coreLayoutParams = WindowManager.LayoutParams(
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
+ 0 /* flags set in computeLayoutParams() */,
+ PixelFormat.TRANSLUCENT
+ ).apply {
+ title = TAG
+ fitInsetsTypes = 0
+ gravity = android.view.Gravity.TOP or android.view.Gravity.LEFT
+ layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
+ }
+
+ /** A helper if the [requestReason] was due to enrollment. */
+ val enrollHelper: UdfpsEnrollHelper? = if (requestReason.isEnrollmentReason()) {
+ UdfpsEnrollHelper(context, fingerprintManager, requestReason)
+ } else {
+ null
+ }
+
+ /** If the overlay is currently showing. */
+ val isShowing: Boolean
+ get() = overlayView != null
+
+ /** Opposite of [isShowing]. */
+ val isHiding: Boolean
+ get() = overlayView == null
+
+ /** The animation controller if the overlay [isShowing]. */
+ val animationViewController: UdfpsAnimationViewController<*>?
+ get() = overlayView?.animationViewController
+
+ /** Show the overlay or return false and do nothing if it is already showing. */
+ @SuppressLint("ClickableViewAccessibility")
+ fun show(controller: UdfpsController): Boolean {
+ if (overlayView == null) {
+ try {
+ overlayView = (inflater.inflate(
+ R.layout.udfps_view, null, false
+ ) as UdfpsView).apply {
+ sensorProperties = sensorProps
+ setHbmProvider(hbmProvider)
+ val animation = inflateUdfpsAnimation(this, controller)
+ if (animation != null) {
+ animation.init()
+ animationViewController = animation
+ }
+ // This view overlaps the sensor area
+ // prevent it from being selectable during a11y
+ if (requestReason.isImportantForAccessibility()) {
+ importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
+ }
+
+ windowManager.addView(this,
+ coreLayoutParams.updateForLocation(sensorProps.location, animation))
+
+ overlayTouchListener = TouchExplorationStateChangeListener {
+ if (accessibilityManager.isTouchExplorationEnabled) {
+ setOnHoverListener { v, event -> onTouch(v, event, true) }
+ setOnTouchListener(null)
+ } else {
+ setOnHoverListener(null)
+ setOnTouchListener { v, event -> onTouch(v, event, true) }
+ }
+ }
+ accessibilityManager.addTouchExplorationStateChangeListener(
+ overlayTouchListener!!
+ )
+ overlayTouchListener?.onTouchExplorationStateChanged(true)
+ }
+ } catch (e: RuntimeException) {
+ Log.e(TAG, "showUdfpsOverlay | failed to add window", e)
+ }
+ return true
+ }
+
+ Log.v(TAG, "showUdfpsOverlay | the overlay is already showing")
+ return false
+ }
+
+ private fun inflateUdfpsAnimation(
+ view: UdfpsView,
+ controller: UdfpsController
+ ): UdfpsAnimationViewController<*>? {
+ return when (requestReason) {
+ REASON_ENROLL_FIND_SENSOR,
+ REASON_ENROLL_ENROLLING -> {
+ UdfpsEnrollViewController(
+ view.addUdfpsView(R.layout.udfps_enroll_view) {
+ updateSensorLocation(sensorProps)
+ },
+ enrollHelper ?: throw IllegalStateException("no enrollment helper"),
+ statusBarStateController,
+ panelExpansionStateManager,
+ dialogManager,
+ dumpManager
+ )
+ }
+ BiometricOverlayConstants.REASON_AUTH_KEYGUARD -> {
+ UdfpsKeyguardViewController(
+ view.addUdfpsView(R.layout.udfps_keyguard_view),
+ statusBarStateController,
+ panelExpansionStateManager,
+ statusBarKeyguardViewManager,
+ keyguardUpdateMonitor,
+ dumpManager,
+ transitionController,
+ configurationController,
+ systemClock,
+ keyguardStateController,
+ unlockedScreenOffAnimationController,
+ dialogManager,
+ controller
+ )
+ }
+ BiometricOverlayConstants.REASON_AUTH_BP -> {
+ // note: empty controller, currently shows no visual affordance
+ UdfpsBpViewController(
+ view.addUdfpsView(R.layout.udfps_bp_view),
+ statusBarStateController,
+ panelExpansionStateManager,
+ dialogManager,
+ dumpManager
+ )
+ }
+ BiometricOverlayConstants.REASON_AUTH_OTHER,
+ BiometricOverlayConstants.REASON_AUTH_SETTINGS -> {
+ UdfpsFpmOtherViewController(
+ view.addUdfpsView(R.layout.udfps_fpm_other_view),
+ statusBarStateController,
+ panelExpansionStateManager,
+ dialogManager,
+ dumpManager
+ )
+ }
+ else -> {
+ Log.e(TAG, "Animation for reason $requestReason not supported yet")
+ null
+ }
+ }
+ }
+
+ /** Hide the overlay or return false and do nothing if it is already hidden. */
+ fun hide(): Boolean {
+ val wasShowing = isShowing
+
+ overlayView?.apply {
+ if (isIlluminationRequested) {
+ stopIllumination()
+ }
+ windowManager.removeView(this)
+ setOnTouchListener(null)
+ setOnHoverListener(null)
+ animationViewController = null
+ overlayTouchListener?.let {
+ accessibilityManager.removeTouchExplorationStateChangeListener(it)
+ }
+ }
+ overlayView = null
+ overlayTouchListener = null
+
+ return wasShowing
+ }
+
+ fun onEnrollmentProgress(remaining: Int) {
+ enrollHelper?.onEnrollmentProgress(remaining)
+ }
+
+ fun onAcquiredGood() {
+ enrollHelper?.animateIfLastStep()
+ }
+
+ fun onEnrollmentHelp() {
+ enrollHelper?.onEnrollmentHelp()
+ }
+
+ /** Cancel this request. */
+ fun cancel() {
+ try {
+ controllerCallback.onUserCanceled()
+ } catch (e: RemoteException) {
+ Log.e(TAG, "Remote exception", e)
+ }
+ }
+
+ private fun WindowManager.LayoutParams.updateForLocation(
+ location: SensorLocationInternal,
+ animation: UdfpsAnimationViewController<*>?
+ ): WindowManager.LayoutParams {
+ val paddingX = animation?.paddingX ?: 0
+ val paddingY = animation?.paddingY ?: 0
+ flags = (Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS
+ or WindowManager.LayoutParams.FLAG_SPLIT_TOUCH)
+ if (animation != null && animation.listenForTouchesOutsideView()) {
+ flags = flags or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ }
+
+ // Default dimensions assume portrait mode.
+ x = location.sensorLocationX - location.sensorRadius - paddingX
+ y = location.sensorLocationY - location.sensorRadius - paddingY
+ height = 2 * location.sensorRadius + 2 * paddingX
+ width = 2 * location.sensorRadius + 2 * paddingY
+
+ // Gets the size based on the current rotation of the display.
+ val p = Point()
+ context.display!!.getRealSize(p)
+ when (context.display!!.rotation) {
+ Surface.ROTATION_90 -> {
+ if (!shouldRotate(animation)) {
+ Log.v(TAG, "skip rotating udfps location ROTATION_90")
+ } else {
+ Log.v(TAG, "rotate udfps location ROTATION_90")
+ x = (location.sensorLocationY - location.sensorRadius - paddingX)
+ y = (p.y - location.sensorLocationX - location.sensorRadius - paddingY)
+ }
+ }
+ Surface.ROTATION_270 -> {
+ if (!shouldRotate(animation)) {
+ Log.v(TAG, "skip rotating udfps location ROTATION_270")
+ } else {
+ Log.v(TAG, "rotate udfps location ROTATION_270")
+ x = (p.x - location.sensorLocationY - location.sensorRadius - paddingX)
+ y = (location.sensorLocationX - location.sensorRadius - paddingY)
+ }
+ }
+ else -> {}
+ }
+
+ // avoid announcing window title
+ accessibilityTitle = " "
+
+ return this
+ }
+
+ private fun shouldRotate(animation: UdfpsAnimationViewController<*>?): Boolean {
+ if (animation !is UdfpsKeyguardViewController) {
+ // always rotate view if we're not on the keyguard
+ return true
+ }
+
+ // on the keyguard, make sure we don't rotate if we're going to sleep or not occluded
+ return !(keyguardUpdateMonitor.isGoingToSleep || !keyguardStateController.isOccluded)
+ }
+
+ private inline fun <reified T : View> UdfpsView.addUdfpsView(
+ @LayoutRes id: Int,
+ init: T.() -> Unit = {}
+ ): T {
+ val subView = inflater.inflate(id, null) as T
+ addView(subView)
+ subView.init()
+ return subView
+ }
+}
+
+@ShowReason
+private fun Int.isEnrollmentReason() =
+ this == REASON_ENROLL_FIND_SENSOR || this == REASON_ENROLL_ENROLLING
+
+@ShowReason
+private fun Int.isImportantForAccessibility() =
+ this == REASON_ENROLL_FIND_SENSOR ||
+ this == REASON_ENROLL_ENROLLING ||
+ this == BiometricOverlayConstants.REASON_AUTH_BP
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java
deleted file mode 100644
index 55ed5aa..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import android.content.Context;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.PathShape;
-import android.util.PathParser;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.systemui.R;
-
-/**
- * Abstract base class for drawable displayed when the finger is not touching the
- * sensor area.
- */
-public abstract class UdfpsDrawable extends Drawable {
- static final float DEFAULT_STROKE_WIDTH = 3f;
-
- @NonNull final Context mContext;
- @NonNull final ShapeDrawable mFingerprintDrawable;
- private final Paint mPaint;
- private boolean mIlluminationShowing;
-
- int mAlpha = 255; // 0 - 255
- public UdfpsDrawable(@NonNull Context context) {
- mContext = context;
- final String fpPath = context.getResources().getString(R.string.config_udfpsIcon);
- mFingerprintDrawable = new ShapeDrawable(
- new PathShape(PathParser.createPathFromPathData(fpPath), 72, 72));
- mFingerprintDrawable.mutate();
-
- mPaint = mFingerprintDrawable.getPaint();
- mPaint.setStyle(Paint.Style.STROKE);
- mPaint.setStrokeCap(Paint.Cap.ROUND);
- setStrokeWidth(DEFAULT_STROKE_WIDTH);
- }
-
- void setStrokeWidth(float strokeWidth) {
- mPaint.setStrokeWidth(strokeWidth);
- invalidateSelf();
- }
-
- /**
- * @param sensorRect the rect coordinates for the sensor area
- */
- public void onSensorRectUpdated(@NonNull RectF sensorRect) {
- final int margin = (int) sensorRect.height() / 8;
-
- final Rect bounds = new Rect((int) sensorRect.left + margin,
- (int) sensorRect.top + margin,
- (int) sensorRect.right - margin,
- (int) sensorRect.bottom - margin);
- updateFingerprintIconBounds(bounds);
- }
-
- /**
- * Bounds for the fingerprint icon
- */
- protected void updateFingerprintIconBounds(@NonNull Rect bounds) {
- mFingerprintDrawable.setBounds(bounds);
- invalidateSelf();
- }
-
- @Override
- public void setAlpha(int alpha) {
- mAlpha = alpha;
- mFingerprintDrawable.setAlpha(mAlpha);
- invalidateSelf();
- }
-
- boolean isIlluminationShowing() {
- return mIlluminationShowing;
- }
-
- void setIlluminationShowing(boolean showing) {
- if (mIlluminationShowing == showing) {
- return;
- }
- mIlluminationShowing = showing;
- invalidateSelf();
- }
-
- @Override
- public void setColorFilter(@Nullable ColorFilter colorFilter) {
- }
-
- @Override
- public int getOpacity() {
- return 0;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.kt
new file mode 100644
index 0000000..ee112b4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.biometrics
+
+import android.content.Context
+import android.graphics.ColorFilter
+import android.graphics.Paint
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.ShapeDrawable
+import android.graphics.drawable.shapes.PathShape
+import android.util.PathParser
+import com.android.systemui.R
+
+private const val DEFAULT_STROKE_WIDTH = 3f
+
+/**
+ * Abstract base class for drawable displayed when the finger is not touching the
+ * sensor area.
+ */
+abstract class UdfpsDrawable(
+ protected val context: Context,
+ drawableFactory: (Context) -> ShapeDrawable
+) : Drawable() {
+
+ constructor(context: Context) : this(context, defaultFactory)
+
+ /** Fingerprint affordance. */
+ val fingerprintDrawable: ShapeDrawable = drawableFactory(context)
+
+ private var _alpha: Int = 255 // 0 - 255
+
+ var strokeWidth: Float = fingerprintDrawable.paint.strokeWidth
+ set(value) {
+ field = value
+ fingerprintDrawable.paint.strokeWidth = value
+ invalidateSelf()
+ }
+
+ var isIlluminationShowing: Boolean = false
+ set(showing) {
+ if (field == showing) {
+ return
+ }
+ field = showing
+ invalidateSelf()
+ }
+
+ /** The [sensorRect] coordinates for the sensor area. */
+ open fun onSensorRectUpdated(sensorRect: RectF) {
+ val margin = sensorRect.height().toInt() / 8
+ val bounds = Rect(
+ sensorRect.left.toInt() + margin,
+ sensorRect.top.toInt() + margin,
+ sensorRect.right.toInt() - margin,
+ sensorRect.bottom.toInt() - margin
+ )
+ updateFingerprintIconBounds(bounds)
+ }
+
+ /** Bounds for the fingerprint icon. */
+ protected open fun updateFingerprintIconBounds(bounds: Rect) {
+ fingerprintDrawable.bounds = bounds
+ invalidateSelf()
+ }
+
+ override fun getAlpha(): Int = _alpha
+
+ override fun setAlpha(alpha: Int) {
+ _alpha = alpha
+ fingerprintDrawable.alpha = alpha
+ invalidateSelf()
+ }
+
+ override fun setColorFilter(colorFilter: ColorFilter?) {}
+
+ override fun getOpacity(): Int = 0
+}
+
+private val defaultFactory = { context: Context ->
+ val fpPath = context.resources.getString(R.string.config_udfpsIcon)
+ val drawable = ShapeDrawable(
+ PathShape(PathParser.createPathFromPathData(fpPath), 72f, 72f)
+ )
+ drawable.mutate()
+ drawable.paint.style = Paint.Style.STROKE
+ drawable.paint.strokeCap = Paint.Cap.ROUND
+ drawable.paint.strokeWidth = DEFAULT_STROKE_WIDTH
+ drawable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
index ac38b13..e701511 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
@@ -102,7 +102,7 @@
mSensorOutlinePaint = new Paint(0 /* flags */);
mSensorOutlinePaint.setAntiAlias(true);
- mSensorOutlinePaint.setColor(mContext.getColor(R.color.udfps_moving_target_fill));
+ mSensorOutlinePaint.setColor(context.getColor(R.color.udfps_moving_target_fill));
mSensorOutlinePaint.setStyle(Paint.Style.FILL);
mBlueFill = new Paint(0 /* flags */);
@@ -112,10 +112,10 @@
mMovingTargetFpIcon = context.getResources()
.getDrawable(R.drawable.ic_kg_fingerprint, null);
- mMovingTargetFpIcon.setTint(mContext.getColor(R.color.udfps_enroll_icon));
+ mMovingTargetFpIcon.setTint(context.getColor(R.color.udfps_enroll_icon));
mMovingTargetFpIcon.mutate();
- mFingerprintDrawable.setTint(mContext.getColor(R.color.udfps_enroll_icon));
+ getFingerprintDrawable().setTint(context.getColor(R.color.udfps_enroll_icon));
mHintColorFaded = context.getColor(R.color.udfps_moving_target_fill);
mHintColorHighlight = context.getColor(R.color.udfps_enroll_progress);
@@ -404,9 +404,9 @@
if (mSensorRect != null) {
canvas.drawOval(mSensorRect, mSensorOutlinePaint);
}
- mFingerprintDrawable.draw(canvas);
- mFingerprintDrawable.setAlpha(mAlpha);
- mSensorOutlinePaint.setAlpha(mAlpha);
+ getFingerprintDrawable().draw(canvas);
+ getFingerprintDrawable().setAlpha(getAlpha());
+ mSensorOutlinePaint.setAlpha(getAlpha());
}
// Draw the finger tip or edges hint.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
index ac9e92e..2ca103b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
@@ -66,7 +66,7 @@
}
@Override
- @NonNull String getTag() {
+ @NonNull protected String getTag() {
return "UdfpsEnrollViewController";
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.kt
similarity index 61%
copy from packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java
copy to packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.kt
index 09b6fab..1afa36b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.kt
@@ -13,29 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.systemui.biometrics
-package com.android.systemui.biometrics;
-
-import android.content.Context;
-import android.graphics.Canvas;
-
-import androidx.annotation.NonNull;
+import android.content.Context
+import android.graphics.Canvas
/**
* Draws udfps fingerprint if sensor isn't illuminating.
*/
-public class UdfpsFpDrawable extends UdfpsDrawable {
-
- UdfpsFpDrawable(@NonNull Context context) {
- super(context);
- }
-
- @Override
- public void draw(@NonNull Canvas canvas) {
- if (isIlluminationShowing()) {
- return;
+class UdfpsFpDrawable(context: Context) : UdfpsDrawable(context) {
+ override fun draw(canvas: Canvas) {
+ if (isIlluminationShowing) {
+ return
}
-
- mFingerprintDrawable.draw(canvas);
+ fingerprintDrawable.draw(canvas)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.java
deleted file mode 100644
index 85f1606..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-import androidx.annotation.Nullable;
-
-import com.android.systemui.R;
-
-/**
- * View corresponding with udfps_fpm_other_view.xml
- */
-public class UdfpsFpmOtherView extends UdfpsAnimationView {
- private final UdfpsFpDrawable mFingerprintDrawable;
- private ImageView mFingerprintView;
-
- public UdfpsFpmOtherView(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- mFingerprintDrawable = new UdfpsFpDrawable(context);
- }
-
- @Override
- protected void onFinishInflate() {
- mFingerprintView = findViewById(R.id.udfps_fpm_other_fp_view);
- mFingerprintView.setImageDrawable(mFingerprintDrawable);
- }
-
- @Override
- UdfpsDrawable getDrawable() {
- return mFingerprintDrawable;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.kt
new file mode 100644
index 0000000..4d6da8f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.biometrics
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.ImageView
+import com.android.systemui.R
+
+/**
+ * View corresponding with udfps_fpm_other_view.xml
+ */
+class UdfpsFpmOtherView(
+ context: Context,
+ attrs: AttributeSet?
+) : UdfpsAnimationView(context, attrs) {
+
+ private val fingerprintDrawable: UdfpsFpDrawable = UdfpsFpDrawable(context)
+ private lateinit var fingerprintView: ImageView
+
+ override fun onFinishInflate() {
+ fingerprintView = findViewById(R.id.udfps_fpm_other_fp_view)!!
+ fingerprintView.setImageDrawable(fingerprintDrawable)
+ }
+
+ override fun getDrawable(): UdfpsDrawable = fingerprintDrawable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java
deleted file mode 100644
index 97dca0f..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import android.annotation.NonNull;
-
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
-import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
-
-/**
- * Class that coordinates non-HBM animations for non keyguard, enrollment or biometric prompt
- * states.
- *
- * Currently only shows the fp drawable.
- */
-class UdfpsFpmOtherViewController extends UdfpsAnimationViewController<UdfpsFpmOtherView> {
- protected UdfpsFpmOtherViewController(
- @NonNull UdfpsFpmOtherView view,
- @NonNull StatusBarStateController statusBarStateController,
- @NonNull PanelExpansionStateManager panelExpansionStateManager,
- @NonNull SystemUIDialogManager systemUIDialogManager,
- @NonNull DumpManager dumpManager) {
- super(view, statusBarStateController, panelExpansionStateManager, systemUIDialogManager,
- dumpManager);
- }
-
- @Override
- @NonNull String getTag() {
- return "UdfpsFpmOtherViewController";
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.kt
new file mode 100644
index 0000000..98205cf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.biometrics
+
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
+
+/**
+ * Class that coordinates non-HBM animations for non keyguard, enrollment or biometric prompt
+ * states.
+ *
+ * Currently only shows the fp drawable.
+ */
+class UdfpsFpmOtherViewController(
+ view: UdfpsFpmOtherView,
+ statusBarStateController: StatusBarStateController,
+ panelExpansionStateManager: PanelExpansionStateManager,
+ systemUIDialogManager: SystemUIDialogManager,
+ dumpManager: DumpManager
+) : UdfpsAnimationViewController<UdfpsFpmOtherView>(
+ view,
+ statusBarStateController,
+ panelExpansionStateManager,
+ systemUIDialogManager,
+ dumpManager
+) {
+ override val tag = "UdfpsFpmOtherViewController"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 3e8a568..d90a746 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -102,7 +102,7 @@
}
@Override
- @NonNull String getTag() {
+ @NonNull protected String getTag() {
return "UdfpsKeyguardViewController";
}
@@ -115,21 +115,21 @@
@Override
protected void onViewAttached() {
super.onViewAttached();
- final float dozeAmount = mStatusBarStateController.getDozeAmount();
+ final float dozeAmount = getStatusBarStateController().getDozeAmount();
mLastDozeAmount = dozeAmount;
mStateListener.onDozeAmountChanged(dozeAmount, dozeAmount);
- mStatusBarStateController.addCallback(mStateListener);
+ getStatusBarStateController().addCallback(mStateListener);
mUdfpsRequested = false;
mLaunchTransitionFadingAway = mKeyguardStateController.isLaunchTransitionFadingAway();
mKeyguardStateController.addCallback(mKeyguardStateControllerCallback);
- mStatusBarState = mStatusBarStateController.getState();
+ mStatusBarState = getStatusBarStateController().getState();
mQsExpanded = mKeyguardViewManager.isQsExpanded();
mInputBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN;
mIsBouncerVisible = mKeyguardViewManager.bouncerIsOrWillBeShowing();
mConfigurationController.addCallback(mConfigurationListener);
- mPanelExpansionStateManager.addExpansionListener(mPanelExpansionListener);
+ getPanelExpansionStateManager().addExpansionListener(mPanelExpansionListener);
updateAlpha();
updatePauseAuth();
@@ -144,11 +144,11 @@
mFaceDetectRunning = false;
mKeyguardStateController.removeCallback(mKeyguardStateControllerCallback);
- mStatusBarStateController.removeCallback(mStateListener);
+ getStatusBarStateController().removeCallback(mStateListener);
mKeyguardViewManager.removeAlternateAuthInterceptor(mAlternateAuthInterceptor);
mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
mConfigurationController.removeCallback(mConfigurationListener);
- mPanelExpansionStateManager.removeExpansionListener(mPanelExpansionListener);
+ getPanelExpansionStateManager().removeExpansionListener(mPanelExpansionListener);
if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) {
mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null);
}
@@ -214,13 +214,13 @@
return false;
}
- if (mUdfpsRequested && !mNotificationShadeVisible
+ if (mUdfpsRequested && !getNotificationShadeVisible()
&& (!mIsBouncerVisible
|| mInputBouncerHiddenAmount != KeyguardBouncer.EXPANSION_VISIBLE)) {
return false;
}
- if (mDialogManager.shouldHideAffordance()) {
+ if (getDialogManager().shouldHideAffordance()) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
deleted file mode 100644
index 30e5aed..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (C) 2020 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.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PointF;
-import android.graphics.RectF;
-import android.hardware.biometrics.SensorLocationInternal;
-import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
-import android.os.Build;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.android.systemui.R;
-import com.android.systemui.biometrics.UdfpsHbmTypes.HbmType;
-import com.android.systemui.doze.DozeReceiver;
-
-/**
- * A view containing 1) A SurfaceView for HBM, and 2) A normal drawable view for all other
- * animations.
- */
-public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIlluminator {
- private static final String TAG = "UdfpsView";
-
- private static final String SETTING_HBM_TYPE =
- "com.android.systemui.biometrics.UdfpsSurfaceView.hbmType";
- private static final @HbmType int DEFAULT_HBM_TYPE = UdfpsHbmTypes.LOCAL_HBM;
-
- private static final int DEBUG_TEXT_SIZE_PX = 32;
-
- @NonNull private final RectF mSensorRect;
- @NonNull private final Paint mDebugTextPaint;
- private final float mSensorTouchAreaCoefficient;
- private final int mOnIlluminatedDelayMs;
- private final @HbmType int mHbmType;
-
- // Only used for UdfpsHbmTypes.GLOBAL_HBM.
- @Nullable private UdfpsSurfaceView mGhbmView;
- // Can be different for enrollment, BiometricPrompt, Keyguard, etc.
- @Nullable private UdfpsAnimationViewController mAnimationViewController;
- // Used to obtain the sensor location.
- @NonNull private FingerprintSensorPropertiesInternal mSensorProps;
- @Nullable private UdfpsHbmProvider mHbmProvider;
- @Nullable private String mDebugMessage;
- private boolean mIlluminationRequested;
-
- public UdfpsView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.UdfpsView, 0,
- 0);
- try {
- if (!a.hasValue(R.styleable.UdfpsView_sensorTouchAreaCoefficient)) {
- throw new IllegalArgumentException(
- "UdfpsView must contain sensorTouchAreaCoefficient");
- }
- mSensorTouchAreaCoefficient = a.getFloat(
- R.styleable.UdfpsView_sensorTouchAreaCoefficient, 0f);
- } finally {
- a.recycle();
- }
-
- mSensorRect = new RectF();
-
- mDebugTextPaint = new Paint();
- mDebugTextPaint.setAntiAlias(true);
- mDebugTextPaint.setColor(Color.BLUE);
- mDebugTextPaint.setTextSize(DEBUG_TEXT_SIZE_PX);
-
- mOnIlluminatedDelayMs = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_udfps_illumination_transition_ms);
-
- if (Build.IS_ENG || Build.IS_USERDEBUG) {
- mHbmType = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- SETTING_HBM_TYPE, DEFAULT_HBM_TYPE, UserHandle.USER_CURRENT);
- } else {
- mHbmType = DEFAULT_HBM_TYPE;
- }
- }
-
- // Don't propagate any touch events to the child views.
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- return mAnimationViewController == null
- || !mAnimationViewController.shouldPauseAuth();
- }
-
- @Override
- protected void onFinishInflate() {
- if (mHbmType == UdfpsHbmTypes.GLOBAL_HBM) {
- mGhbmView = findViewById(R.id.hbm_view);
- }
- }
-
- void setSensorProperties(@NonNull FingerprintSensorPropertiesInternal properties) {
- mSensorProps = properties;
- }
-
- @Override
- public void setHbmProvider(@Nullable UdfpsHbmProvider hbmProvider) {
- mHbmProvider = hbmProvider;
- }
-
- @Override
- public void dozeTimeTick() {
- if (mAnimationViewController != null) {
- mAnimationViewController.dozeTimeTick();
- }
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- int paddingX = mAnimationViewController == null ? 0
- : mAnimationViewController.getPaddingX();
- int paddingY = mAnimationViewController == null ? 0
- : mAnimationViewController.getPaddingY();
- final SensorLocationInternal location = mSensorProps.getLocation();
- mSensorRect.set(
- paddingX,
- paddingY,
- 2 * location.sensorRadius + paddingX,
- 2 * location.sensorRadius + paddingY);
-
- if (mAnimationViewController != null) {
- mAnimationViewController.onSensorRectUpdated(new RectF(mSensorRect));
- }
- }
-
- void onTouchOutsideView() {
- if (mAnimationViewController != null) {
- mAnimationViewController.onTouchOutsideView();
- }
- }
-
- void setAnimationViewController(
- @Nullable UdfpsAnimationViewController animationViewController) {
- mAnimationViewController = animationViewController;
- }
-
- @Nullable UdfpsAnimationViewController getAnimationViewController() {
- return mAnimationViewController;
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- Log.v(TAG, "onAttachedToWindow");
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- Log.v(TAG, "onDetachedFromWindow");
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- if (!mIlluminationRequested) {
- if (!TextUtils.isEmpty(mDebugMessage)) {
- canvas.drawText(mDebugMessage, 0, 160, mDebugTextPaint);
- }
- }
- }
-
- void setDebugMessage(String message) {
- mDebugMessage = message;
- postInvalidate();
- }
-
- boolean isWithinSensorArea(float x, float y) {
- // The X and Y coordinates of the sensor's center.
- final PointF translation = mAnimationViewController == null
- ? new PointF(0, 0)
- : mAnimationViewController.getTouchTranslation();
- final float cx = mSensorRect.centerX() + translation.x;
- final float cy = mSensorRect.centerY() + translation.y;
- // Radii along the X and Y axes.
- final float rx = (mSensorRect.right - mSensorRect.left) / 2.0f;
- final float ry = (mSensorRect.bottom - mSensorRect.top) / 2.0f;
-
- return x > (cx - rx * mSensorTouchAreaCoefficient)
- && x < (cx + rx * mSensorTouchAreaCoefficient)
- && y > (cy - ry * mSensorTouchAreaCoefficient)
- && y < (cy + ry * mSensorTouchAreaCoefficient)
- && !mAnimationViewController.shouldPauseAuth();
- }
-
- boolean isIlluminationRequested() {
- return mIlluminationRequested;
- }
-
- /**
- * @param onIlluminatedRunnable Runs when the first illumination frame reaches the panel.
- */
- @Override
- public void startIllumination(@Nullable Runnable onIlluminatedRunnable) {
- mIlluminationRequested = true;
- if (mAnimationViewController != null) {
- mAnimationViewController.onIlluminationStarting();
- }
-
- if (mGhbmView != null) {
- mGhbmView.setGhbmIlluminationListener(this::doIlluminate);
- mGhbmView.setVisibility(View.VISIBLE);
- mGhbmView.startGhbmIllumination(onIlluminatedRunnable);
- } else {
- doIlluminate(null /* surface */, onIlluminatedRunnable);
- }
- }
-
- private void doIlluminate(@Nullable Surface surface, @Nullable Runnable onIlluminatedRunnable) {
- if (mGhbmView != null && surface == null) {
- Log.e(TAG, "doIlluminate | surface must be non-null for GHBM");
- }
- if (mHbmProvider != null) {
- mHbmProvider.enableHbm(mHbmType, surface, () -> {
- if (mGhbmView != null) {
- mGhbmView.drawIlluminationDot(mSensorRect);
- }
- if (onIlluminatedRunnable != null) {
- // No framework API can reliably tell when a frame reaches the panel. A timeout
- // is the safest solution.
- postDelayed(onIlluminatedRunnable, mOnIlluminatedDelayMs);
- } else {
- Log.w(TAG, "doIlluminate | onIlluminatedRunnable is null");
- }
- });
- }
- }
-
- @Override
- public void stopIllumination() {
- mIlluminationRequested = false;
- if (mAnimationViewController != null) {
- mAnimationViewController.onIlluminationStopped();
- }
- if (mGhbmView != null) {
- mGhbmView.setGhbmIlluminationListener(null);
- mGhbmView.setVisibility(View.INVISIBLE);
- }
- if (mHbmProvider != null) {
- mHbmProvider.disableHbm(null /* onHbmDisabled */);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
new file mode 100644
index 0000000..9fbc458
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2020 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.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.PointF
+import android.graphics.RectF
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
+import android.os.Build
+import android.os.UserHandle
+import android.provider.Settings
+import android.util.AttributeSet
+import android.util.Log
+import android.view.MotionEvent
+import android.view.Surface
+import android.widget.FrameLayout
+import com.android.systemui.R
+import com.android.systemui.doze.DozeReceiver
+import com.android.systemui.biometrics.UdfpsHbmTypes.HbmType
+
+private const val TAG = "UdfpsView"
+private const val SETTING_HBM_TYPE = "com.android.systemui.biometrics.UdfpsSurfaceView.hbmType"
+@HbmType
+private const val DEFAULT_HBM_TYPE = UdfpsHbmTypes.LOCAL_HBM
+
+/**
+ * A view containing 1) A SurfaceView for HBM, and 2) A normal drawable view for all other
+ * animations.
+ */
+class UdfpsView(
+ context: Context,
+ attrs: AttributeSet?
+) : FrameLayout(context, attrs), DozeReceiver, UdfpsIlluminator {
+
+ private val sensorRect = RectF()
+ private var hbmProvider: UdfpsHbmProvider? = null
+ private val debugTextPaint = Paint().apply {
+ isAntiAlias = true
+ color = Color.BLUE
+ textSize = 32f
+ }
+
+ private val sensorTouchAreaCoefficient: Float =
+ context.theme.obtainStyledAttributes(attrs, R.styleable.UdfpsView, 0, 0).use { a ->
+ require(a.hasValue(R.styleable.UdfpsView_sensorTouchAreaCoefficient)) {
+ "UdfpsView must contain sensorTouchAreaCoefficient"
+ }
+ a.getFloat(R.styleable.UdfpsView_sensorTouchAreaCoefficient, 0f)
+ }
+
+ private val onIlluminatedDelayMs = context.resources.getInteger(
+ com.android.internal.R.integer.config_udfps_illumination_transition_ms
+ ).toLong()
+
+ @HbmType
+ private val hbmType = if (Build.IS_ENG || Build.IS_USERDEBUG) {
+ Settings.Secure.getIntForUser(
+ context.contentResolver,
+ SETTING_HBM_TYPE,
+ DEFAULT_HBM_TYPE,
+ UserHandle.USER_CURRENT
+ )
+ } else {
+ DEFAULT_HBM_TYPE
+ }
+
+ // Only used for UdfpsHbmTypes.GLOBAL_HBM.
+ private var ghbmView: UdfpsSurfaceView? = null
+
+ /** View controller (can be different for enrollment, BiometricPrompt, Keyguard, etc.). */
+ var animationViewController: UdfpsAnimationViewController<*>? = null
+
+ /** Properties used to obtain the sensor location. */
+ var sensorProperties: FingerprintSensorPropertiesInternal? = null
+
+ /** Debug message. */
+ var debugMessage: String? = null
+ set(value) {
+ field = value
+ postInvalidate()
+ }
+
+ /** When [startIllumination] has been called but not stopped via [stopIllumination]. */
+ var isIlluminationRequested: Boolean = false
+ private set
+
+ override fun setHbmProvider(provider: UdfpsHbmProvider?) {
+ hbmProvider = provider
+ }
+
+ // Don't propagate any touch events to the child views.
+ override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
+ return (animationViewController == null || !animationViewController!!.shouldPauseAuth())
+ }
+
+ override fun onFinishInflate() {
+ if (hbmType == UdfpsHbmTypes.GLOBAL_HBM) {
+ ghbmView = findViewById(R.id.hbm_view)
+ }
+ }
+
+ override fun dozeTimeTick() {
+ animationViewController?.dozeTimeTick()
+ }
+
+ override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
+ super.onLayout(changed, left, top, right, bottom)
+
+ val paddingX = animationViewController?.paddingX ?: 0
+ val paddingY = animationViewController?.paddingY ?: 0
+ val sensorRadius = sensorProperties?.location?.sensorRadius ?: 0
+
+ sensorRect.set(
+ paddingX.toFloat(),
+ paddingY.toFloat(),
+ (2 * sensorRadius + paddingX).toFloat(),
+ (2 * sensorRadius + paddingY).toFloat()
+ )
+ animationViewController?.onSensorRectUpdated(RectF(sensorRect))
+ }
+
+ fun onTouchOutsideView() {
+ animationViewController?.onTouchOutsideView()
+ }
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+ Log.v(TAG, "onAttachedToWindow")
+ }
+
+ override fun onDetachedFromWindow() {
+ super.onDetachedFromWindow()
+ Log.v(TAG, "onDetachedFromWindow")
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ if (!isIlluminationRequested) {
+ if (!debugMessage.isNullOrEmpty()) {
+ canvas.drawText(debugMessage!!, 0f, 160f, debugTextPaint)
+ }
+ }
+ }
+
+ fun isWithinSensorArea(x: Float, y: Float): Boolean {
+ // The X and Y coordinates of the sensor's center.
+ val translation = animationViewController?.touchTranslation ?: PointF(0f, 0f)
+ val cx = sensorRect.centerX() + translation.x
+ val cy = sensorRect.centerY() + translation.y
+ // Radii along the X and Y axes.
+ val rx = (sensorRect.right - sensorRect.left) / 2.0f
+ val ry = (sensorRect.bottom - sensorRect.top) / 2.0f
+
+ return x > cx - rx * sensorTouchAreaCoefficient &&
+ x < cx + rx * sensorTouchAreaCoefficient &&
+ y > cy - ry * sensorTouchAreaCoefficient &&
+ y < cy + ry * sensorTouchAreaCoefficient &&
+ !(animationViewController?.shouldPauseAuth() ?: false)
+ }
+
+ /**
+ * Start and run [onIlluminatedRunnable] when the first illumination frame reaches the panel.
+ */
+ override fun startIllumination(onIlluminatedRunnable: Runnable?) {
+ isIlluminationRequested = true
+ animationViewController?.onIlluminationStarting()
+
+ val gView = ghbmView
+ if (gView != null) {
+ gView.setGhbmIlluminationListener(this::doIlluminate)
+ gView.visibility = VISIBLE
+ gView.startGhbmIllumination(onIlluminatedRunnable)
+ } else {
+ doIlluminate(null /* surface */, onIlluminatedRunnable)
+ }
+ }
+
+ private fun doIlluminate(surface: Surface?, onIlluminatedRunnable: Runnable?) {
+ if (ghbmView != null && surface == null) {
+ Log.e(TAG, "doIlluminate | surface must be non-null for GHBM")
+ }
+
+ hbmProvider?.enableHbm(hbmType, surface) {
+ ghbmView?.drawIlluminationDot(sensorRect)
+ if (onIlluminatedRunnable != null) {
+ // No framework API can reliably tell when a frame reaches the panel. A timeout
+ // is the safest solution.
+ postDelayed(onIlluminatedRunnable, onIlluminatedDelayMs)
+ } else {
+ Log.w(TAG, "doIlluminate | onIlluminatedRunnable is null")
+ }
+ }
+ }
+
+ override fun stopIllumination() {
+ isIlluminationRequested = false
+ animationViewController?.onIlluminationStopped()
+ ghbmView?.let { view ->
+ view.setGhbmIlluminationListener(null)
+ view.visibility = INVISIBLE
+ }
+ hbmProvider?.disableHbm(null /* onHbmDisabled */)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index af06979..cffb2f7 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -23,8 +23,9 @@
import com.android.systemui.SystemUIAppComponentFactory;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
-import com.android.systemui.media.taptotransfer.MediaTttChipController;
import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
+import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver;
+import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender;
import com.android.systemui.people.PeopleProvider;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.unfold.SysUIUnfoldComponent;
@@ -134,7 +135,8 @@
});
getNaturalRotationUnfoldProgressProvider().ifPresent(o -> o.init());
// No init method needed, just needs to be gotten so that it's created.
- getMediaTttChipController();
+ getMediaTttChipControllerSender();
+ getMediaTttChipControllerReceiver();
getMediaTttCommandLineHelper();
getUnfoldLatencyTracker().init();
}
@@ -190,7 +192,10 @@
Optional<NaturalRotationUnfoldProgressProvider> getNaturalRotationUnfoldProgressProvider();
/** */
- Optional<MediaTttChipController> getMediaTttChipController();
+ Optional<MediaTttChipControllerSender> getMediaTttChipControllerSender();
+
+ /** */
+ Optional<MediaTttChipControllerReceiver> getMediaTttChipControllerReceiver();
/** */
Optional<MediaTttCommandLineHelper> getMediaTttCommandLineHelper();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 9c25b35..2beed4c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -40,7 +40,6 @@
void extendPulse(int reason);
void setAnimateWakeup(boolean animateWakeup);
- void setAnimateScreenOff(boolean animateScreenOff);
/**
* Reports that a tap event happend on the Sensors Low Power Island.
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index b2fe3bb..e568b82 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -21,30 +21,21 @@
import android.app.AlarmManager;
import android.content.Context;
-import android.content.res.Configuration;
import android.os.Handler;
import android.os.SystemClock;
-import android.provider.Settings;
import android.text.format.Formatter;
import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.unfold.FoldAodAnimationController;
-import com.android.systemui.unfold.FoldAodAnimationController.FoldAodAnimationStatus;
-import com.android.systemui.unfold.SysUIUnfoldComponent;
import com.android.systemui.util.AlarmTimeout;
import com.android.systemui.util.wakelock.WakeLock;
import java.util.Calendar;
-import java.util.Optional;
import javax.inject.Inject;
@@ -52,9 +43,7 @@
* The policy controlling doze.
*/
@DozeScope
-public class DozeUi implements DozeMachine.Part, TunerService.Tunable,
- ConfigurationController.ConfigurationListener, FoldAodAnimationStatus,
- StatusBarStateController.StateListener {
+public class DozeUi implements DozeMachine.Part {
// if enabled, calls dozeTimeTick() whenever the time changes:
private static final boolean BURN_IN_TESTING_ENABLED = false;
private static final long TIME_TICK_DEADLINE_MILLIS = 90 * 1000; // 1.5min
@@ -62,26 +51,15 @@
private final DozeHost mHost;
private final Handler mHandler;
private final WakeLock mWakeLock;
- private final FoldAodAnimationController mFoldAodAnimationController;
private DozeMachine mMachine;
private final AlarmTimeout mTimeTicker;
private final boolean mCanAnimateTransition;
private final DozeParameters mDozeParameters;
private final DozeLog mDozeLog;
private final StatusBarStateController mStatusBarStateController;
- private final TunerService mTunerService;
- private final ConfigurationController mConfigurationController;
-
- private boolean mKeyguardShowing;
private final KeyguardUpdateMonitorCallback mKeyguardVisibilityCallback =
new KeyguardUpdateMonitorCallback() {
@Override
- public void onKeyguardVisibilityChanged(boolean showing) {
- mKeyguardShowing = showing;
- updateAnimateScreenOff();
- }
-
- @Override
public void onTimeChanged() {
if (BURN_IN_TESTING_ENABLED && mStatusBarStateController.isDozing()) {
// update whenever the time changes for manual burn in testing
@@ -91,11 +69,6 @@
mHandler.post(mWakeLock.wrap(() -> {}));
}
}
-
- @Override
- public void onShadeExpandedChanged(boolean expanded) {
- updateAnimateScreenOff();
- }
};
private long mLastTimeTickElapsed = 0;
@@ -104,10 +77,8 @@
public DozeUi(Context context, AlarmManager alarmManager,
WakeLock wakeLock, DozeHost host, @Main Handler handler,
DozeParameters params, KeyguardUpdateMonitor keyguardUpdateMonitor,
- DozeLog dozeLog, TunerService tunerService,
StatusBarStateController statusBarStateController,
- Optional<SysUIUnfoldComponent> sysUiUnfoldComponent,
- ConfigurationController configurationController) {
+ DozeLog dozeLog) {
mContext = context;
mWakeLock = wakeLock;
mHost = host;
@@ -117,31 +88,7 @@
mTimeTicker = new AlarmTimeout(alarmManager, this::onTimeTick, "doze_time_tick", handler);
keyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback);
mDozeLog = dozeLog;
- mTunerService = tunerService;
mStatusBarStateController = statusBarStateController;
- mStatusBarStateController.addCallback(this);
-
- mTunerService.addTunable(this, Settings.Secure.DOZE_ALWAYS_ON);
-
- mConfigurationController = configurationController;
- mConfigurationController.addCallback(this);
-
- mFoldAodAnimationController = sysUiUnfoldComponent
- .map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null);
-
- if (mFoldAodAnimationController != null) {
- mFoldAodAnimationController.addCallback(this);
- }
- }
-
- @Override
- public void destroy() {
- mTunerService.removeTunable(this);
- mConfigurationController.removeCallback(this);
-
- if (mFoldAodAnimationController != null) {
- mFoldAodAnimationController.removeCallback(this);
- }
}
@Override
@@ -149,22 +96,6 @@
mMachine = dozeMachine;
}
- /**
- * Decide if we're taking over the screen-off animation
- * when the device was configured to skip doze after screen off.
- */
- private void updateAnimateScreenOff() {
- if (mCanAnimateTransition) {
- final boolean controlScreenOff =
- mDozeParameters.getAlwaysOn()
- && (mKeyguardShowing || mDozeParameters.shouldControlUnlockedScreenOff())
- && !mHost.isPowerSaveActive();
- mDozeParameters.setControlScreenOffAnimation(controlScreenOff);
- mHost.setAnimateScreenOff(controlScreenOff
- && mDozeParameters.shouldAnimateDozingChange());
- }
- }
-
private void pulseWhileDozing(int reason) {
mHost.pulseWhileDozing(
new DozeHost.PulseCallback() {
@@ -293,34 +224,4 @@
scheduleTimeTick();
}
-
- @VisibleForTesting
- KeyguardUpdateMonitorCallback getKeyguardCallback() {
- return mKeyguardVisibilityCallback;
- }
-
- @Override
- public void onTuningChanged(String key, String newValue) {
- if (key.equals(Settings.Secure.DOZE_ALWAYS_ON)) {
- updateAnimateScreenOff();
- }
- }
-
- @Override
- public void onConfigChanged(Configuration newConfig) {
- updateAnimateScreenOff();
- }
-
- /**
- * Called when StatusBar state changed, could affect unlocked screen off animation state
- */
- @Override
- public void onStatePostChange() {
- updateAnimateScreenOff();
- }
-
- @Override
- public void onFoldToAodAnimationChanged() {
- updateAnimateScreenOff();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
new file mode 100644
index 0000000..572bb44
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams;
+
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+import com.android.systemui.dreams.dagger.DreamOverlayComponent;
+import com.android.systemui.dreams.dagger.DreamOverlayModule;
+import com.android.systemui.util.ViewController;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * View controller for {@link DreamOverlayContainerView}.
+ */
+@DreamOverlayComponent.DreamOverlayScope
+public class DreamOverlayContainerViewController extends ViewController<DreamOverlayContainerView> {
+ // The height of the area at the top of the dream overlay to allow dragging down the
+ // notifications shade.
+ private final int mDreamOverlayNotificationsDragAreaHeight;
+ private final DreamOverlayStatusBarViewController mStatusBarViewController;
+
+ // The dream overlay's content view, which is located below the status bar (in z-order) and is
+ // the space into which widgets are placed.
+ private final ViewGroup mDreamOverlayContentView;
+
+ // A hook into the internal inset calculation where we declare the overlays as the only
+ // touchable regions.
+ private final ViewTreeObserver.OnComputeInternalInsetsListener
+ mOnComputeInternalInsetsListener =
+ new ViewTreeObserver.OnComputeInternalInsetsListener() {
+ @Override
+ public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
+ inoutInfo.setTouchableInsets(
+ ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+ final Region region = new Region();
+ final Rect rect = new Rect();
+ final int childCount = mDreamOverlayContentView.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = mDreamOverlayContentView.getChildAt(i);
+ if (child.getGlobalVisibleRect(rect)) {
+ region.op(rect, Region.Op.UNION);
+ }
+ }
+
+ // Add the notifications drag area to the tap region (otherwise the
+ // notifications shade can't be dragged down).
+ if (mDreamOverlayContentView.getGlobalVisibleRect(rect)) {
+ rect.bottom = rect.top + mDreamOverlayNotificationsDragAreaHeight;
+ region.op(rect, Region.Op.UNION);
+ }
+
+ inoutInfo.touchableRegion.set(region);
+ }
+ };
+
+ @Inject
+ public DreamOverlayContainerViewController(
+ DreamOverlayContainerView containerView,
+ @Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView,
+ DreamOverlayStatusBarViewController statusBarViewController) {
+ super(containerView);
+ mDreamOverlayContentView = contentView;
+ mStatusBarViewController = statusBarViewController;
+ mDreamOverlayNotificationsDragAreaHeight =
+ mView.getResources().getDimensionPixelSize(
+ R.dimen.dream_overlay_notifications_drag_area_height);
+ }
+
+ @Override
+ protected void onInit() {
+ mStatusBarViewController.init();
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mView.getViewTreeObserver()
+ .addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
+ }
+
+ @Override
+ protected void onViewDetached() {
+ mView.getViewTreeObserver()
+ .removeOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
+ }
+
+ void addOverlay(View overlayView, ConstraintLayout.LayoutParams layoutParams) {
+ mDreamOverlayContentView.addView(overlayView, layoutParams);
+ }
+
+ View getContainerView() {
+ return mView;
+ }
+
+ void removeAllOverlays() {
+ mDreamOverlayContentView.removeAllViews();
+ }
+
+ @VisibleForTesting
+ int getDreamOverlayNotificationsDragAreaHeight() {
+ return mDreamOverlayNotificationsDragAreaHeight;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 7c2bb4b..a53120f 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -17,13 +17,8 @@
package com.android.systemui.dreams;
import android.content.Context;
-import android.graphics.Rect;
-import android.graphics.Region;
import android.graphics.drawable.ColorDrawable;
import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -54,12 +49,12 @@
private final Executor mExecutor;
// The state controller informs the service of updates to the complications present.
private final DreamOverlayStateController mStateController;
- // The component used to resolve dream overlay dependencies.
- private final DreamOverlayComponent mDreamOverlayComponent;
+ // A controller for the dream overlay container view (which contains both the status bar and the
+ // content area).
+ private final DreamOverlayContainerViewController mDreamOverlayContainerViewController;
- // The dream overlay's content view, which is located below the status bar (in z-order) and is
- // the space into which widgets are placed.
- private ViewGroup mDreamOverlayContentView;
+ // A reference to the {@link Window} used to hold the dream overlay.
+ private Window mWindow;
private final DreamOverlayStateController.Callback mOverlayStateCallback =
new DreamOverlayStateController.Callback() {
@@ -69,47 +64,6 @@
}
};
- // The service listens to view changes in order to declare that input occurring in areas outside
- // the overlay should be passed through to the dream underneath.
- private final View.OnAttachStateChangeListener mRootViewAttachListener =
- new View.OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(View v) {
- v.getViewTreeObserver()
- .addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
- v.getViewTreeObserver()
- .removeOnComputeInternalInsetsListener(
- mOnComputeInternalInsetsListener);
- }
- };
-
- // A hook into the internal inset calculation where we declare the complications as the only
- // touchable regions.
- private final ViewTreeObserver.OnComputeInternalInsetsListener
- mOnComputeInternalInsetsListener =
- new ViewTreeObserver.OnComputeInternalInsetsListener() {
- @Override
- public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
- if (mDreamOverlayContentView != null) {
- inoutInfo.setTouchableInsets(
- ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- final Region region = new Region();
- for (int i = 0; i < mDreamOverlayContentView.getChildCount(); i++) {
- View child = mDreamOverlayContentView.getChildAt(i);
- final Rect rect = new Rect();
- child.getGlobalVisibleRect(rect);
- region.op(rect, Region.Op.UNION);
- }
-
- inoutInfo.touchableRegion.set(region);
- }
- }
- };
-
@Inject
public DreamOverlayService(
Context context,
@@ -119,23 +73,29 @@
mContext = context;
mExecutor = executor;
mStateController = overlayStateController;
- mDreamOverlayComponent = dreamOverlayComponentFactory.create();
+ mDreamOverlayContainerViewController =
+ dreamOverlayComponentFactory.create().getDreamOverlayContainerViewController();
mStateController.addCallback(mOverlayStateCallback);
}
@Override
+ public void onDestroy() {
+ final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
+ windowManager.removeView(mWindow.getDecorView());
+ mStateController.removeCallback(mOverlayStateCallback);
+ super.onDestroy();
+ }
+
+ @Override
public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) {
mExecutor.execute(() -> addOverlayWindowLocked(layoutParams));
}
private void reloadComplicationsLocked() {
- if (mDreamOverlayContentView == null) {
- return;
- }
- mDreamOverlayContentView.removeAllViews();
- for (ComplicationProvider complicationProvider : mStateController.getComplications()) {
- addComplication(complicationProvider);
+ mDreamOverlayContainerViewController.removeAllOverlays();
+ for (ComplicationProvider overlayProvider : mStateController.getComplications()) {
+ addComplication(overlayProvider);
}
}
@@ -147,32 +107,28 @@
* into the dream window.
*/
private void addOverlayWindowLocked(WindowManager.LayoutParams layoutParams) {
- final PhoneWindow window = new PhoneWindow(mContext);
- window.setAttributes(layoutParams);
- window.setWindowManager(null, layoutParams.token, "DreamOverlay", true);
+ mWindow = new PhoneWindow(mContext);
+ mWindow.setAttributes(layoutParams);
+ mWindow.setWindowManager(null, layoutParams.token, "DreamOverlay", true);
- window.setBackgroundDrawable(new ColorDrawable(0));
+ mWindow.setBackgroundDrawable(new ColorDrawable(0));
- window.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
- window.requestFeature(Window.FEATURE_NO_TITLE);
+ mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
+ mWindow.requestFeature(Window.FEATURE_NO_TITLE);
// Hide all insets when the dream is showing
- window.getDecorView().getWindowInsetsController().hide(WindowInsets.Type.systemBars());
- window.setDecorFitsSystemWindows(false);
+ mWindow.getDecorView().getWindowInsetsController().hide(WindowInsets.Type.systemBars());
+ mWindow.setDecorFitsSystemWindows(false);
if (DEBUG) {
Log.d(TAG, "adding overlay window to dream");
}
- window.setContentView(mDreamOverlayComponent.getDreamOverlayContainerView());
-
- mDreamOverlayContentView = mDreamOverlayComponent.getDreamOverlayContentView();
- mDreamOverlayContentView.addOnAttachStateChangeListener(mRootViewAttachListener);
-
- mDreamOverlayComponent.getDreamOverlayStatusBarViewController().init();
+ mDreamOverlayContainerViewController.init();
+ mWindow.setContentView(mDreamOverlayContainerViewController.getContainerView());
final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
- windowManager.addView(window.getDecorView(), window.getAttributes());
+ windowManager.addView(mWindow.getDecorView(), mWindow.getAttributes());
mExecutor.execute(this::reloadComplicationsLocked);
}
@@ -181,25 +137,12 @@
provider.onCreateComplication(mContext,
(view, layoutParams) -> {
// Always move UI related work to the main thread.
- mExecutor.execute(() -> {
- if (mDreamOverlayContentView == null) {
- return;
- }
-
- mDreamOverlayContentView.addView(view, layoutParams);
- });
+ mExecutor.execute(() -> mDreamOverlayContainerViewController
+ .addOverlay(view, layoutParams));
},
() -> {
// The Callback is set on the main thread.
- mExecutor.execute(() -> {
- requestExit();
- });
+ mExecutor.execute(this::requestExit);
});
}
-
- @Override
- public void onDestroy() {
- mStateController.removeCallback(mOverlayStateCallback);
- super.onDestroy();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
index a3a446a..c90332b 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
@@ -18,10 +18,7 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import android.view.ViewGroup;
-
-import com.android.systemui.dreams.DreamOverlayContainerView;
-import com.android.systemui.dreams.DreamOverlayStatusBarViewController;
+import com.android.systemui.dreams.DreamOverlayContainerViewController;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
@@ -48,15 +45,7 @@
@Scope
@interface DreamOverlayScope {}
- /** Builds a {@link DreamOverlayContainerView} */
+ /** Builds a {@link DreamOverlayContainerViewController}. */
@DreamOverlayScope
- DreamOverlayContainerView getDreamOverlayContainerView();
-
- /** Builds a content view for dream overlays */
- @DreamOverlayScope
- ViewGroup getDreamOverlayContentView();
-
- /** Builds a {@link DreamOverlayStatusBarViewController}. */
- @DreamOverlayScope
- DreamOverlayStatusBarViewController getDreamOverlayStatusBarViewController();
+ DreamOverlayContainerViewController getDreamOverlayContainerViewController();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
index d0a8fad..5b588a9 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
@@ -44,6 +44,7 @@
private static final String DREAM_OVERLAY_BATTERY_VIEW = "dream_overlay_battery_view";
public static final String DREAM_OVERLAY_BATTERY_CONTROLLER =
"dream_overlay_battery_controller";
+ public static final String DREAM_OVERLAY_CONTENT_VIEW = "dream_overlay_content_view";
/** */
@Provides
@@ -58,6 +59,7 @@
/** */
@Provides
@DreamOverlayComponent.DreamOverlayScope
+ @Named(DREAM_OVERLAY_CONTENT_VIEW)
public static ViewGroup providesDreamOverlayContentView(DreamOverlayContainerView view) {
return Preconditions.checkNotNull(view.findViewById(R.id.dream_overlay_content),
"R.id.dream_overlay_content must not be null");
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 4e852a8..726f865 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -43,15 +43,18 @@
public static final BooleanFlag NEW_NOTIFICATION_PIPELINE_RENDERING =
new BooleanFlag(101, false);
- public static final BooleanFlag NOTIFICATION_UPDATES =
- new BooleanFlag(102, true);
-
public static final BooleanFlag NOTIFICATION_PIPELINE_DEVELOPER_LOGGING =
new BooleanFlag(103, false);
public static final ResourceBooleanFlag NOTIFICATION_SHADE_DRAG =
new ResourceBooleanFlag(104, R.bool.config_enableNotificationShadeDrag);
+ public static final BooleanFlag NSSL_DEBUG_LINES =
+ new BooleanFlag(105, false);
+
+ public static final BooleanFlag NSSL_DEBUG_REMOVE_ANIMATION =
+ new BooleanFlag(106, false);
+
/***************************************/
// 200 - keyguard/lockscreen
public static final BooleanFlag KEYGUARD_LAYOUT =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 22a69d4..fb31d88 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -583,6 +583,18 @@
checkPermission();
mKeyguardViewMediator.onShortPowerPressedGoHome();
}
+
+ @Override
+ public void dismissKeyguardToLaunch(Intent intentToLaunch) {
+ checkPermission();
+ mKeyguardViewMediator.dismissKeyguardToLaunch(intentToLaunch);
+ }
+
+ @Override
+ public void onSystemKeyPressed(int keycode) {
+ checkPermission();
+ mKeyguardViewMediator.onSystemKeyPressed(keycode);
+ }
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0512d48..8f4a28c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2750,6 +2750,14 @@
// do nothing
}
+ public void dismissKeyguardToLaunch(Intent intentToLaunch) {
+ // do nothing
+ }
+
+ public void onSystemKeyPressed(int keycode) {
+ // do nothing
+ }
+
public ViewMediatorCallback getViewMediatorCallback() {
return mViewMediatorCallback;
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index e921ad29c..ce3b443 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -18,6 +18,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.MediaControlPanel.SMARTSPACE_CARD_DISMISS_EVENT
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.qs.PageIndicator
@@ -56,7 +57,8 @@
configurationController: ConfigurationController,
falsingCollector: FalsingCollector,
falsingManager: FalsingManager,
- dumpManager: DumpManager
+ dumpManager: DumpManager,
+ private val mediaFlags: MediaFlags
) : Dumpable {
/**
* The current width of the carousel
@@ -382,7 +384,7 @@
private fun reorderAllPlayers(previousVisiblePlayerKey: MediaPlayerData.MediaSortKey?) {
mediaContent.removeAllViews()
for (mediaPlayer in MediaPlayerData.players()) {
- mediaPlayer.playerViewHolder?.let {
+ mediaPlayer.mediaViewHolder?.let {
mediaContent.addView(it.player)
} ?: mediaPlayer.recommendationViewHolder?.let {
mediaContent.addView(it.recommendations)
@@ -416,12 +418,19 @@
.elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
if (existingPlayer == null) {
var newPlayer = mediaControlPanelFactory.get()
- newPlayer.attachPlayer(
- PlayerViewHolder.create(LayoutInflater.from(context), mediaContent))
+ if (mediaFlags.areMediaSessionActionsEnabled()) {
+ newPlayer.attachPlayer(
+ PlayerSessionViewHolder.create(LayoutInflater.from(context), mediaContent),
+ MediaViewController.TYPE.PLAYER_SESSION)
+ } else {
+ newPlayer.attachPlayer(
+ PlayerViewHolder.create(LayoutInflater.from(context), mediaContent),
+ MediaViewController.TYPE.PLAYER)
+ }
newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
- newPlayer.playerViewHolder?.player?.setLayoutParams(lp)
+ newPlayer.mediaViewHolder?.player?.setLayoutParams(lp)
newPlayer.bindPlayer(dataCopy, key)
newPlayer.setListening(currentlyExpanded)
MediaPlayerData.addMediaPlayer(key, dataCopy, newPlayer, systemClock)
@@ -493,7 +502,7 @@
val removed = MediaPlayerData.removeMediaPlayer(key)
removed?.apply {
mediaCarouselScrollHandler.onPrePlayerRemoved(removed)
- mediaContent.removeView(removed.playerViewHolder?.player)
+ mediaContent.removeView(removed.mediaViewHolder?.player)
mediaContent.removeView(removed.recommendationViewHolder?.recommendations)
removed.onDestroy()
mediaCarouselScrollHandler.onPlayersChanged()
@@ -836,7 +845,7 @@
MediaPlayerData.players().forEachIndexed {
index, it ->
if (it.mIsImpressed) {
- logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
+ logSmartspaceCardReported(SMARTSPACE_CARD_DISMISS_EVENT,
it.mInstanceId,
it.mUid,
it.recommendationViewHolder != null,
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
index cbcec95..5dc4bcf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
@@ -528,7 +528,7 @@
* where it was and update our scroll position.
*/
fun onPrePlayerRemoved(removed: MediaControlPanel) {
- val removedIndex = mediaContent.indexOfChild(removed.playerViewHolder?.player)
+ val removedIndex = mediaContent.indexOfChild(removed.mediaViewHolder?.player)
// If the removed index is less than the visibleMediaIndex, then we need to decrement it.
// RTL has no effect on this, because indices are always relative (start-to-end).
// Update the index 'manually' since we won't always get a call to onMediaScrollingChanged
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 63555bb..3c23722 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -57,12 +57,10 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
-import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.util.animation.TransitionLayout;
import com.android.systemui.util.time.SystemClock;
import java.net.URISyntaxException;
-import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
@@ -87,6 +85,10 @@
private static final String KEY_SMARTSPACE_ARTIST_NAME = "artist_name";
private static final String KEY_SMARTSPACE_OPEN_IN_FOREGROUND = "KEY_OPEN_IN_FOREGROUND";
+ // Event types logged by smartspace
+ private static final int SMARTSPACE_CARD_CLICK_EVENT = 760;
+ protected static final int SMARTSPACE_CARD_DISMISS_EVENT = 761;
+
private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS);
// Button IDs for QS controls
@@ -104,13 +106,12 @@
private final ActivityStarter mActivityStarter;
private Context mContext;
- private PlayerViewHolder mPlayerViewHolder;
+ private MediaViewHolder mMediaViewHolder;
private RecommendationViewHolder mRecommendationViewHolder;
private String mKey;
private MediaViewController mMediaViewController;
private MediaSession.Token mToken;
private MediaController mController;
- private KeyguardDismissUtil mKeyguardDismissUtil;
private Lazy<MediaDataManager> mMediaDataManagerLazy;
private int mBackgroundColor;
private int mDevicePadding;
@@ -139,8 +140,8 @@
public MediaControlPanel(Context context, @Background Executor backgroundExecutor,
ActivityStarter activityStarter, MediaViewController mediaViewController,
SeekBarViewModel seekBarViewModel, Lazy<MediaDataManager> lazyMediaDataManager,
- KeyguardDismissUtil keyguardDismissUtil, MediaOutputDialogFactory
- mediaOutputDialogFactory, MediaCarouselController mediaCarouselController,
+ MediaOutputDialogFactory mediaOutputDialogFactory,
+ MediaCarouselController mediaCarouselController,
FalsingManager falsingManager, MediaFlags mediaFlags, SystemClock systemClock) {
mContext = context;
mBackgroundExecutor = backgroundExecutor;
@@ -148,7 +149,6 @@
mSeekBarViewModel = seekBarViewModel;
mMediaViewController = mediaViewController;
mMediaDataManagerLazy = lazyMediaDataManager;
- mKeyguardDismissUtil = keyguardDismissUtil;
mMediaOutputDialogFactory = mediaOutputDialogFactory;
mMediaCarouselController = mediaCarouselController;
mFalsingManager = falsingManager;
@@ -157,8 +157,7 @@
loadDimens();
mSeekBarViewModel.setLogSmartspaceClick(() -> {
- logSmartspaceCardReported(
- 760, // SMARTSPACE_CARD_CLICK
+ logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
/* isRecommendationCard */ false);
return Unit.INSTANCE;
});
@@ -179,13 +178,13 @@
}
/**
- * Get the player view holder used to display media controls.
+ * Get the view holder used to display media controls.
*
- * @return the player view holder
+ * @return the media view holder
*/
@Nullable
- public PlayerViewHolder getPlayerViewHolder() {
- return mPlayerViewHolder;
+ public MediaViewHolder getMediaViewHolder() {
+ return mMediaViewHolder;
}
/**
@@ -229,16 +228,17 @@
}
/** Attaches the player to the player view holder. */
- public void attachPlayer(PlayerViewHolder vh) {
- mPlayerViewHolder = vh;
+ public void attachPlayer(MediaViewHolder vh, MediaViewController.TYPE playerType) {
+ mMediaViewHolder = vh;
TransitionLayout player = vh.getPlayer();
- mSeekBarObserver = new SeekBarObserver(vh);
+ boolean useSessionLayout = playerType == MediaViewController.TYPE.PLAYER_SESSION;
+ mSeekBarObserver = new SeekBarObserver(vh, useSessionLayout);
mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver);
mSeekBarViewModel.attachTouchHandlers(vh.getSeekBar());
- mMediaViewController.attach(player, MediaViewController.TYPE.PLAYER);
+ mMediaViewController.attach(player, playerType);
- mPlayerViewHolder.getPlayer().setOnLongClickListener(v -> {
+ vh.getPlayer().setOnLongClickListener(v -> {
if (!mMediaViewController.isGutsVisible()) {
openGuts();
return true;
@@ -247,12 +247,12 @@
return true;
}
});
- mPlayerViewHolder.getCancel().setOnClickListener(v -> {
+ vh.getCancel().setOnClickListener(v -> {
if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
closeGuts();
}
});
- mPlayerViewHolder.getSettings().setOnClickListener(v -> {
+ vh.getSettings().setOnClickListener(v -> {
if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
}
@@ -289,9 +289,19 @@
/** Bind this player view based on the data given. */
public void bindPlayer(@NonNull MediaData data, String key) {
- if (mPlayerViewHolder == null) {
+ if (mMediaViewHolder == null) {
return;
}
+ bindPlayerCommon(data, key);
+ if (mMediaViewHolder instanceof PlayerViewHolder) {
+ bindNotificationPlayer(data, key);
+ } else if (mMediaViewHolder instanceof PlayerSessionViewHolder) {
+ bindSessionPlayer(data, key);
+ }
+ }
+
+ /** Bind elements common to both layouts */
+ private void bindPlayerCommon(@NonNull MediaData data, String key) {
mKey = key;
MediaSession.Token token = data.getToken();
PackageManager packageManager = mContext.getPackageManager();
@@ -316,99 +326,63 @@
mController = null;
}
- ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
- ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
-
// Click action
PendingIntent clickIntent = data.getClickIntent();
if (clickIntent != null) {
- mPlayerViewHolder.getPlayer().setOnClickListener(v -> {
+ mMediaViewHolder.getPlayer().setOnClickListener(v -> {
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
if (mMediaViewController.isGutsVisible()) return;
- logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
+ logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
/* isRecommendationCard */ false);
mActivityStarter.postStartActivityDismissingKeyguard(clickIntent,
- buildLaunchAnimatorController(mPlayerViewHolder.getPlayer()));
+ buildLaunchAnimatorController(mMediaViewHolder.getPlayer()));
});
}
// Accessibility label
- mPlayerViewHolder.getPlayer().setContentDescription(
+ mMediaViewHolder.getPlayer().setContentDescription(
mContext.getString(
R.string.controls_media_playing_item_description,
data.getSong(), data.getArtist(), data.getApp()));
- ImageView albumView = mPlayerViewHolder.getAlbumView();
- boolean hasArtwork = data.getArtwork() != null;
- if (hasArtwork) {
- Drawable artwork = scaleDrawable(data.getArtwork());
- albumView.setPadding(0, 0, 0, 0);
- albumView.setImageDrawable(artwork);
- } else {
- Drawable deviceIcon;
- if (data.getDevice() != null && data.getDevice().getIcon() != null) {
- deviceIcon = data.getDevice().getIcon().getConstantState().newDrawable().mutate();
- } else {
- deviceIcon = getContext().getDrawable(R.drawable.ic_headphone);
- }
- deviceIcon.setTintList(ColorStateList.valueOf(mBackgroundColor));
- albumView.setPadding(mDevicePadding, mDevicePadding, mDevicePadding, mDevicePadding);
- albumView.setImageDrawable(deviceIcon);
- }
-
- // App icon
- ImageView appIconView = mPlayerViewHolder.getAppIcon();
- appIconView.clearColorFilter();
- if (data.getAppIcon() != null && !data.getResumption()) {
- appIconView.setImageIcon(data.getAppIcon());
- int color = mContext.getColor(android.R.color.system_accent2_900);
- appIconView.setColorFilter(color);
- } else {
- appIconView.setColorFilter(getGrayscaleFilter());
- try {
- Drawable icon = mContext.getPackageManager().getApplicationIcon(
- data.getPackageName());
- appIconView.setImageDrawable(icon);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
- appIconView.setImageResource(R.drawable.ic_music_note);
- }
- }
-
// Song name
- TextView titleText = mPlayerViewHolder.getTitleText();
+ TextView titleText = mMediaViewHolder.getTitleText();
titleText.setText(data.getSong());
// Artist name
- TextView artistText = mPlayerViewHolder.getArtistText();
+ TextView artistText = mMediaViewHolder.getArtistText();
artistText.setText(data.getArtist());
- // Transfer chip
- ViewGroup seamlessView = mPlayerViewHolder.getSeamless();
+ // Seek Bar
+ final MediaController controller = getController();
+ mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller));
+
+ // Guts label
+ boolean isDismissible = data.isClearable();
+ mMediaViewHolder.getLongPressText().setText(isDismissible
+ ? R.string.controls_media_close_session
+ : R.string.controls_media_active_session);
+
+ // Output switcher chip
+ ViewGroup seamlessView = mMediaViewHolder.getSeamless();
seamlessView.setVisibility(View.VISIBLE);
- setVisibleAndAlpha(collapsedSet, R.id.media_seamless, true /*visible */);
- setVisibleAndAlpha(expandedSet, R.id.media_seamless, true /*visible */);
seamlessView.setOnClickListener(
v -> {
if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
mMediaOutputDialogFactory.create(data.getPackageName(), true,
- mPlayerViewHolder.getSeamlessButton());
+ mMediaViewHolder.getSeamlessButton());
}
});
-
- ImageView iconView = mPlayerViewHolder.getSeamlessIcon();
- TextView deviceName = mPlayerViewHolder.getSeamlessText();
-
+ ImageView iconView = mMediaViewHolder.getSeamlessIcon();
+ TextView deviceName = mMediaViewHolder.getSeamlessText();
final MediaDeviceData device = data.getDevice();
- final int seamlessId = mPlayerViewHolder.getSeamless().getId();
// Disable clicking on output switcher for invalid devices and resumption controls
final boolean seamlessDisabled = (device != null && !device.getEnabled())
|| data.getResumption();
final float seamlessAlpha = seamlessDisabled ? DISABLED_ALPHA : 1.0f;
- expandedSet.setAlpha(seamlessId, seamlessAlpha);
- collapsedSet.setAlpha(seamlessId, seamlessAlpha);
- mPlayerViewHolder.getSeamless().setEnabled(!seamlessDisabled);
+ mMediaViewHolder.getSeamlessButton().setAlpha(seamlessAlpha);
+ seamlessView.setEnabled(!seamlessDisabled);
String deviceString = null;
if (device != null && device.getEnabled()) {
Drawable icon = device.getIcon();
@@ -429,32 +403,88 @@
deviceName.setText(deviceString);
seamlessView.setContentDescription(deviceString);
+ // Dismiss
+ mMediaViewHolder.getDismissLabel().setAlpha(isDismissible ? 1 : DISABLED_ALPHA);
+ mMediaViewHolder.getDismiss().setEnabled(isDismissible);
+ mMediaViewHolder.getDismiss().setOnClickListener(v -> {
+ if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
+
+ logSmartspaceCardReported(SMARTSPACE_CARD_DISMISS_EVENT,
+ /* isRecommendationCard */ false);
+
+ if (mKey != null) {
+ closeGuts();
+ if (!mMediaDataManagerLazy.get().dismissMediaData(mKey,
+ MediaViewController.GUTS_ANIMATION_DURATION + 100)) {
+ Log.w(TAG, "Manager failed to dismiss media " + mKey);
+ // Remove directly from carousel so user isn't stuck with defunct controls
+ mMediaCarouselController.removePlayer(key, false, false);
+ }
+ } else {
+ Log.w(TAG, "Dismiss media with null notification. Token uid="
+ + data.getToken().getUid());
+ }
+ });
+
+ // TODO: We don't need to refresh this state constantly, only if the state actually changed
+ // to something which might impact the measurement
+ mMediaViewController.refreshState();
+ }
+
+ /** Bind elements specific to PlayerViewHolder */
+ private void bindNotificationPlayer(@NonNull MediaData data, String key) {
+ ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
+ ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
+
+ // Album art
+ PlayerViewHolder playerHolder = (PlayerViewHolder) mMediaViewHolder;
+ ImageView albumView = playerHolder.getAlbumView();
+ boolean hasArtwork = data.getArtwork() != null;
+ if (hasArtwork) {
+ Drawable artwork = scaleDrawable(data.getArtwork());
+ albumView.setPadding(0, 0, 0, 0);
+ albumView.setImageDrawable(artwork);
+ } else {
+ Drawable deviceIcon;
+ if (data.getDevice() != null && data.getDevice().getIcon() != null) {
+ deviceIcon = data.getDevice().getIcon().getConstantState().newDrawable().mutate();
+ } else {
+ deviceIcon = getContext().getDrawable(R.drawable.ic_headphone);
+ }
+ deviceIcon.setTintList(ColorStateList.valueOf(mBackgroundColor));
+ albumView.setPadding(mDevicePadding, mDevicePadding, mDevicePadding, mDevicePadding);
+ albumView.setImageDrawable(deviceIcon);
+ }
+
+ // App icon - use notification icon
+ ImageView appIconView = mMediaViewHolder.getAppIcon();
+ appIconView.clearColorFilter();
+ if (data.getAppIcon() != null && !data.getResumption()) {
+ appIconView.setImageIcon(data.getAppIcon());
+ int color = mContext.getColor(android.R.color.system_accent2_900);
+ appIconView.setColorFilter(color);
+ } else {
+ // Resume players use launcher icon
+ appIconView.setColorFilter(getGrayscaleFilter());
+ try {
+ Drawable icon = mContext.getPackageManager().getApplicationIcon(
+ data.getPackageName());
+ appIconView.setImageDrawable(icon);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
+ appIconView.setImageResource(R.drawable.ic_music_note);
+ }
+ }
+
// Media action buttons
List<MediaAction> actionIcons = data.getActions();
List<Integer> actionsWhenCollapsed = data.getActionsToShowInCompact();
- if (mMediaFlags.areMediaSessionActionsEnabled() && data.getSemanticActions() != null) {
- // Use PlaybackState actions instead
- MediaButton semanticActions = data.getSemanticActions();
-
- actionIcons = new ArrayList<MediaAction>();
- actionIcons.add(semanticActions.getStartCustom());
- actionIcons.add(semanticActions.getPrevOrCustom());
- actionIcons.add(semanticActions.getPlayOrPause());
- actionIcons.add(semanticActions.getNextOrCustom());
- actionIcons.add(semanticActions.getEndCustom());
-
- actionsWhenCollapsed = new ArrayList<Integer>();
- actionsWhenCollapsed.add(1);
- actionsWhenCollapsed.add(2);
- actionsWhenCollapsed.add(3);
- }
-
int i = 0;
for (; i < actionIcons.size() && i < ACTION_IDS.length; i++) {
int actionId = ACTION_IDS[i];
boolean visibleInCompat = actionsWhenCollapsed.contains(i);
- final ImageButton button = mPlayerViewHolder.getAction(actionId);
+ final ImageButton button = mMediaViewHolder.getAction(actionId);
MediaAction mediaAction = actionIcons.get(i);
if (mediaAction != null) {
button.setImageIcon(mediaAction.getIcon());
@@ -467,7 +497,7 @@
button.setEnabled(true);
button.setOnClickListener(v -> {
if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
- logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
+ logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
/* isRecommendationCard */ false);
action.run();
}
@@ -495,43 +525,71 @@
if (actionIcons.size() == 0) {
expandedSet.setVisibility(ACTION_IDS[0], ConstraintSet.INVISIBLE);
}
+ }
- // Seek Bar
- final MediaController controller = getController();
- mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller));
-
- // Guts label
- boolean isDismissible = data.isClearable();
- mPlayerViewHolder.getLongPressText().setText(isDismissible
- ? R.string.controls_media_close_session
- : R.string.controls_media_active_session);
-
- // Dismiss
- mPlayerViewHolder.getDismissLabel().setAlpha(isDismissible ? 1 : DISABLED_ALPHA);
- mPlayerViewHolder.getDismiss().setEnabled(isDismissible);
- mPlayerViewHolder.getDismiss().setOnClickListener(v -> {
- if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
-
- logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
- /* isRecommendationCard */ false);
-
- if (mKey != null) {
- closeGuts();
- if (!mMediaDataManagerLazy.get().dismissMediaData(mKey,
- MediaViewController.GUTS_ANIMATION_DURATION + 100)) {
- Log.w(TAG, "Manager failed to dismiss media " + mKey);
- // Remove directly from carousel to let user recover - TODO(b/190799184)
- mMediaCarouselController.removePlayer(key, false, false);
- }
+ /** Bind elements specific to PlayerSessionViewHolder */
+ private void bindSessionPlayer(@NonNull MediaData data, String key) {
+ // App icon - use launcher icon
+ ImageView appIconView = mMediaViewHolder.getAppIcon();
+ appIconView.clearColorFilter();
+ try {
+ Drawable icon = mContext.getPackageManager().getApplicationIcon(
+ data.getPackageName());
+ appIconView.setImageDrawable(icon);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
+ // Fall back to notification icon
+ if (data.getAppIcon() != null) {
+ appIconView.setImageIcon(data.getAppIcon());
} else {
- Log.w(TAG, "Dismiss media with null notification. Token uid="
- + data.getToken().getUid());
+ appIconView.setImageResource(R.drawable.ic_music_note);
}
- });
+ int color = mContext.getColor(android.R.color.system_accent2_900);
+ appIconView.setColorFilter(color);
+ }
- // TODO: We don't need to refresh this state constantly, only if the state actually changed
- // to something which might impact the measurement
- mMediaViewController.refreshState();
+ // Media action buttons
+ MediaButton semanticActions = data.getSemanticActions();
+ if (semanticActions != null) {
+ PlayerSessionViewHolder sessionHolder = (PlayerSessionViewHolder) mMediaViewHolder;
+ setSemanticButton(sessionHolder.getActionPlayPause(),
+ semanticActions.getPlayOrPause());
+ setSemanticButton(sessionHolder.getActionNext(),
+ semanticActions.getNextOrCustom());
+ setSemanticButton(sessionHolder.getActionPrev(),
+ semanticActions.getPrevOrCustom());
+ setSemanticButton(sessionHolder.getActionStart(),
+ semanticActions.getStartCustom());
+ setSemanticButton(sessionHolder.getActionEnd(),
+ semanticActions.getEndCustom());
+ } else {
+ Log.w(TAG, "Using semantic player, but did not get buttons");
+ }
+ }
+
+ private void setSemanticButton(final ImageButton button, MediaAction mediaAction) {
+ if (mediaAction != null) {
+ button.setImageIcon(mediaAction.getIcon());
+ button.setContentDescription(mediaAction.getContentDescription());
+
+ Runnable action = mediaAction.getAction();
+ if (action == null) {
+ button.setEnabled(false);
+ } else {
+ button.setEnabled(true);
+ button.setOnClickListener(v -> {
+ if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
+ /* isRecommendationCard */ false);
+ action.run();
+ }
+ });
+ }
+ } else {
+ button.setImageIcon(null);
+ button.setContentDescription(null);
+ button.setEnabled(false);
+ }
}
@Nullable
@@ -696,7 +754,7 @@
mRecommendationViewHolder.getDismiss().setOnClickListener(v -> {
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
- logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
+ logSmartspaceCardReported(SMARTSPACE_CARD_DISMISS_EVENT,
/* isRecommendationCard */ true);
closeGuts();
mMediaDataManagerLazy.get().dismissSmartspaceRecommendation(
@@ -729,8 +787,8 @@
* @param immediate {@code true} if it should be closed without animation
*/
public void closeGuts(boolean immediate) {
- if (mPlayerViewHolder != null) {
- mPlayerViewHolder.marquee(false, mMediaViewController.GUTS_ANIMATION_DURATION);
+ if (mMediaViewHolder != null) {
+ mMediaViewHolder.marquee(false, mMediaViewController.GUTS_ANIMATION_DURATION);
} else if (mRecommendationViewHolder != null) {
mRecommendationViewHolder.marquee(false, mMediaViewController.GUTS_ANIMATION_DURATION);
}
@@ -747,9 +805,9 @@
boolean wasTruncated = false;
Layout l = null;
- if (mPlayerViewHolder != null) {
- mPlayerViewHolder.marquee(true, mMediaViewController.GUTS_ANIMATION_DURATION);
- l = mPlayerViewHolder.getSettingsText().getLayout();
+ if (mMediaViewHolder != null) {
+ mMediaViewHolder.marquee(true, mMediaViewController.GUTS_ANIMATION_DURATION);
+ l = mMediaViewHolder.getSettingsText().getLayout();
} else if (mRecommendationViewHolder != null) {
mRecommendationViewHolder.marquee(true, mMediaViewController.GUTS_ANIMATION_DURATION);
l = mRecommendationViewHolder.getSettingsText().getLayout();
@@ -853,7 +911,7 @@
view.setOnClickListener(v -> {
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
- logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
+ logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
/* isRecommendationCard */ true,
interactedSubcardRank,
getSmartspaceSubCardCardinality());
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index 3681a2a..791a312 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -37,9 +37,12 @@
private val mediaHostStatesManager: MediaHostStatesManager
) {
- /** Indicating the media view controller is for a player or recommendation. */
+ /**
+ * Indicating that the media view controller is for a notification-based player,
+ * session-based player, or recommendation
+ */
enum class TYPE {
- PLAYER, RECOMMENDATION
+ PLAYER, PLAYER_SESSION, RECOMMENDATION
}
companion object {
@@ -257,31 +260,29 @@
* [TransitionViewState].
*/
private fun setGutsViewState(viewState: TransitionViewState) {
- if (type == TYPE.PLAYER) {
- PlayerViewHolder.controlsIds.forEach { id ->
- viewState.widgetStates.get(id)?.let { state ->
- // Make sure to use the unmodified state if guts are not visible.
- state.alpha = if (isGutsVisible) 0f else state.alpha
- state.gone = if (isGutsVisible) true else state.gone
- }
- }
- PlayerViewHolder.gutsIds.forEach { id ->
- viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f
- viewState.widgetStates.get(id)?.gone = !isGutsVisible
- }
- } else {
- RecommendationViewHolder.controlsIds.forEach { id ->
- viewState.widgetStates.get(id)?.let { state ->
- // Make sure to use the unmodified state if guts are not visible.
- state.alpha = if (isGutsVisible) 0f else state.alpha
- state.gone = if (isGutsVisible) true else state.gone
- }
- }
- RecommendationViewHolder.gutsIds.forEach { id ->
- viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f
- viewState.widgetStates.get(id)?.gone = !isGutsVisible
+ val controlsIds = when (type) {
+ TYPE.PLAYER -> PlayerViewHolder.controlsIds
+ TYPE.PLAYER_SESSION -> PlayerSessionViewHolder.controlsIds
+ TYPE.RECOMMENDATION -> RecommendationViewHolder.controlsIds
+ }
+ val gutsIds = when (type) {
+ TYPE.PLAYER -> PlayerViewHolder.gutsIds
+ TYPE.PLAYER_SESSION -> PlayerSessionViewHolder.gutsIds
+ TYPE.RECOMMENDATION -> RecommendationViewHolder.gutsIds
+ }
+
+ controlsIds.forEach { id ->
+ viewState.widgetStates.get(id)?.let { state ->
+ // Make sure to use the unmodified state if guts are not visible.
+ state.alpha = if (isGutsVisible) 0f else state.alpha
+ state.gone = if (isGutsVisible) true else state.gone
}
}
+ gutsIds.forEach { id ->
+ viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f
+ viewState.widgetStates.get(id)?.gone = !isGutsVisible
+ }
+
if (shouldHideGutsSettings) {
viewState.widgetStates.get(R.id.settings)?.gone = true
}
@@ -470,12 +471,19 @@
private fun updateMediaViewControllerType(type: TYPE) {
this.type = type
- if (type == TYPE.PLAYER) {
- collapsedLayout.load(context, R.xml.media_collapsed)
- expandedLayout.load(context, R.xml.media_expanded)
- } else {
- collapsedLayout.load(context, R.xml.media_recommendation_collapsed)
- expandedLayout.load(context, R.xml.media_recommendation_expanded)
+ when (type) {
+ TYPE.PLAYER -> {
+ collapsedLayout.load(context, R.xml.media_collapsed)
+ expandedLayout.load(context, R.xml.media_expanded)
+ }
+ TYPE.PLAYER_SESSION -> {
+ collapsedLayout.clone(context, R.layout.media_session_view)
+ expandedLayout.clone(context, R.layout.media_session_view)
+ }
+ TYPE.RECOMMENDATION -> {
+ collapsedLayout.load(context, R.xml.media_recommendation_collapsed)
+ expandedLayout.load(context, R.xml.media_recommendation_expanded)
+ }
}
refreshState()
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
new file mode 100644
index 0000000..c333b50
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media
+
+import android.util.Log
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageButton
+import android.widget.ImageView
+import android.widget.SeekBar
+import android.widget.TextView
+import com.android.systemui.R
+import com.android.systemui.util.animation.TransitionLayout
+
+private const val TAG = "MediaViewHolder"
+
+/**
+ * Parent class for different media player views
+ */
+abstract class MediaViewHolder constructor(itemView: View) {
+ val player = itemView as TransitionLayout
+
+ // Player information
+ val appIcon = itemView.requireViewById<ImageView>(R.id.icon)
+ val titleText = itemView.requireViewById<TextView>(R.id.header_title)
+ val artistText = itemView.requireViewById<TextView>(R.id.header_artist)
+
+ // Output switcher
+ val seamless = itemView.requireViewById<ViewGroup>(R.id.media_seamless)
+ val seamlessIcon = itemView.requireViewById<ImageView>(R.id.media_seamless_image)
+ val seamlessText = itemView.requireViewById<TextView>(R.id.media_seamless_text)
+ val seamlessButton = itemView.requireViewById<View>(R.id.media_seamless_button)
+
+ // Seekbar views
+ val seekBar = itemView.requireViewById<SeekBar>(R.id.media_progress_bar)
+ open val elapsedTimeView: TextView? = null
+ open val totalTimeView: TextView? = null
+
+ // Settings screen
+ val longPressText = itemView.requireViewById<TextView>(R.id.remove_text)
+ val cancel = itemView.requireViewById<View>(R.id.cancel)
+ val dismiss = itemView.requireViewById<ViewGroup>(R.id.dismiss)
+ val dismissLabel = dismiss.getChildAt(0)
+ val settings = itemView.requireViewById<View>(R.id.settings)
+ val settingsText = itemView.requireViewById<TextView>(R.id.settings_text)
+
+ init {
+ (player.background as IlluminationDrawable).let {
+ it.registerLightSource(seamless)
+ it.registerLightSource(cancel)
+ it.registerLightSource(dismiss)
+ it.registerLightSource(settings)
+ }
+ }
+
+ abstract fun getAction(id: Int): ImageButton
+
+ fun marquee(start: Boolean, delay: Long) {
+ val longPressTextHandler = longPressText.getHandler()
+ if (longPressTextHandler == null) {
+ Log.d(TAG, "marquee while longPressText.getHandler() is null", Exception())
+ return
+ }
+ longPressTextHandler.postDelayed({ longPressText.setSelected(start) }, delay)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt
new file mode 100644
index 0000000..87d2cff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageButton
+import com.android.systemui.R
+
+/**
+ * ViewHolder for a media player with MediaSession-based controls
+ */
+class PlayerSessionViewHolder private constructor(itemView: View) : MediaViewHolder(itemView) {
+
+ // Action Buttons
+ val actionPlayPause = itemView.requireViewById<ImageButton>(R.id.actionPlayPause)
+ val actionNext = itemView.requireViewById<ImageButton>(R.id.actionNext)
+ val actionPrev = itemView.requireViewById<ImageButton>(R.id.actionPrev)
+ val actionStart = itemView.requireViewById<ImageButton>(R.id.actionStart)
+ val actionEnd = itemView.requireViewById<ImageButton>(R.id.actionEnd)
+
+ init {
+ (player.background as IlluminationDrawable).let {
+ it.registerLightSource(actionPlayPause)
+ it.registerLightSource(actionNext)
+ it.registerLightSource(actionPrev)
+ it.registerLightSource(actionStart)
+ it.registerLightSource(actionEnd)
+ }
+ }
+
+ override fun getAction(id: Int): ImageButton {
+ return when (id) {
+ R.id.actionPlayPause -> actionPlayPause
+ R.id.actionNext -> actionNext
+ R.id.actionPrev -> actionPrev
+ R.id.actionStart -> actionStart
+ R.id.actionEnd -> actionEnd
+ else -> {
+ throw IllegalArgumentException()
+ }
+ }
+ }
+
+ companion object {
+ /**
+ * Creates a PlayerSessionViewHolder.
+ *
+ * @param inflater LayoutInflater to use to inflate the layout.
+ * @param parent Parent of inflated view.
+ */
+ @JvmStatic fun create(
+ inflater: LayoutInflater,
+ parent: ViewGroup
+ ): PlayerSessionViewHolder {
+ val mediaView = inflater.inflate(R.layout.media_session_view, parent, false)
+ mediaView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
+ // Because this media view (a TransitionLayout) is used to measure and layout the views
+ // in various states before being attached to its parent, we can't depend on the default
+ // LAYOUT_DIRECTION_INHERIT to correctly resolve the ltr direction.
+ mediaView.layoutDirection = View.LAYOUT_DIRECTION_LOCALE
+ return PlayerSessionViewHolder(mediaView).apply {
+ // Media playback is in the direction of tape, not time, so it stays LTR
+ seekBar.layoutDirection = View.LAYOUT_DIRECTION_LTR
+ }
+ }
+
+ val controlsIds = setOf(
+ R.id.icon,
+ R.id.app_name,
+ R.id.header_title,
+ R.id.header_artist,
+ R.id.media_seamless,
+ R.id.media_progress_bar,
+ R.id.actionPlayPause,
+ R.id.actionNext,
+ R.id.actionPrev,
+ R.id.actionStart,
+ R.id.actionEnd,
+ R.id.icon
+ )
+ val gutsIds = setOf(
+ R.id.remove_text,
+ R.id.cancel,
+ R.id.dismiss,
+ R.id.settings
+ )
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
index 1322ade..a1faa40 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
@@ -16,43 +16,26 @@
package com.android.systemui.media
-import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.ImageView
-import android.widget.SeekBar
import android.widget.TextView
import com.android.systemui.R
-import com.android.systemui.util.animation.TransitionLayout
-
-private const val TAG = "PlayerViewHolder"
/**
* ViewHolder for a media player.
*/
-class PlayerViewHolder private constructor(itemView: View) {
-
- val player = itemView as TransitionLayout
+class PlayerViewHolder private constructor(itemView: View) : MediaViewHolder(itemView) {
// Player information
- val appIcon = itemView.requireViewById<ImageView>(R.id.icon)
val albumView = itemView.requireViewById<ImageView>(R.id.album_art)
- val titleText = itemView.requireViewById<TextView>(R.id.header_title)
- val artistText = itemView.requireViewById<TextView>(R.id.header_artist)
-
- // Output switcher
- val seamless = itemView.requireViewById<ViewGroup>(R.id.media_seamless)
- val seamlessIcon = itemView.requireViewById<ImageView>(R.id.media_seamless_image)
- val seamlessText = itemView.requireViewById<TextView>(R.id.media_seamless_text)
- val seamlessButton = itemView.requireViewById<View>(R.id.media_seamless_button)
// Seek bar
- val seekBar = itemView.requireViewById<SeekBar>(R.id.media_progress_bar)
val progressTimes = itemView.requireViewById<ViewGroup>(R.id.notification_media_progress_time)
- val elapsedTimeView = itemView.requireViewById<TextView>(R.id.media_elapsed_time)
- val totalTimeView = itemView.requireViewById<TextView>(R.id.media_total_time)
+ override val elapsedTimeView = itemView.requireViewById<TextView>(R.id.media_elapsed_time)
+ override val totalTimeView = itemView.requireViewById<TextView>(R.id.media_total_time)
// Action Buttons
val action0 = itemView.requireViewById<ImageButton>(R.id.action0)
@@ -61,29 +44,17 @@
val action3 = itemView.requireViewById<ImageButton>(R.id.action3)
val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
- // Settings screen
- val longPressText = itemView.requireViewById<TextView>(R.id.remove_text)
- val cancel = itemView.requireViewById<View>(R.id.cancel)
- val dismiss = itemView.requireViewById<ViewGroup>(R.id.dismiss)
- val dismissLabel = dismiss.getChildAt(0)
- val settings = itemView.requireViewById<View>(R.id.settings)
- val settingsText = itemView.requireViewById<TextView>(R.id.settings_text)
-
init {
(player.background as IlluminationDrawable).let {
- it.registerLightSource(seamless)
it.registerLightSource(action0)
it.registerLightSource(action1)
it.registerLightSource(action2)
it.registerLightSource(action3)
it.registerLightSource(action4)
- it.registerLightSource(cancel)
- it.registerLightSource(dismiss)
- it.registerLightSource(settings)
}
}
- fun getAction(id: Int): ImageButton {
+ override fun getAction(id: Int): ImageButton {
return when (id) {
R.id.action0 -> action0
R.id.action1 -> action1
@@ -96,15 +67,6 @@
}
}
- fun marquee(start: Boolean, delay: Long) {
- val longPressTextHandler = longPressText.getHandler()
- if (longPressTextHandler == null) {
- Log.d(TAG, "marquee while longPressText.getHandler() is null", Exception())
- return
- }
- longPressTextHandler.postDelayed({ longPressText.setSelected(start) }, delay)
- }
-
companion object {
/**
* Creates a PlayerViewHolder.
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
index 33ef19a..cf997055 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
@@ -26,16 +26,29 @@
*
* <p>Updates the seek bar views in response to changes to the model.
*/
-class SeekBarObserver(private val holder: PlayerViewHolder) : Observer<SeekBarViewModel.Progress> {
+class SeekBarObserver(
+ private val holder: MediaViewHolder,
+ private val useSessionLayout: Boolean
+) : Observer<SeekBarViewModel.Progress> {
val seekBarEnabledMaxHeight = holder.seekBar.context.resources
.getDimensionPixelSize(R.dimen.qs_media_enabled_seekbar_height)
val seekBarDisabledHeight = holder.seekBar.context.resources
.getDimensionPixelSize(R.dimen.qs_media_disabled_seekbar_height)
- val seekBarEnabledVerticalPadding = holder.seekBar.context.resources
- .getDimensionPixelSize(R.dimen.qs_media_enabled_seekbar_vertical_padding)
- val seekBarDisabledVerticalPadding = holder.seekBar.context.resources
- .getDimensionPixelSize(R.dimen.qs_media_disabled_seekbar_vertical_padding)
+ val seekBarEnabledVerticalPadding = if (useSessionLayout) {
+ holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_session_enabled_seekbar_vertical_padding)
+ } else {
+ holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_enabled_seekbar_vertical_padding)
+ }
+ val seekBarDisabledVerticalPadding = if (useSessionLayout) {
+ holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_session_disabled_seekbar_vertical_padding)
+ } else {
+ holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_disabled_seekbar_vertical_padding)
+ }
/** Updates seek bar views when the data model changes. */
@UiThread
@@ -48,8 +61,8 @@
holder.seekBar.setEnabled(false)
holder.seekBar.getThumb().setAlpha(0)
holder.seekBar.setProgress(0)
- holder.elapsedTimeView.setText("")
- holder.totalTimeView.setText("")
+ holder.elapsedTimeView?.setText("")
+ holder.totalTimeView?.setText("")
holder.seekBar.contentDescription = ""
return
}
@@ -65,13 +78,13 @@
holder.seekBar.setMax(data.duration)
val totalTimeString = DateUtils.formatElapsedTime(
data.duration / DateUtils.SECOND_IN_MILLIS)
- holder.totalTimeView.setText(totalTimeString)
+ holder.totalTimeView?.setText(totalTimeString)
data.elapsedTime?.let {
holder.seekBar.setProgress(it)
val elapsedTimeString = DateUtils.formatElapsedTime(
it / DateUtils.SECOND_IN_MILLIS)
- holder.elapsedTimeView.setText(elapsedTimeString)
+ holder.elapsedTimeView?.setText(elapsedTimeString)
holder.seekBar.contentDescription = holder.seekBar.context.getString(
R.string.controls_media_seekbar_description,
diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
index 1174fa8..558f0e6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
@@ -26,9 +26,10 @@
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.media.MediaHostStatesManager;
-import com.android.systemui.media.taptotransfer.MediaTttChipController;
import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
import com.android.systemui.media.taptotransfer.MediaTttFlags;
+import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver;
+import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender;
import com.android.systemui.statusbar.commandline.CommandRegistry;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -80,7 +81,7 @@
/** */
@Provides
@SysUISingleton
- static Optional<MediaTttChipController> providesMediaTttChipController(
+ static Optional<MediaTttChipControllerSender> providesMediaTttChipControllerSender(
MediaTttFlags mediaTttFlags,
Context context,
WindowManager windowManager,
@@ -89,22 +90,42 @@
if (!mediaTttFlags.isMediaTttEnabled()) {
return Optional.empty();
}
- return Optional.of(new MediaTttChipController(
+ return Optional.of(new MediaTttChipControllerSender(
context, windowManager, mainExecutor, backgroundExecutor));
}
/** */
@Provides
@SysUISingleton
+ static Optional<MediaTttChipControllerReceiver> providesMediaTttChipControllerReceiver(
+ MediaTttFlags mediaTttFlags,
+ Context context,
+ WindowManager windowManager) {
+ if (!mediaTttFlags.isMediaTttEnabled()) {
+ return Optional.empty();
+ }
+ return Optional.of(new MediaTttChipControllerReceiver(context, windowManager));
+ }
+
+ /** */
+ @Provides
+ @SysUISingleton
static Optional<MediaTttCommandLineHelper> providesMediaTttCommandLineHelper(
MediaTttFlags mediaTttFlags,
CommandRegistry commandRegistry,
- MediaTttChipController mediaTttChipController,
+ Context context,
+ MediaTttChipControllerSender mediaTttChipControllerSender,
+ MediaTttChipControllerReceiver mediaTttChipControllerReceiver,
@Main DelayableExecutor mainExecutor) {
if (!mediaTttFlags.isMediaTttEnabled()) {
return Optional.empty();
}
- return Optional.of(new MediaTttCommandLineHelper(
- commandRegistry, mediaTttChipController, mainExecutor));
+ return Optional.of(
+ new MediaTttCommandLineHelper(
+ commandRegistry,
+ context,
+ mediaTttChipControllerSender,
+ mediaTttChipControllerReceiver,
+ mainExecutor));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipState.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipState.kt
deleted file mode 100644
index 1f308a9a..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipState.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media.taptotransfer
-
-import androidx.annotation.StringRes
-import com.android.systemui.R
-import java.util.concurrent.Future
-
-/**
- * A class that stores all the information necessary to display the media tap-to-transfer chip in
- * certain states.
- *
- * This is a sealed class where each subclass represents a specific chip state. Each subclass can
- * contain additional information that is necessary for only that state.
- */
-sealed class MediaTttChipState(
- /** A string resource for the text that the chip should display. */
- @StringRes internal val chipText: Int,
- /** The name of the other device involved in the transfer. */
- internal val otherDeviceName: String
-)
-
-/**
- * A state representing that the two devices are close but not close enough to initiate a transfer.
- * The chip will instruct the user to move closer in order to initiate the transfer.
- */
-class MoveCloserToTransfer(
- otherDeviceName: String
-) : MediaTttChipState(R.string.media_move_closer_to_transfer, otherDeviceName)
-
-/**
- * A state representing that a transfer has been initiated (but not completed).
- *
- * @property future a future that will be resolved when the transfer has either succeeded or failed.
- * If the transfer succeeded, the future can optionally return an undo runnable (see
- * [TransferSucceeded.undoRunnable]). [MediaTttChipController] is responsible for transitioning
- * the chip to the [TransferSucceeded] state if the future resolves successfully.
- */
-class TransferInitiated(
- otherDeviceName: String,
- val future: Future<Runnable?>
-) : MediaTttChipState(R.string.media_transfer_playing, otherDeviceName)
-
-/**
- * A state representing that a transfer has been successfully completed.
- *
- * @property undoRunnable if present, the runnable that should be run to undo the transfer. We will
- * show an Undo button on the chip if this runnable is present.
- */
-class TransferSucceeded(
- otherDeviceName: String,
- val undoRunnable: Runnable? = null
-) : MediaTttChipState(R.string.media_transfer_playing, otherDeviceName)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
index 663037c..5a86723 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
@@ -16,10 +16,20 @@
package com.android.systemui.media.taptotransfer
+import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.Icon
import android.util.Log
import androidx.annotation.VisibleForTesting
+import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
+import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver
+import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender
+import com.android.systemui.media.taptotransfer.sender.MoveCloserToTransfer
+import com.android.systemui.media.taptotransfer.sender.TransferInitiated
+import com.android.systemui.media.taptotransfer.sender.TransferSucceeded
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.util.concurrency.DelayableExecutor
@@ -34,32 +44,59 @@
@SysUISingleton
class MediaTttCommandLineHelper @Inject constructor(
commandRegistry: CommandRegistry,
- private val mediaTttChipController: MediaTttChipController,
+ context: Context,
+ private val mediaTttChipControllerSender: MediaTttChipControllerSender,
+ private val mediaTttChipControllerReceiver: MediaTttChipControllerReceiver,
@Main private val mainExecutor: DelayableExecutor,
) {
+ private val appIconDrawable =
+ Icon.createWithResource(context, R.drawable.ic_avatar_user).loadDrawable(context).also {
+ it.setTint(Color.YELLOW)
+ }
+
init {
- commandRegistry.registerCommand(ADD_CHIP_COMMAND_TAG) { AddChipCommand() }
- commandRegistry.registerCommand(REMOVE_CHIP_COMMAND_TAG) { RemoveChipCommand() }
+ commandRegistry.registerCommand(
+ ADD_CHIP_COMMAND_SENDER_TAG) { AddChipCommandSender() }
+ commandRegistry.registerCommand(
+ REMOVE_CHIP_COMMAND_SENDER_TAG) { RemoveChipCommandSender() }
+ commandRegistry.registerCommand(
+ ADD_CHIP_COMMAND_RECEIVER_TAG) { AddChipCommandReceiver() }
+ commandRegistry.registerCommand(
+ REMOVE_CHIP_COMMAND_RECEIVER_TAG) { RemoveChipCommandReceiver() }
}
- inner class AddChipCommand : Command {
+ inner class AddChipCommandSender : Command {
override fun execute(pw: PrintWriter, args: List<String>) {
val otherDeviceName = args[0]
when (args[1]) {
MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME -> {
- mediaTttChipController.displayChip(MoveCloserToTransfer(otherDeviceName))
+ mediaTttChipControllerSender.displayChip(
+ MoveCloserToTransfer(
+ appIconDrawable, APP_ICON_CONTENT_DESCRIPTION, otherDeviceName
+ )
+ )
}
TRANSFER_INITIATED_COMMAND_NAME -> {
val futureTask = FutureTask { fakeUndoRunnable }
- mediaTttChipController.displayChip(
- TransferInitiated(otherDeviceName, futureTask)
+ mediaTttChipControllerSender.displayChip(
+ TransferInitiated(
+ appIconDrawable,
+ APP_ICON_CONTENT_DESCRIPTION,
+ otherDeviceName,
+ futureTask
+ )
)
mainExecutor.executeDelayed({ futureTask.run() }, FUTURE_WAIT_TIME)
}
TRANSFER_SUCCEEDED_COMMAND_NAME -> {
- mediaTttChipController.displayChip(
- TransferSucceeded(otherDeviceName, fakeUndoRunnable)
+ mediaTttChipControllerSender.displayChip(
+ TransferSucceeded(
+ appIconDrawable,
+ APP_ICON_CONTENT_DESCRIPTION,
+ otherDeviceName,
+ fakeUndoRunnable
+ )
)
}
else -> {
@@ -73,18 +110,42 @@
}
override fun help(pw: PrintWriter) {
- pw.println(
- "Usage: adb shell cmd statusbar $ADD_CHIP_COMMAND_TAG <deviceName> <chipStatus>"
+ pw.println("Usage: adb shell cmd statusbar " +
+ "$ADD_CHIP_COMMAND_SENDER_TAG <deviceName> <chipStatus>"
)
}
}
- inner class RemoveChipCommand : Command {
+ /** A command to REMOVE the media ttt chip on the SENDER device. */
+ inner class RemoveChipCommandSender : Command {
override fun execute(pw: PrintWriter, args: List<String>) {
- mediaTttChipController.removeChip()
+ mediaTttChipControllerSender.removeChip()
}
override fun help(pw: PrintWriter) {
- pw.println("Usage: adb shell cmd statusbar $REMOVE_CHIP_COMMAND_TAG")
+ pw.println("Usage: adb shell cmd statusbar $REMOVE_CHIP_COMMAND_SENDER_TAG")
+ }
+ }
+
+
+ /** A command to DISPLAY the media ttt chip on the RECEIVER device. */
+ inner class AddChipCommandReceiver : Command {
+ override fun execute(pw: PrintWriter, args: List<String>) {
+ mediaTttChipControllerReceiver.displayChip(
+ ChipStateReceiver(appIconDrawable, APP_ICON_CONTENT_DESCRIPTION)
+ )
+ }
+ override fun help(pw: PrintWriter) {
+ pw.println("Usage: adb shell cmd statusbar $ADD_CHIP_COMMAND_RECEIVER_TAG")
+ }
+ }
+
+ /** A command to REMOVE the media ttt chip on the RECEIVER device. */
+ inner class RemoveChipCommandReceiver : Command {
+ override fun execute(pw: PrintWriter, args: List<String>) {
+ mediaTttChipControllerReceiver.removeChip()
+ }
+ override fun help(pw: PrintWriter) {
+ pw.println("Usage: adb shell cmd statusbar $REMOVE_CHIP_COMMAND_RECEIVER_TAG")
}
}
@@ -94,9 +155,13 @@
}
@VisibleForTesting
-const val ADD_CHIP_COMMAND_TAG = "media-ttt-chip-add"
+const val ADD_CHIP_COMMAND_SENDER_TAG = "media-ttt-chip-add-sender"
@VisibleForTesting
-const val REMOVE_CHIP_COMMAND_TAG = "media-ttt-chip-remove"
+const val REMOVE_CHIP_COMMAND_SENDER_TAG = "media-ttt-chip-remove-sender"
+@VisibleForTesting
+const val ADD_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-add-receiver"
+@VisibleForTesting
+const val REMOVE_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-remove-receiver"
@VisibleForTesting
val MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME = MoveCloserToTransfer::class.simpleName!!
@VisibleForTesting
@@ -105,3 +170,5 @@
val TRANSFER_SUCCEEDED_COMMAND_NAME = TransferSucceeded::class.simpleName!!
private const val FUTURE_WAIT_TIME = 2000L
+private const val APP_ICON_CONTENT_DESCRIPTION = "Fake media app icon"
+private const val TAG = "MediaTapToTransferCli"
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/README.md b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/README.md
new file mode 100644
index 0000000..1145891
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/README.md
@@ -0,0 +1,11 @@
+# Media Tap-To-Transfer
+
+This package (and child packages) include code for the media tap-to-transfer feature, which
+allows users to easily transfer playing media between devices.
+
+In media transfer, there are two devices: the *sender* and the *receiver*. The sender device will
+start and stop media casts to the receiver device. On both devices, System UI will display a chip
+informing the user about the media cast occurring.
+
+This package is structured so that the sender code is in the sender package, the receiver code is
+in the receiver package, and code that's shared between them is in the common package.
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
new file mode 100644
index 0000000..67721a5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.taptotransfer.common
+
+import android.annotation.LayoutRes
+import android.annotation.SuppressLint
+import android.content.Context
+import android.graphics.PixelFormat
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import android.view.WindowManager
+import com.android.internal.widget.CachingIconView
+import com.android.systemui.R
+
+/**
+ * A superclass controller that provides common functionality for showing chips on the sender device
+ * and the receiver device.
+ *
+ * Subclasses need to override and implement [updateChipView], which is where they can control what
+ * gets displayed to the user.
+ */
+abstract class MediaTttChipControllerCommon<T : MediaTttChipState>(
+ private val context: Context,
+ private val windowManager: WindowManager,
+ @LayoutRes private val chipLayoutRes: Int
+) {
+ /** The window layout parameters we'll use when attaching the view to a window. */
+ @SuppressLint("WrongConstant") // We're allowed to use TYPE_VOLUME_OVERLAY
+ private val windowLayoutParams = WindowManager.LayoutParams().apply {
+ width = WindowManager.LayoutParams.WRAP_CONTENT
+ height = WindowManager.LayoutParams.WRAP_CONTENT
+ gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL)
+ type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY
+ flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ title = "Media Tap-To-Transfer Chip View"
+ format = PixelFormat.TRANSLUCENT
+ setTrustedOverlay()
+ }
+
+ /** The chip view currently being displayed. Null if the chip is not being displayed. */
+ var chipView: ViewGroup? = null
+
+ /**
+ * Displays the chip with the current state.
+ *
+ * This method handles inflating and attaching the view, then delegates to [updateChipView] to
+ * display the correct information in the chip.
+ */
+ fun displayChip(chipState: T) {
+ val oldChipView = chipView
+ if (chipView == null) {
+ chipView = LayoutInflater
+ .from(context)
+ .inflate(chipLayoutRes, null) as ViewGroup
+ }
+ val currentChipView = chipView!!
+
+ updateChipView(chipState, currentChipView)
+
+ // Add view if necessary
+ if (oldChipView == null) {
+ windowManager.addView(chipView, windowLayoutParams)
+ }
+ }
+
+
+ /** Hides the chip. */
+ fun removeChip() {
+ if (chipView == null) { return }
+ windowManager.removeView(chipView)
+ chipView = null
+ }
+
+ /**
+ * A method implemented by subclasses to update [currentChipView] based on [chipState].
+ */
+ abstract fun updateChipView(chipState: T, currentChipView: ViewGroup)
+
+ /**
+ * An internal method to set the icon on the view.
+ *
+ * This is in the common superclass since both the sender and the receiver show an icon.
+ */
+ internal fun setIcon(chipState: T, currentChipView: ViewGroup) {
+ currentChipView.findViewById<CachingIconView>(R.id.app_icon).apply {
+ this.setImageDrawable(chipState.appIconDrawable)
+ this.contentDescription = chipState.appIconContentDescription
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt
new file mode 100644
index 0000000..c510cbb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.taptotransfer.common
+
+import android.graphics.drawable.Drawable
+
+/**
+ * A superclass chip state that will be subclassed by the sender chip and receiver chip.
+ *
+ * @property appIconDrawable a drawable representing the icon of the app playing the media.
+ * @property appIconContentDescription a string to use as the content description for the icon.
+ */
+open class MediaTttChipState(
+ internal val appIconDrawable: Drawable,
+ internal val appIconContentDescription: String
+)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt
new file mode 100644
index 0000000..df6b934
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.taptotransfer.receiver
+
+import android.graphics.drawable.Drawable
+import com.android.systemui.media.taptotransfer.common.MediaTttChipState
+
+/**
+ * A class that stores all the information necessary to display the media tap-to-transfer chip on
+ * the receiver device.
+ */
+class ChipStateReceiver(
+ appIconDrawable: Drawable,
+ appIconContentDescription: String
+) : MediaTttChipState(appIconDrawable, appIconContentDescription)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
new file mode 100644
index 0000000..1780954
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.taptotransfer.receiver
+
+import android.content.Context
+import android.view.ViewGroup
+import android.view.WindowManager
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
+import javax.inject.Inject
+
+/**
+ * A controller to display and hide the Media Tap-To-Transfer chip on the **receiving** device.
+ *
+ * This chip is shown when a user is transferring media to/from a sending device and this device.
+ */
+@SysUISingleton
+class MediaTttChipControllerReceiver @Inject constructor(
+ context: Context,
+ windowManager: WindowManager,
+) : MediaTttChipControllerCommon<ChipStateReceiver>(
+ context, windowManager, R.layout.media_ttt_chip_receiver
+) {
+
+ override fun updateChipView(chipState: ChipStateReceiver, currentChipView: ViewGroup) {
+ setIcon(chipState, currentChipView)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
new file mode 100644
index 0000000..b1f6faa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.taptotransfer.sender
+
+import android.graphics.drawable.Drawable
+import androidx.annotation.StringRes
+import com.android.systemui.R
+import com.android.systemui.media.taptotransfer.common.MediaTttChipState
+import java.util.concurrent.Future
+
+/**
+ * A class that stores all the information necessary to display the media tap-to-transfer chip on
+ * the sender device.
+ *
+ * This is a sealed class where each subclass represents a specific chip state. Each subclass can
+ * contain additional information that is necessary for only that state.
+ *
+ * @property chipText a string resource for the text that the chip should display.
+ * @property otherDeviceName the name of the other device involved in the transfer.
+ */
+sealed class ChipStateSender(
+ appIconDrawable: Drawable,
+ appIconContentDescription: String,
+ @StringRes internal val chipText: Int,
+ internal val otherDeviceName: String,
+) : MediaTttChipState(appIconDrawable, appIconContentDescription)
+
+/**
+ * A state representing that the two devices are close but not close enough to initiate a transfer.
+ * The chip will instruct the user to move closer in order to initiate the transfer.
+ */
+class MoveCloserToTransfer(
+ appIconDrawable: Drawable,
+ appIconContentDescription: String,
+ otherDeviceName: String,
+) : ChipStateSender(
+ appIconDrawable,
+ appIconContentDescription,
+ R.string.media_move_closer_to_transfer,
+ otherDeviceName
+)
+
+/**
+ * A state representing that a transfer has been initiated (but not completed).
+ *
+ * @property future a future that will be resolved when the transfer has either succeeded or failed.
+ * If the transfer succeeded, the future can optionally return an undo runnable (see
+ * [TransferSucceeded.undoRunnable]). [MediaTttChipControllerSender] is responsible for transitioning
+ * the chip to the [TransferSucceeded] state if the future resolves successfully.
+ */
+class TransferInitiated(
+ appIconDrawable: Drawable,
+ appIconContentDescription: String,
+ otherDeviceName: String,
+ val future: Future<Runnable?>
+) : ChipStateSender(
+ appIconDrawable,
+ appIconContentDescription,
+ R.string.media_transfer_playing,
+ otherDeviceName
+)
+
+/**
+ * A state representing that a transfer has been successfully completed.
+ *
+ * @property undoRunnable if present, the runnable that should be run to undo the transfer. We will
+ * show an Undo button on the chip if this runnable is present.
+ */
+class TransferSucceeded(
+ appIconDrawable: Drawable,
+ appIconContentDescription: String,
+ otherDeviceName: String,
+ val undoRunnable: Runnable? = null
+) : ChipStateSender(appIconDrawable,
+ appIconContentDescription,
+ R.string.media_transfer_playing,
+ otherDeviceName
+)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
similarity index 60%
rename from packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt
rename to packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
index baa469d..77d3d70 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
@@ -14,65 +14,40 @@
* limitations under the License.
*/
-package com.android.systemui.media.taptotransfer
+package com.android.systemui.media.taptotransfer.sender
-import android.annotation.SuppressLint
import android.content.Context
-import android.graphics.PixelFormat
-import android.view.Gravity
-import android.view.LayoutInflater
import android.view.View
+import android.view.ViewGroup
import android.view.WindowManager
-import android.widget.LinearLayout
import android.widget.TextView
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
import java.util.concurrent.Executor
import java.util.concurrent.TimeUnit
import javax.inject.Inject
-const val TAG = "MediaTapToTransfer"
-
/**
- * A controller to display and hide the Media Tap-To-Transfer chip. This chip is shown when a user
- * is currently playing media on a local "media cast sender" device (e.g. a phone) and gets close
- * enough to a "media cast receiver" device (e.g. a tablet). This chip encourages the user to
- * transfer the media from the sender device to the receiver device.
+ * A controller to display and hide the Media Tap-To-Transfer chip on the **sending** device. This
+ * chip is shown when a user is transferring media to/from this device and a receiver device.
*/
@SysUISingleton
-class MediaTttChipController @Inject constructor(
- private val context: Context,
- private val windowManager: WindowManager,
+class MediaTttChipControllerSender @Inject constructor(
+ context: Context,
+ windowManager: WindowManager,
@Main private val mainExecutor: Executor,
@Background private val backgroundExecutor: Executor,
+) : MediaTttChipControllerCommon<ChipStateSender>(
+ context, windowManager, R.layout.media_ttt_chip
) {
- @SuppressLint("WrongConstant") // We're allowed to use TYPE_VOLUME_OVERLAY
- private val windowLayoutParams = WindowManager.LayoutParams().apply {
- width = WindowManager.LayoutParams.WRAP_CONTENT
- height = WindowManager.LayoutParams.WRAP_CONTENT
- gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL)
- type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY
- flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- title = "Media Tap-To-Transfer Chip View"
- format = PixelFormat.TRANSLUCENT
- setTrustedOverlay()
- }
-
- /** The chip view currently being displayed. Null if the chip is not being displayed. */
- private var chipView: LinearLayout? = null
-
/** Displays the chip view for the given state. */
- fun displayChip(chipState: MediaTttChipState) {
- val oldChipView = chipView
- if (chipView == null) {
- chipView = LayoutInflater
- .from(context)
- .inflate(R.layout.media_ttt_chip, null) as LinearLayout
- }
- val currentChipView = chipView!!
+ override fun updateChipView(chipState: ChipStateSender, currentChipView: ViewGroup) {
+ // App icon
+ setIcon(chipState, currentChipView)
// Text
currentChipView.requireViewById<TextView>(R.id.text).apply {
@@ -102,18 +77,6 @@
if (chipState is TransferInitiated) {
addFutureCallback(chipState)
}
-
- // Add view if necessary
- if (oldChipView == null) {
- windowManager.addView(chipView, windowLayoutParams)
- }
- }
-
- /** Hides the chip. */
- fun removeChip() {
- if (chipView == null) { return }
- windowManager.removeView(chipView)
- chipView = null
}
/**
@@ -128,7 +91,14 @@
val undoRunnable = chipState.future.get(TRANSFER_TIMEOUT_SECONDS, TimeUnit.SECONDS)
// Make UI changes on the main thread
mainExecutor.execute {
- displayChip(TransferSucceeded(chipState.otherDeviceName, undoRunnable))
+ displayChip(
+ TransferSucceeded(
+ chipState.appIconDrawable,
+ chipState.appIconContentDescription,
+ chipState.otherDeviceName,
+ undoRunnable
+ )
+ )
}
} catch (ex: Exception) {
// TODO(b/203800327): Maybe show a failure chip here if UX decides we need one.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index d2d2180..c2a82a7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -49,15 +49,9 @@
/** Quick settings tile: Invert colors **/
public class ColorInversionTile extends QSTileImpl<BooleanState> {
- private static final String EXTRA_FRAGMENT_ARGS_KEY = ":settings:fragment_args_key";
- private static final String EXTRA_SHOW_FRAGMENT_ARGS_KEY = ":settings:show_fragment_args";
- private static final String COLOR_INVERSION_PREFERENCE_KEY = "toggle_inversion_preference";
-
private final Icon mIcon = ResourceIcon.get(drawable.ic_invert_colors);
private final SettingObserver mSetting;
- private boolean mListening;
-
@Inject
public ColorInversionTile(
QSHost host,
@@ -126,11 +120,7 @@
protected void handleUpdateState(BooleanState state, Object arg) {
final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
final boolean enabled = value != 0;
- if (state.slash == null) {
- state.slash = new SlashState();
- }
state.value = enabled;
- state.slash.isSlashed = !state.value;
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.label = mContext.getString(R.string.quick_settings_inversion_label);
state.icon = mIcon;
@@ -142,15 +132,4 @@
public int getMetricsCategory() {
return MetricsEvent.QS_COLORINVERSION;
}
-
- @Override
- protected String composeChangeAnnouncement() {
- if (mState.value) {
- return mContext.getString(
- R.string.accessibility_quick_settings_color_inversion_changed_on);
- } else {
- return mContext.getString(
- R.string.accessibility_quick_settings_color_inversion_changed_off);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 0bbb5bd..082dc5c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -16,12 +16,18 @@
package com.android.systemui.qs.tiles;
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+
+import static com.android.systemui.statusbar.policy.RotationLockControllerImpl.hasSufficientPermission;
+
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.hardware.SensorPrivacyManager;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
+import android.provider.Settings.Secure;
import android.service.quicksettings.Tile;
import android.view.View;
import android.widget.Switch;
@@ -38,18 +44,25 @@
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.SettingObserver;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.RotationLockController;
import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
+import com.android.systemui.util.settings.SecureSettings;
import javax.inject.Inject;
/** Quick settings tile: Rotation **/
-public class RotationLockTile extends QSTileImpl<BooleanState> {
+public class RotationLockTile extends QSTileImpl<BooleanState> implements
+ BatteryController.BatteryStateChangeCallback {
private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_auto_rotate);
private final RotationLockController mController;
+ private final SensorPrivacyManager mPrivacyManager;
+ private final BatteryController mBatteryController;
+ private final SettingObserver mSetting;
@Inject
public RotationLockTile(
@@ -61,12 +74,41 @@
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
- RotationLockController rotationLockController
+ RotationLockController rotationLockController,
+ SensorPrivacyManager privacyManager,
+ BatteryController batteryController,
+ SecureSettings secureSettings
) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
mController = rotationLockController;
mController.observe(this, mCallback);
+ mPrivacyManager = privacyManager;
+ mBatteryController = batteryController;
+ int currentUser = host.getUserContext().getUserId();
+ mSetting = new SettingObserver(
+ secureSettings,
+ mHandler,
+ Secure.CAMERA_AUTOROTATE,
+ currentUser
+ ) {
+ @Override
+ protected void handleValueChanged(int value, boolean observedChange) {
+ // mHandler is the background handler so calling this is OK
+ handleRefreshState(null);
+ }
+ };
+ mBatteryController.observe(getLifecycle(), this);
+ }
+
+ @Override
+ protected void handleInitialize() {
+ mPrivacyManager.addSensorPrivacyListener(CAMERA, mSensorPrivacyChangedListener);
+ }
+
+ @Override
+ public void onPowerSaveChanged(boolean isPowerSave) {
+ refreshState();
}
@Override
@@ -95,14 +137,46 @@
protected void handleUpdateState(BooleanState state, Object arg) {
final boolean rotationLocked = mController.isRotationLocked();
+ final boolean powerSave = mBatteryController.isPowerSave();
+ final boolean cameraLocked = mPrivacyManager.isSensorPrivacyEnabled(CAMERA);
+ final boolean cameraRotation =
+ !powerSave && !cameraLocked && hasSufficientPermission(mContext)
+ && mController.isCameraRotationEnabled();
state.value = !rotationLocked;
state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
state.icon = mIcon;
state.contentDescription = getAccessibilityString(rotationLocked);
+ if (!rotationLocked && cameraRotation) {
+ state.secondaryLabel = mContext.getResources().getString(
+ R.string.rotation_lock_camera_rotation_on);
+ } else {
+ state.secondaryLabel = "";
+ }
+ state.stateDescription = state.secondaryLabel;
+
state.expandedAccessibilityClassName = Switch.class.getName();
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
}
+ @Override
+ protected void handleDestroy() {
+ super.handleDestroy();
+ mSetting.setListening(false);
+ mPrivacyManager.removeSensorPrivacyListener(CAMERA, mSensorPrivacyChangedListener);
+ }
+
+ @Override
+ public void handleSetListening(boolean listening) {
+ super.handleSetListening(listening);
+ mSetting.setListening(listening);
+ }
+
+ @Override
+ protected void handleUserSwitch(int newUserId) {
+ mSetting.setUserId(newUserId);
+ handleRefreshState(null);
+ }
+
public static boolean isCurrentOrientationLockPortrait(RotationLockController controller,
Resources resources) {
int lockOrientation = controller.getRotationLockOrientation();
@@ -140,4 +214,8 @@
refreshState(rotationLocked);
}
};
+
+ private final SensorPrivacyManager.OnSensorPrivacyChangedListener
+ mSensorPrivacyChangedListener =
+ (sensor, enabled) -> refreshState();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 03d8e7e..c8115e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -92,6 +92,8 @@
override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
val interpolatedAmount = INTERPOLATOR.getInterpolation(amount)
+ scrim.interpolatedRevealAmount = interpolatedAmount
+
scrim.startColorAlpha =
getPercentPastThreshold(1 - interpolatedAmount,
threshold = 1 - START_COLOR_REVEAL_PERCENTAGE)
@@ -152,6 +154,7 @@
// non-interpolated amount
val fadeAmount = getPercentPastThreshold(amount, 0.5f)
val radius = startRadius + ((endRadius - startRadius) * amount)
+ scrim.interpolatedRevealAmount = amount
scrim.revealGradientEndColorAlpha = 1f - fadeAmount
scrim.setRevealGradientBounds(
centerX - radius /* left */,
@@ -182,6 +185,7 @@
with(scrim) {
revealGradientEndColorAlpha = 1f - fadeAmount
+ interpolatedRevealAmount = interpolatedAmount
setRevealGradientBounds(
width * (1f + OFF_SCREEN_START_AMOUNT) -
width * WIDTH_INCREASE_MULTIPLIER * interpolatedAmount,
@@ -284,6 +288,14 @@
}
}
+ var interpolatedRevealAmount: Float = 1f
+
+ val isScrimAlmostOccludes: Boolean
+ get() {
+ // if the interpolatedRevealAmount less than 0.1, over 90% of the screen is black.
+ return interpolatedRevealAmount < 0.1f
+ }
+
private fun updateScrimOpaque() {
isScrimOpaque = revealAmount == 0.0f && alpha == 1.0f && visibility == VISIBLE
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 210ee96..3730d12 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -379,6 +379,7 @@
}
}
+ @Nullable
public String getMediaNotificationKey() {
return mMediaNotificationKey;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index f500d39..4717b3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -20,8 +20,6 @@
import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_UNKNOWN;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationCallback;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.Notification;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -33,6 +31,9 @@
import android.util.ArraySet;
import android.util.Log;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
@@ -123,8 +124,8 @@
* filtered out if for instance they are not for the current user
*/
private final ArrayMap<String, NotificationEntry> mActiveNotifications = new ArrayMap<>();
- @VisibleForTesting
/** This is the list of "active notifications for this user in this context" */
+ @VisibleForTesting
protected final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>();
private final List<NotificationEntry> mReadOnlyNotifications =
Collections.unmodifiableList(mSortedAndFiltered);
@@ -899,7 +900,7 @@
}
/** Calls to NotificationRankingManager and updates mSortedAndFiltered */
- private void updateRankingAndSort(@NonNull RankingMap rankingMap, String reason) {
+ private void updateRankingAndSort(RankingMap rankingMap, String reason) {
if (mNotifPipelineFlags.isNewPipelineEnabled()) {
mLogger.logUseWhileNewPipelineActive("updateRankingAndSort", reason);
return;
@@ -961,6 +962,7 @@
* Returns a collections containing ALL notifications we know about, including ones that are
* hidden or for other users. See {@link CommonNotifCollection#getAllNotifs()}.
*/
+ @NonNull
@Override
public Collection<NotificationEntry> getAllNotifs() {
mNotifPipelineFlags.checkLegacyPipelineEnabled();
@@ -969,7 +971,7 @@
@Nullable
@Override
- public NotificationEntry getEntry(String key) {
+ public NotificationEntry getEntry(@NonNull String key) {
mNotifPipelineFlags.checkLegacyPipelineEnabled();
return getPendingOrActiveNotif(key);
}
@@ -989,7 +991,7 @@
}
@Override
- public void addCollectionListener(NotifCollectionListener listener) {
+ public void addCollectionListener(@NonNull NotifCollectionListener listener) {
mNotifCollectionListeners.add(listener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index f8f1279..b6b9c3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -44,7 +44,6 @@
import android.annotation.IntDef;
import android.annotation.MainThread;
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.Notification;
import android.os.Handler;
@@ -59,6 +58,7 @@
import android.util.Pair;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.Dumpable;
@@ -193,7 +193,8 @@
}
/** @see NotifPipeline#getEntry(String) () */
- NotificationEntry getEntry(String key) {
+ @Nullable
+ NotificationEntry getEntry(@NonNull String key) {
return mNotificationSet.get(key);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
index e9b7caa5..85c0064 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
@@ -82,11 +82,8 @@
public void attach(NotifPipeline pipeline) {
mNotifPipeline = pipeline;
mNotifPipeline.addNotificationDismissInterceptor(mDismissInterceptor);
- mNotifPipeline.addFinalizeFilter(mNotifFilter);
- if (mBubblesManagerOptional.isPresent()) {
- mBubblesManagerOptional.get().addNotifCallback(mNotifCallback);
- }
-
+ mNotifPipeline.addPreGroupFilter(mNotifFilter);
+ mBubblesManagerOptional.ifPresent(manager -> manager.addNotifCallback(mNotifCallback));
}
private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index fe1cd7b..33005b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -90,6 +90,7 @@
readShowSilentNotificationSetting();
setupInvalidateNotifListCallbacks();
+ // Filter at the "finalize" stage so that views remain bound by PreparationCoordinator
pipeline.addFinalizeFilter(mNotifFilter);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
index 8769969..ecee006 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
@@ -49,6 +49,6 @@
@Override
public void attach(NotifPipeline pipeline) {
- pipeline.addFinalizeFilter(mMediaFilter);
+ pipeline.addPreGroupFilter(mMediaFilter);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java
index 471c357..beaa1ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection.notifcollection;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -37,7 +38,7 @@
* Registers a listener to be informed when notifications are created, added, updated, removed,
* or deleted.
*/
- void addCollectionListener(NotifCollectionListener listener);
+ void addCollectionListener(@NonNull NotifCollectionListener listener);
/**
* Returns the list of all known notifications, i.e. the notifications that are currently posted
@@ -46,11 +47,11 @@
*
* The returned collection is read-only, unsorted, unfiltered, and ungrouped.
*/
- Collection<NotificationEntry> getAllNotifs();
+ @NonNull Collection<NotificationEntry> getAllNotifs();
/**
* Returns the notification entry for the given notification key;
* the returned entry (if present) may be in any state.
*/
- @Nullable NotificationEntry getEntry(String key);
+ @Nullable NotificationEntry getEntry(@NonNull String key);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
index b2e15f4..b61a540 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
@@ -77,11 +77,11 @@
override fun onPrimaryMetadataOrStateChanged(metadata: MediaMetadata?, state: Int) {
val previous = currentMediaEntry
- var newEntry = commonNotifCollection.getEntry(mediaManager.mediaNotificationKey)
- if (!NotificationMediaManager.isPlayingState(state)) {
- newEntry = null
- }
- currentMediaEntry = newEntry
+ val mediaNotificationKey = mediaManager.mediaNotificationKey
+ currentMediaEntry =
+ if (mediaNotificationKey != null && NotificationMediaManager.isPlayingState(state))
+ commonNotifCollection.getEntry(mediaNotificationKey)
+ else null
updateAutoHeadsUp(previous)
updateAutoHeadsUp(currentMediaEntry)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 4b3d6f7..ab36da5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -23,8 +23,10 @@
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.IndentingPrintWriter;
+import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewParent;
import android.widget.FrameLayout;
import androidx.annotation.Nullable;
@@ -517,6 +519,36 @@
return mChangingPosition;
}
+ /**
+ * Called before adding this view to a group, which would always throw an exception if this view
+ * has a parent, so clean up the transient container and throw an exception if the parent isn't
+ * a transient container. Provide as much detail in the event of a crash as possible.
+ */
+ public void removeFromTransientContainerForAdditionTo(ViewGroup newParent) {
+ final ViewParent parent = getParent();
+ if (parent == null) {
+ // If this view has no parent, the add will succeed, so do nothing.
+ return;
+ }
+ ViewGroup transientContainer = getTransientContainer();
+ if (transientContainer == null) {
+ throw new IllegalStateException(
+ "Can't add view " + this + " to container " + newParent + "; current parent "
+ + parent + " is not a transient container");
+ }
+ if (transientContainer != parent) {
+ throw new IllegalStateException(
+ "Expandable view " + this + " has transient container " + transientContainer
+ + " which is not the same as its parent " + parent);
+ }
+ if (parent != newParent) {
+ Log.w(TAG, "Moving view " + this + " from transient container "
+ + transientContainer + " to parent " + newParent);
+ }
+ transientContainer.removeTransientView(this);
+ setTransientContainer(null);
+ }
+
public void setTransientContainer(ViewGroup transientContainer) {
mTransientContainer = transientContainer;
}
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 3a37fb4..9d599cb 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
@@ -41,11 +41,8 @@
import android.widget.FrameLayout.LayoutParams;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -304,12 +301,9 @@
} else {
mMenuContainer = new FrameLayout(mContext);
}
- // The setting can win (which is needed for tests) but if not set, then use the flag
final int showDismissSetting = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.SHOW_NEW_NOTIF_DISMISS, -1);
- final boolean newFlowHideShelf = showDismissSetting == -1
- ? Dependency.get(FeatureFlags.class).isEnabled(Flags.NOTIFICATION_UPDATES)
- : showDismissSetting == 1;
+ Settings.Global.SHOW_NEW_NOTIF_DISMISS, /* default = */ 1);
+ final boolean newFlowHideShelf = showDismissSetting == 1;
if (newFlowHideShelf) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 046a133..a3fe47c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -44,6 +44,7 @@
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.HybridGroupManager;
import com.android.systemui.statusbar.notification.row.HybridNotificationView;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
@@ -272,6 +273,7 @@
* @param childIndex the index to add it at, if -1 it will be added at the end
*/
public void addNotification(ExpandableNotificationRow row, int childIndex) {
+ ensureRemovedFromTransientContainer(row);
int newIndex = childIndex < 0 ? mAttachedChildren.size() : childIndex;
mAttachedChildren.add(newIndex, row);
addView(row);
@@ -291,6 +293,16 @@
}
}
+ private void ensureRemovedFromTransientContainer(View v) {
+ if (v.getParent() != null && v instanceof ExpandableView) {
+ // If the child is animating away, it will still have a parent, so detach it first
+ // TODO: We should really cancel the active animations here. This will
+ // happen automatically when the view's intro animation starts, but
+ // it's a fragile link.
+ ((ExpandableView) v).removeFromTransientContainerForAdditionTo(this);
+ }
+ }
+
public void removeNotification(ExpandableNotificationRow row) {
int childIndex = mAttachedChildren.indexOf(row);
mAttachedChildren.remove(row);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
index 1cb5e62..464fd06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
@@ -21,8 +21,6 @@
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -41,7 +39,6 @@
private final ExpandableView[] mLastInSectionViews;
private final ExpandableView[] mTmpFirstInSectionViews;
private final ExpandableView[] mTmpLastInSectionViews;
- private final FeatureFlags mFeatureFlags;
private boolean mExpanded;
private HashSet<ExpandableView> mAnimatedChildren;
private Runnable mRoundingChangedCallback;
@@ -56,9 +53,7 @@
@Inject
NotificationRoundnessManager(
- NotificationSectionsFeatureManager sectionsFeatureManager,
- FeatureFlags featureFlags) {
- mFeatureFlags = featureFlags;
+ NotificationSectionsFeatureManager sectionsFeatureManager) {
int numberOfSections = sectionsFeatureManager.getNumberOfBuckets();
mFirstInSectionViews = new ExpandableView[numberOfSections];
mLastInSectionViews = new ExpandableView[numberOfSections];
@@ -125,9 +120,6 @@
ExpandableView viewBefore,
ExpandableView viewSwiped,
ExpandableView viewAfter) {
- if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_UPDATES)) {
- return;
- }
final boolean animate = true;
ExpandableView oldViewBefore = mViewBeforeSwipedView;
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 79b05c9..3e9ce25 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
@@ -43,7 +43,6 @@
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Bundle;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.AttributeSet;
@@ -80,6 +79,8 @@
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.EmptyShadeView;
@@ -132,14 +133,6 @@
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "StackScroller";
- // Usage:
- // adb shell setprop persist.debug.nssl true && adb reboot
- private static final boolean DEBUG = SystemProperties.getBoolean("persist.debug.nssl",
- false /* default */);
- // TODO(b/187291379) disable again before release
- private static final boolean DEBUG_REMOVE_ANIMATION = SystemProperties.getBoolean(
- "persist.debug.nssl.dismiss", false /* default */);
-
// Delay in milli-seconds before shade closes for clear all.
private final int DELAY_BEFORE_SHADE_CLOSE = 200;
private boolean mShadeNeedsToClose = false;
@@ -192,7 +185,12 @@
private float mInitialTouchX;
private float mInitialTouchY;
+ private final boolean mDebugLines;
private Paint mDebugPaint;
+ /** Used to track the Y positions that were already used to draw debug text labels. */
+ private Set<Integer> mDebugTextUsedYPositions;
+ private final boolean mDebugRemoveAnimation;
+
private int mContentHeight;
private int mIntrinsicContentHeight;
private int mCollapsedSize;
@@ -569,6 +567,9 @@
public NotificationStackScrollLayout(Context context, AttributeSet attrs) {
super(context, attrs, 0, 0);
Resources res = getResources();
+ FeatureFlags featureFlags = Dependency.get(FeatureFlags.class);
+ mDebugLines = featureFlags.isEnabled(Flags.NSSL_DEBUG_LINES);
+ mDebugRemoveAnimation = featureFlags.isEnabled(Flags.NSSL_DEBUG_REMOVE_ANIMATION);
mSectionsManager = Dependency.get(NotificationSectionsManager.class);
mScreenOffAnimationController =
Dependency.get(ScreenOffAnimationController.class);
@@ -591,10 +592,10 @@
res.getBoolean(R.bool.config_drawNotificationBackground);
setOutlineProvider(mOutlineProvider);
- boolean willDraw = mShouldDrawNotificationBackground || DEBUG;
+ boolean willDraw = mShouldDrawNotificationBackground || mDebugLines;
setWillNotDraw(!willDraw);
mBackgroundPaint.setAntiAlias(true);
- if (DEBUG) {
+ if (mDebugLines) {
mDebugPaint = new Paint();
mDebugPaint.setColor(0xffff0000);
mDebugPaint.setStrokeWidth(2);
@@ -729,18 +730,17 @@
drawHeadsUpBackground(canvas);
}
- if (DEBUG) {
+ if (mDebugLines) {
onDrawDebug(canvas);
}
}
- /** Used to track the Y positions that were already used to draw debug text labels. */
- private static final Set<Integer> DEBUG_TEXT_USED_Y_POSITIONS =
- DEBUG ? new HashSet<>() : Collections.emptySet();
-
private void onDrawDebug(Canvas canvas) {
- DEBUG_TEXT_USED_Y_POSITIONS.clear();
-
+ if (mDebugTextUsedYPositions == null) {
+ mDebugTextUsedYPositions = new HashSet<>();
+ } else {
+ mDebugTextUsedYPositions.clear();
+ }
int y = mTopPadding;
drawDebugInfo(canvas, y, Color.RED, /* label= */ "mTopPadding");
@@ -776,10 +776,10 @@
private int computeDebugYTextPosition(int lineY) {
int textY = lineY;
- while (DEBUG_TEXT_USED_Y_POSITIONS.contains(textY)) {
+ while (mDebugTextUsedYPositions.contains(textY)) {
textY = (int) (textY + mDebugPaint.getTextSize());
}
- DEBUG_TEXT_USED_Y_POSITIONS.add(textY);
+ mDebugTextUsedYPositions.add(textY);
return textY;
}
@@ -2702,14 +2702,14 @@
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
boolean generateRemoveAnimation(ExpandableView child) {
String key = "";
- if (DEBUG_REMOVE_ANIMATION) {
+ if (mDebugRemoveAnimation) {
if (child instanceof ExpandableNotificationRow) {
key = ((ExpandableNotificationRow) child).getEntry().getKey();
}
Log.d(TAG, "generateRemoveAnimation " + key);
}
if (removeRemovedChildFromHeadsUpChangeAnimations(child)) {
- if (DEBUG_REMOVE_ANIMATION) {
+ if (mDebugRemoveAnimation) {
Log.d(TAG, "removedBecauseOfHeadsUp " + key);
}
mAddedHeadsUpChildren.remove(child);
@@ -2720,7 +2720,7 @@
mClearTransientViewsWhenFinished.add(child);
return true;
}
- if (DEBUG_REMOVE_ANIMATION) {
+ if (mDebugRemoveAnimation) {
Log.d(TAG, "generateRemove " + key
+ "\nmIsExpanded " + mIsExpanded
+ "\nmAnimationsEnabled " + mAnimationsEnabled
@@ -2728,7 +2728,7 @@
}
if (mIsExpanded && mAnimationsEnabled && !isChildInInvisibleGroup(child)) {
if (!mChildrenToAddAnimated.contains(child)) {
- if (DEBUG_REMOVE_ANIMATION) {
+ if (mDebugRemoveAnimation) {
Log.d(TAG, "needsAnimation = true " + key);
}
// Generate Animations
@@ -3227,7 +3227,7 @@
ignoreChildren);
mAnimationEvents.add(event);
mSwipedOutViews.remove(child);
- if (DEBUG_REMOVE_ANIMATION) {
+ if (mDebugRemoveAnimation) {
String key = "";
if (child instanceof ExpandableNotificationRow) {
key = ((ExpandableNotificationRow) child).getEntry().getKey();
@@ -4655,18 +4655,12 @@
}
private void ensureRemovedFromTransientContainer(View v) {
- if (v.getParent() == this && v instanceof ExpandableView) {
- ExpandableView expandableView = (ExpandableView) v;
- ViewGroup transientContainer = expandableView.getTransientContainer();
- // If the child is animating away, it will still have a parent, so
- // detach it first
+ if (v.getParent() != null && v instanceof ExpandableView) {
+ // If the child is animating away, it will still have a parent, so detach it first
// TODO: We should really cancel the active animations here. This will
// happen automatically when the view's intro animation starts, but
// it's a fragile link.
- if (transientContainer != null) {
- transientContainer.removeTransientView(v);
- expandableView.setTransientContainer(null);
- }
+ ((ExpandableView) v).removeFromTransientContainerForAdditionTo(this);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index ad1c232..98b5dcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -645,7 +645,7 @@
if (biometricSourceType.equals(BiometricSourceType.FINGERPRINT)
&& mUpdateMonitor.isUdfpsSupported()
&& mNumConsecutiveFpFailures >= FP_ATTEMPTS_BEFORE_SHOW_BOUNCER) {
- mKeyguardViewController.showBouncer(true);
+ startWakeAndUnlock(MODE_SHOW_BOUNCER);
UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN);
mNumConsecutiveFpFailures = 0;
}
@@ -668,7 +668,8 @@
&& mUpdateMonitor.isUdfpsSupported()
&& (mStatusBarStateController.getState() == StatusBarState.SHADE
|| mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED)) {
- mKeyguardViewController.showBouncer(true);
+ startWakeAndUnlock(MODE_SHOW_BOUNCER);
+ UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN);
}
cleanup();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index d87a024..1b42b58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.PowerManager;
@@ -26,7 +27,10 @@
import android.util.MathUtils;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
@@ -36,13 +40,18 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.tuner.TunerService;
+import com.android.systemui.unfold.FoldAodAnimationController;
+import com.android.systemui.unfold.SysUIUnfoldComponent;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashSet;
+import java.util.Optional;
import java.util.Set;
import javax.inject.Inject;
@@ -54,7 +63,8 @@
public class DozeParameters implements
TunerService.Tunable,
com.android.systemui.plugins.statusbar.DozeParameters,
- Dumpable {
+ Dumpable, ConfigurationController.ConfigurationListener,
+ StatusBarStateController.StateListener, FoldAodAnimationController.FoldAodAnimationStatus {
private static final int MAX_DURATION = 60 * 1000;
public static final boolean FORCE_NO_BLANKING =
SystemProperties.getBoolean("debug.force_no_blanking", false);
@@ -69,12 +79,30 @@
private final BatteryController mBatteryController;
private final FeatureFlags mFeatureFlags;
private final ScreenOffAnimationController mScreenOffAnimationController;
+ private final FoldAodAnimationController mFoldAodAnimationController;
+ private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
private final Set<Callback> mCallbacks = new HashSet<>();
private boolean mDozeAlwaysOn;
private boolean mControlScreenOffAnimation;
+ private boolean mKeyguardShowing;
+ @VisibleForTesting
+ final KeyguardUpdateMonitorCallback mKeyguardVisibilityCallback =
+ new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ mKeyguardShowing = showing;
+ updateControlScreenOff();
+ }
+
+ @Override
+ public void onShadeExpandedChanged(boolean expanded) {
+ updateControlScreenOff();
+ }
+ };
+
@Inject
protected DozeParameters(
@Main Resources resources,
@@ -85,7 +113,12 @@
TunerService tunerService,
DumpManager dumpManager,
FeatureFlags featureFlags,
- ScreenOffAnimationController screenOffAnimationController) {
+ ScreenOffAnimationController screenOffAnimationController,
+ Optional<SysUIUnfoldComponent> sysUiUnfoldComponent,
+ UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ ConfigurationController configurationController,
+ StatusBarStateController statusBarStateController) {
mResources = resources;
mAmbientDisplayConfiguration = ambientDisplayConfiguration;
mAlwaysOnPolicy = alwaysOnDisplayPolicy;
@@ -97,11 +130,22 @@
mPowerManager.setDozeAfterScreenOff(!mControlScreenOffAnimation);
mFeatureFlags = featureFlags;
mScreenOffAnimationController = screenOffAnimationController;
+ mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
+ keyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback);
tunerService.addTunable(
this,
Settings.Secure.DOZE_ALWAYS_ON,
Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+ configurationController.addCallback(this);
+ statusBarStateController.addCallback(this);
+
+ mFoldAodAnimationController = sysUiUnfoldComponent
+ .map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null);
+
+ if (mFoldAodAnimationController != null) {
+ mFoldAodAnimationController.addCallback(this);
+ }
}
public boolean getDisplayStateSupported() {
@@ -222,13 +266,26 @@
mPowerManager.setDozeAfterScreenOff(!controlScreenOffAnimation);
}
+ public void updateControlScreenOff() {
+ if (!getDisplayNeedsBlanking()) {
+ final boolean controlScreenOff =
+ getAlwaysOn() && (mKeyguardShowing || shouldControlUnlockedScreenOff());
+ setControlScreenOffAnimation(controlScreenOff);
+ }
+ }
+
/**
* Whether we want to control the screen off animation when the device is unlocked. If we do,
* we'll animate in AOD before turning off the screen, rather than simply fading to black and
* then abruptly showing AOD.
+ *
+ * There are currently several reasons we might not want to control the screen off even if we
+ * are able to, such as the shade being expanded, being in landscape, or having animations
+ * disabled for a11y.
*/
public boolean shouldControlUnlockedScreenOff() {
- return mScreenOffAnimationController.shouldControlUnlockedScreenOff();
+ return canControlUnlockedScreenOff()
+ && mUnlockedScreenOffAnimationController.shouldPlayUnlockedScreenOffAnimation();
}
public boolean shouldDelayKeyguardShow() {
@@ -325,6 +382,11 @@
@Override
public void onTuningChanged(String key, String newValue) {
mDozeAlwaysOn = mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT);
+
+ if (key.equals(Settings.Secure.DOZE_ALWAYS_ON)) {
+ updateControlScreenOff();
+ }
+
for (Callback callback : mCallbacks) {
callback.onAlwaysOnChange();
}
@@ -332,6 +394,21 @@
}
@Override
+ public void onConfigChanged(Configuration newConfig) {
+ updateControlScreenOff();
+ }
+
+ @Override
+ public void onStatePostChange() {
+ updateControlScreenOff();
+ }
+
+ @Override
+ public void onFoldToAodAnimationChanged() {
+ updateControlScreenOff();
+ }
+
+ @Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.print("getAlwaysOn(): "); pw.println(getAlwaysOn());
pw.print("getDisplayStateSupported(): "); pw.println(getDisplayStateSupported());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index 57b9c03..a88a3b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -63,7 +63,6 @@
private final DozeLog mDozeLog;
private final PowerManager mPowerManager;
private boolean mAnimateWakeup;
- private boolean mAnimateScreenOff;
private boolean mIgnoreTouchWhilePulsing;
private Runnable mPendingScreenOffCallback;
@VisibleForTesting
@@ -357,11 +356,6 @@
}
@Override
- public void setAnimateScreenOff(boolean animateScreenOff) {
- mAnimateScreenOff = animateScreenOff;
- }
-
- @Override
public void onSlpiTap(float screenX, float screenY) {
if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null
&& mAmbientIndicationContainer.getVisibility() == View.VISIBLE) {
@@ -440,10 +434,6 @@
return mAnimateWakeup;
}
- boolean shouldAnimateScreenOff() {
- return mAnimateScreenOff;
- }
-
boolean getIgnoreTouchWhilePulsing() {
return mIgnoreTouchWhilePulsing;
}
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 7ca8652..732e5f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -57,8 +57,7 @@
private int mUserSwitchPreferredY;
/**
- * Minimum top margin to avoid overlap with status bar, lock icon, or multi-user switcher
- * avatar.
+ * Minimum top margin to avoid overlap with status bar or multi-user switcher avatar.
*/
private int mMinTopMargin;
@@ -203,7 +202,7 @@
if (mBypassEnabled) {
return mUnlockedStackScrollerPadding;
} else if (mIsSplitShade) {
- return getClockY(1.0f, mDarkAmount);
+ return getClockY(1.0f, mDarkAmount) + mUserSwitchHeight;
} else {
return getClockY(1.0f, mDarkAmount) + mKeyguardStatusHeight;
}
@@ -213,7 +212,7 @@
if (mBypassEnabled) {
return (int) (mUnlockedStackScrollerPadding + mOverStretchAmount);
} else if (mIsSplitShade) {
- return Math.max(0, clockYPosition - mSplitShadeTopNotificationsMargin);
+ return clockYPosition - mSplitShadeTopNotificationsMargin + mUserSwitchHeight;
} else {
return clockYPosition + mKeyguardStatusHeight;
}
@@ -223,7 +222,7 @@
if (mBypassEnabled) {
return mUnlockedStackScrollerPadding;
} else if (mIsSplitShade) {
- return Math.max(mSplitShadeTargetTopMargin, mMinTopMargin);
+ return mSplitShadeTargetTopMargin + mUserSwitchHeight;
} else {
return mMinTopMargin + mKeyguardStatusHeight;
}
@@ -231,7 +230,7 @@
private int getExpandedPreferredClockY() {
if (mIsSplitShade) {
- return Math.max(mSplitShadeTargetTopMargin, mMinTopMargin);
+ return mSplitShadeTargetTopMargin;
} else {
return mMinTopMargin;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 434671c..9ca904b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -1440,8 +1440,11 @@
mKeyguardStatusViewController.displayClock(LARGE, shouldAnimateClockChange);
}
updateKeyguardStatusViewAlignment(true /* animate */);
- int userIconHeight = mKeyguardQsUserSwitchController != null
+ int userSwitcherHeight = mKeyguardQsUserSwitchController != null
? mKeyguardQsUserSwitchController.getUserIconHeight() : 0;
+ if (mKeyguardUserSwitcherController != null) {
+ userSwitcherHeight = mKeyguardUserSwitcherController.getHeight();
+ }
float expandedFraction =
mScreenOffAnimationController.shouldExpandNotifications()
? 1.0f : getExpandedFraction();
@@ -1461,7 +1464,7 @@
mStatusBarHeaderHeightKeyguard,
expandedFraction,
mKeyguardStatusViewController.getLockscreenHeight(),
- userIconHeight,
+ userSwitcherHeight,
userSwitcherPreferredY,
darkamount, mOverStretchAmount,
bypassEnabled, getUnlockedStackScrollerPadding(),
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 07914cf..2ba70df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3162,7 +3162,7 @@
boolean wakeAndUnlock = mBiometricUnlockController.getMode()
== BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup() && !wakeAndUnlock)
- || (mDozing && mDozeServiceHost.shouldAnimateScreenOff()
+ || (mDozing && mDozeParameters.shouldControlScreenOff()
&& visibleNotOccludedOrWillBe);
mNotificationPanelViewController.setDozing(mDozing, animate, mWakeUpTouchLocation);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index fc661b9..0ba7134 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -9,6 +9,9 @@
import android.provider.Settings
import android.view.Surface
import android.view.View
+import com.android.internal.jank.InteractionJankMonitor
+import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF
+import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.KeyguardViewMediator
@@ -50,7 +53,8 @@
private val keyguardViewMediatorLazy: dagger.Lazy<KeyguardViewMediator>,
private val keyguardStateController: KeyguardStateController,
private val dozeParameters: dagger.Lazy<DozeParameters>,
- private val globalSettings: GlobalSettings
+ private val globalSettings: GlobalSettings,
+ private val interactionJankMonitor: InteractionJankMonitor
) : WakefulnessLifecycle.Observer, ScreenOffAnimation {
private val handler = Handler()
@@ -78,17 +82,28 @@
sendUnlockedScreenOffProgressUpdate(
1f - (it.animatedFraction as Float),
1f - (it.animatedValue as Float))
+ if (lightRevealScrim.isScrimAlmostOccludes &&
+ interactionJankMonitor.isInstrumenting(CUJ_SCREEN_OFF)) {
+ // ends the instrument when the scrim almost occludes the screen.
+ // because the following janky frames might not be perceptible.
+ interactionJankMonitor.end(CUJ_SCREEN_OFF)
+ }
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationCancel(animation: Animator?) {
lightRevealScrim.revealAmount = 1f
lightRevealAnimationPlaying = false
sendUnlockedScreenOffProgressUpdate(0f, 0f)
+ interactionJankMonitor.cancel(CUJ_SCREEN_OFF)
}
override fun onAnimationEnd(animation: Animator?) {
lightRevealAnimationPlaying = false
}
+
+ override fun onAnimationStart(animation: Animator?) {
+ interactionJankMonitor.begin(statusBar.notificationShadeWindowView, CUJ_SCREEN_OFF)
+ }
})
}
@@ -163,6 +178,16 @@
decidedToAnimateGoingToSleep = null
// We need to unset the listener. These are persistent for future animators
keyguardView.animate().setListener(null)
+ interactionJankMonitor.end(CUJ_SCREEN_OFF_SHOW_AOD)
+ }
+
+ override fun onAnimationCancel(animation: Animator?) {
+ interactionJankMonitor.cancel(CUJ_SCREEN_OFF_SHOW_AOD)
+ }
+
+ override fun onAnimationStart(animation: Animator?) {
+ interactionJankMonitor.begin(
+ statusBar.notificationShadeWindowView, CUJ_SCREEN_OFF_SHOW_AOD)
}
})
.start()
@@ -229,10 +254,6 @@
return false
}
- if (!dozeParameters.get().canControlUnlockedScreenOff()) {
- return false
- }
-
// If animations are disabled system-wide, don't play this one either.
if (Settings.Global.getString(
context.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE) == "0") {
@@ -248,10 +269,10 @@
// already expanded and showing notifications/QS, the animation looks really messy. For now,
// disable it if the notification panel is not fully collapsed.
if ((!this::statusBar.isInitialized ||
- !statusBar.notificationPanelViewController.isFullyCollapsed)
+ !statusBar.notificationPanelViewController.isFullyCollapsed) &&
// Status bar might be expanded because we have started
// playing the animation already
- && !isAnimationPlaying()
+ !isAnimationPlaying()
) {
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index ffa7963..04a6a11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -248,6 +248,10 @@
return mUserSwitcherController.isSimpleUserSwitcher();
}
+ public int getHeight() {
+ return mListView.getHeight();
+ }
+
/**
* @param animate if the transition should be animated
* @return true if the switcher state changed
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
index cd8894c..850a4b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
@@ -97,9 +97,12 @@
} else {
// Update clickable state immediately so that the menu feels more responsive
userItemViews[i].setClickable(open);
- // Before running the animation, ensure visibility is set correctly
- userItemViews[i].updateVisibilities(animate || open /* showItem */,
- true /* showTextName */, false /* animate */);
+ // when opening we need to make views visible beforehand so they can be animated
+ if (open) {
+ userItemViews[i].updateVisibilities(true /* showItem */,
+ true /* showTextName */, false /* animate */);
+ }
+
}
}
@@ -117,6 +120,13 @@
setClipChildren(true);
setClipToPadding(true);
mAnimating = false;
+ if (!open) {
+ // after closing we hide children so that height of this view is correct
+ for (int i = 1; i < userItemViews.length; i++) {
+ userItemViews[i].updateVisibilities(false /* showItem */,
+ true /* showTextName */, false /* animate */);
+ }
+ }
});
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 8e8a33f..3831857 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.policy;
+import static android.app.AppOpsManager.OP_COARSE_LOCATION;
+import static android.app.AppOpsManager.OP_FINE_LOCATION;
import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
import static com.android.settingslib.Utils.updateLocationEnabled;
@@ -30,11 +32,13 @@
import android.os.Message;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.systemui.BootCompleteCache;
import com.android.systemui.appops.AppOpItem;
import com.android.systemui.appops.AppOpsController;
@@ -43,6 +47,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.Utils;
import java.util.ArrayList;
@@ -59,30 +64,47 @@
private final Context mContext;
private final AppOpsController mAppOpsController;
+ private final DeviceConfigProxy mDeviceConfigProxy;
private final BootCompleteCache mBootCompleteCache;
private final UserTracker mUserTracker;
private final H mHandler;
private boolean mAreActiveLocationRequests;
+ private boolean mShouldDisplayAllAccesses;
@Inject
public LocationControllerImpl(Context context, AppOpsController appOpsController,
+ DeviceConfigProxy deviceConfigProxy,
@Main Looper mainLooper, @Background Handler backgroundHandler,
BroadcastDispatcher broadcastDispatcher, BootCompleteCache bootCompleteCache,
UserTracker userTracker) {
mContext = context;
mAppOpsController = appOpsController;
+ mDeviceConfigProxy = deviceConfigProxy;
mBootCompleteCache = bootCompleteCache;
mHandler = new H(mainLooper);
mUserTracker = userTracker;
+ mShouldDisplayAllAccesses = getDeviceConfigSetting();
+
+ // Register to listen for changes in DeviceConfig settings.
+ mDeviceConfigProxy.addOnPropertiesChangedListener(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ backgroundHandler::post,
+ properties -> {
+ mShouldDisplayAllAccesses = getDeviceConfigSetting();
+ updateActiveLocationRequests();
+ });
// Register to listen for changes in location settings.
IntentFilter filter = new IntentFilter();
filter.addAction(LocationManager.MODE_CHANGED_ACTION);
broadcastDispatcher.registerReceiverWithHandler(this, filter, mHandler, UserHandle.ALL);
- mAppOpsController.addCallback(new int[]{OP_MONITOR_HIGH_POWER_LOCATION}, this);
+ // Listen to all accesses and filter the ones interested in based on flags.
+ mAppOpsController.addCallback(
+ new int[]{OP_COARSE_LOCATION, OP_FINE_LOCATION, OP_MONITOR_HIGH_POWER_LOCATION},
+ this);
// Examine the current location state and initialize the status view.
backgroundHandler.post(this::updateActiveLocationRequests);
@@ -154,6 +176,11 @@
UserHandle.of(userId));
}
+ private boolean getDeviceConfigSetting() {
+ return mDeviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED, false);
+ }
+
/**
* Returns true if there currently exist active high power location requests.
*/
@@ -171,10 +198,37 @@
return false;
}
- // Reads the active location requests and updates the status view if necessary.
+ /**
+ * Returns true if there currently exist active location requests.
+ */
+ @VisibleForTesting
+ protected boolean areActiveLocationRequests() {
+ if (!mShouldDisplayAllAccesses) {
+ return false;
+ }
+ List<AppOpItem> appOpsItems = mAppOpsController.getActiveAppOps();
+
+ final int numItems = appOpsItems.size();
+ for (int i = 0; i < numItems; i++) {
+ if (appOpsItems.get(i).getCode() == OP_FINE_LOCATION
+ || appOpsItems.get(i).getCode() == OP_COARSE_LOCATION) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // Reads the active location requests from either OP_MONITOR_HIGH_POWER_LOCATION,
+ // OP_FINE_LOCATION, or OP_COARSE_LOCATION and updates the status view if necessary.
private void updateActiveLocationRequests() {
boolean hadActiveLocationRequests = mAreActiveLocationRequests;
- mAreActiveLocationRequests = areActiveHighPowerLocationRequests();
+ if (mShouldDisplayAllAccesses) {
+ mAreActiveLocationRequests =
+ areActiveHighPowerLocationRequests() || areActiveLocationRequests();
+ } else {
+ mAreActiveLocationRequests = areActiveHighPowerLocationRequests();
+ }
if (mAreActiveLocationRequests != hadActiveLocationRequests) {
mHandler.sendEmptyMessage(H.MSG_LOCATION_ACTIVE_CHANGED);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
index f258fb1..1158324 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
@@ -23,6 +23,7 @@
int getRotationLockOrientation();
boolean isRotationLockAffordanceVisible();
boolean isRotationLocked();
+ boolean isCameraRotationEnabled();
void setRotationLocked(boolean locked);
void setRotationLockedAtAngle(boolean locked, int rotation);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
index 67f5364..3143a47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -18,6 +18,9 @@
import static com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule.DEVICE_STATE_ROTATION_LOCK_DEFAULTS;
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.UserHandle;
import androidx.annotation.NonNull;
@@ -34,6 +37,7 @@
/** Platform implementation of the rotation lock controller. **/
@SysUISingleton
public final class RotationLockControllerImpl implements RotationLockController {
+
private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks =
new CopyOnWriteArrayList<>();
@@ -86,11 +90,15 @@
return mRotationPolicy.isRotationLocked();
}
+ public boolean isCameraRotationEnabled() {
+ return mRotationPolicy.isCameraRotationEnabled();
+ }
+
public void setRotationLocked(boolean locked) {
mRotationPolicy.setRotationLock(locked);
}
- public void setRotationLockedAtAngle(boolean locked, int rotation){
+ public void setRotationLockedAtAngle(boolean locked, int rotation) {
mRotationPolicy.setRotationLockAtAngle(locked, rotation);
}
@@ -121,4 +129,11 @@
callback.onRotationLockStateChanged(mRotationPolicy.isRotationLocked(),
mRotationPolicy.isRotationLockToggleVisible());
}
+
+ public static boolean hasSufficientPermission(Context context) {
+ final PackageManager packageManager = context.getPackageManager();
+ final String rotationPackage = packageManager.getRotationResolverPackageName();
+ return rotationPackage != null && packageManager.checkPermission(
+ Manifest.permission.CAMERA, rotationPackage) == PackageManager.PERMISSION_GRANTED;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
index 97fce51..05e5666 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
@@ -33,6 +33,7 @@
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.UserHandle;
+import android.util.IconDrawableFactory;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -40,10 +41,6 @@
import android.widget.TextView;
import com.android.internal.R;
-import com.android.launcher3.icons.BaseIconFactory.IconOptions;
-import com.android.launcher3.icons.IconFactory;
-import com.android.settingslib.applications.ApplicationsState;
-import com.android.settingslib.applications.ApplicationsState.AppEntry;
import com.android.systemui.plugins.ToastPlugin;
/**
@@ -199,7 +196,9 @@
iconView.setVisibility(View.GONE);
} else {
iconView.setImageDrawable(icon);
- if (appInfo.labelRes != 0) {
+ if (appInfo == null) {
+ Log.d(TAG, "No appInfo for pkg=" + mPackageName + " usr=" + mUserId);
+ } else if (appInfo.labelRes != 0) {
try {
Resources res = mContext.getPackageManager().getResourcesForApplication(
appInfo,
@@ -252,48 +251,29 @@
return null;
}
- final Context userContext;
try {
- userContext = context.createPackageContextAsUser("android",
- 0, new UserHandle(userId));
+ final PackageManager packageManager = context.getPackageManager();
+ final ApplicationInfo appInfo = packageManager.getApplicationInfoAsUser(
+ packageName,
+ PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA),
+ userId);
+ if (appInfo == null || !showApplicationIcon(appInfo, packageManager)) {
+ return null;
+ }
+
+ IconDrawableFactory iconFactory = IconDrawableFactory.newInstance(context);
+ return iconFactory.getBadgedIcon(appInfo, UserHandle.getUserId(appInfo.uid));
} catch (NameNotFoundException e) {
- Log.e(TAG, "Could not create user package context");
+ Log.e(TAG, "Couldn't find application info for packageName=" + packageName
+ + " userId=" + userId);
return null;
}
-
- final ApplicationsState appState =
- ApplicationsState.getInstance((Application) context.getApplicationContext());
- if (!appState.isUserAdded(userId)) {
- Log.d(TAG, "user hasn't been fully initialized, not showing an app icon for "
- + "packageName=" + packageName);
- return null;
- }
-
- final PackageManager packageManager = userContext.getPackageManager();
- final AppEntry appEntry = appState.getEntry(packageName, userId);
- if (appEntry == null || appEntry.info == null
- || !showApplicationIcon(appEntry.info, packageManager)) {
- return null;
- }
-
- final ApplicationInfo appInfo = appEntry.info;
- UserHandle user = UserHandle.getUserHandleForUid(appInfo.uid);
- IconFactory iconFactory = IconFactory.obtain(context);
- try {
- return iconFactory.createBadgedIconBitmap(
- appInfo.loadUnbadgedIcon(packageManager),
- new IconOptions().setUser(user))
- .newIcon(context);
- } finally {
- iconFactory.recycle();
- }
}
private static boolean showApplicationIcon(ApplicationInfo appInfo,
PackageManager packageManager) {
if (hasFlag(appInfo.flags, FLAG_UPDATED_SYSTEM_APP)) {
- return packageManager.getLaunchIntentForPackage(appInfo.packageName)
- != null;
+ return packageManager.getLaunchIntentForPackage(appInfo.packageName) != null;
}
return !hasFlag(appInfo.flags, FLAG_SYSTEM);
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt b/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
index 2a0cc7d..b64d7be 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
@@ -17,8 +17,10 @@
package com.android.systemui.util.wrapper
import android.content.Context
+import android.provider.Settings.Secure.CAMERA_AUTOROTATE
import com.android.internal.view.RotationPolicy
import com.android.internal.view.RotationPolicy.RotationPolicyListener
+import com.android.systemui.util.settings.SecureSettings
import javax.inject.Inject
/**
@@ -30,12 +32,16 @@
fun getRotationLockOrientation(): Int
fun isRotationLockToggleVisible(): Boolean
fun isRotationLocked(): Boolean
+ fun isCameraRotationEnabled(): Boolean
fun registerRotationPolicyListener(listener: RotationPolicyListener, userHandle: Int)
fun unregisterRotationPolicyListener(listener: RotationPolicyListener)
}
-class RotationPolicyWrapperImpl @Inject constructor(private val context: Context) :
- RotationPolicyWrapper {
+class RotationPolicyWrapperImpl @Inject constructor(
+ private val context: Context,
+ private val secureSettings: SecureSettings
+) :
+ RotationPolicyWrapper {
override fun setRotationLock(enabled: Boolean) {
RotationPolicy.setRotationLock(context, enabled)
@@ -54,6 +60,9 @@
override fun isRotationLocked(): Boolean =
RotationPolicy.isRotationLocked(context)
+ override fun isCameraRotationEnabled(): Boolean =
+ secureSettings.getInt(CAMERA_AUTOROTATE, 0) == 1
+
override fun registerRotationPolicyListener(
listener: RotationPolicyListener,
userHandle: Int
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 4600bc7..31b17f8 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -258,11 +258,6 @@
public void onKeyguardVisibilityChanged(boolean showing) {
splitScreen.onKeyguardVisibilityChanged(showing);
}
-
- @Override
- public void onKeyguardOccludedChanged(boolean occluded) {
- splitScreen.onKeyguardOccludedChanged(occluded);
- }
};
mKeyguardUpdateMonitor.registerCallback(mSplitScreenKeyguardCallback);
@@ -271,11 +266,6 @@
public void onFinishedWakingUp() {
splitScreen.onFinishedWakingUp();
}
-
- @Override
- public void onFinishedGoingToSleep() {
- splitScreen.onFinishedGoingToSleep();
- }
});
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
new file mode 100644
index 0000000..57f3617
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics
+
+import android.hardware.biometrics.ComponentInfoInternal
+import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.biometrics.SensorProperties
+import android.hardware.fingerprint.FingerprintSensorProperties
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
+
+/** Creates properties from the sensor location with test values. */
+fun SensorLocationInternal.asFingerprintSensorProperties(
+ sensorId: Int = 22,
+ @SensorProperties.Strength sensorStrength: Int = SensorProperties.STRENGTH_WEAK,
+ @FingerprintSensorProperties.SensorType sensorType: Int =
+ FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
+ maxEnrollmentsPerUser: Int = 1,
+ info: List<ComponentInfoInternal> = listOf(ComponentInfoInternal("a", "b", "c", "d", "e")),
+ resetLockoutRequiresHardwareAuthToken: Boolean = false
+) = FingerprintSensorPropertiesInternal(
+ sensorId,
+ sensorStrength,
+ maxEnrollmentsPerUser,
+ info,
+ sensorType,
+ resetLockoutRequiresHardwareAuthToken,
+ listOf(this)
+)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
new file mode 100644
index 0000000..84eb935
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics
+
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
+import android.hardware.biometrics.BiometricOverlayConstants.ShowReason
+import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.fingerprint.FingerprintManager
+import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.LayoutInflater
+import android.view.MotionEvent
+import android.view.View
+import android.view.WindowManager
+import android.view.accessibility.AccessibilityManager
+import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.LockscreenShadeTransitionController
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.time.SystemClock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+class UdfpsControllerOverlayTest : SysuiTestCase() {
+
+ @JvmField @Rule
+ var rule = MockitoJUnit.rule()
+
+ @Mock private lateinit var fingerprintManager: FingerprintManager
+ @Mock private lateinit var inflater: LayoutInflater
+ @Mock private lateinit var windowManager: WindowManager
+ @Mock private lateinit var accessibilityManager: AccessibilityManager
+ @Mock private lateinit var statusBarStateController: StatusBarStateController
+ @Mock private lateinit var panelExpansionStateManager: PanelExpansionStateManager
+ @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var dialogManager: SystemUIDialogManager
+ @Mock private lateinit var dumpManager: DumpManager
+ @Mock private lateinit var transitionController: LockscreenShadeTransitionController
+ @Mock private lateinit var configurationController: ConfigurationController
+ @Mock private lateinit var systemClock: SystemClock
+ @Mock private lateinit var keyguardStateController: KeyguardStateController
+ @Mock
+ private lateinit var unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController
+ @Mock private lateinit var hbmProvider: UdfpsHbmProvider
+ @Mock private lateinit var controllerCallback: IUdfpsOverlayControllerCallback
+ @Mock private lateinit var udfpsController: UdfpsController
+ @Mock private lateinit var udfpsView: UdfpsView
+ @Mock private lateinit var udfpsEnrollView: UdfpsEnrollView
+
+ private val sensorProps = SensorLocationInternal("", 10, 100, 20)
+ .asFingerprintSensorProperties()
+ private val onTouch = { _: View, _: MotionEvent, _: Boolean -> true }
+ private lateinit var controllerOverlay: UdfpsControllerOverlay
+
+ @Before
+ fun setup() {
+ context.orCreateTestableResources.addOverride(R.integer.config_udfpsEnrollProgressBar, 20)
+ whenever(inflater.inflate(R.layout.udfps_view, null, false))
+ .thenReturn(udfpsView)
+ whenever(inflater.inflate(R.layout.udfps_enroll_view, null))
+ .thenReturn(udfpsEnrollView)
+ whenever(inflater.inflate(R.layout.udfps_bp_view, null))
+ .thenReturn(mock(UdfpsBpView::class.java))
+ whenever(inflater.inflate(R.layout.udfps_keyguard_view, null))
+ .thenReturn(mock(UdfpsKeyguardView::class.java))
+ whenever(inflater.inflate(R.layout.udfps_fpm_other_view, null))
+ .thenReturn(mock(UdfpsFpmOtherView::class.java))
+ whenever(udfpsEnrollView.context).thenReturn(context)
+ }
+
+ private fun withReason(@ShowReason reason: Int, block: () -> Unit) {
+ controllerOverlay = UdfpsControllerOverlay(
+ context, fingerprintManager, inflater, windowManager, accessibilityManager,
+ statusBarStateController, panelExpansionStateManager, statusBarKeyguardViewManager,
+ keyguardUpdateMonitor, dialogManager, dumpManager, transitionController,
+ configurationController, systemClock, keyguardStateController,
+ unlockedScreenOffAnimationController, sensorProps, hbmProvider, reason,
+ controllerCallback, onTouch)
+ block()
+ }
+
+ @Test
+ fun showUdfpsOverlay_bp() = withReason(REASON_AUTH_BP) { showUdfpsOverlay() }
+
+ @Test
+ fun showUdfpsOverlay_keyguard() = withReason(REASON_AUTH_KEYGUARD) { showUdfpsOverlay() }
+
+ @Test
+ fun showUdfpsOverlay_settings() = withReason(REASON_AUTH_SETTINGS) { showUdfpsOverlay() }
+
+ @Test
+ fun showUdfpsOverlay_locate() = withReason(REASON_ENROLL_FIND_SENSOR) {
+ showUdfpsOverlay(isEnrollUseCase = true)
+ }
+
+ @Test
+ fun showUdfpsOverlay_enroll() = withReason(REASON_ENROLL_ENROLLING) {
+ showUdfpsOverlay(isEnrollUseCase = true)
+ }
+
+ @Test
+ fun showUdfpsOverlay_other() = withReason(REASON_AUTH_OTHER) { showUdfpsOverlay() }
+
+ private fun showUdfpsOverlay(isEnrollUseCase: Boolean = false) {
+ val didShow = controllerOverlay.show(udfpsController)
+
+ verify(windowManager).addView(eq(controllerOverlay.overlayView), any())
+ verify(udfpsView).setHbmProvider(eq(hbmProvider))
+ verify(udfpsView).sensorProperties = eq(sensorProps)
+ verify(udfpsView).animationViewController = any()
+ verify(udfpsView).addView(any())
+
+ assertThat(didShow).isTrue()
+ assertThat(controllerOverlay.isShowing).isTrue()
+ assertThat(controllerOverlay.isHiding).isFalse()
+ assertThat(controllerOverlay.overlayView).isNotNull()
+ if (isEnrollUseCase) {
+ verify(udfpsEnrollView).updateSensorLocation(eq(sensorProps))
+ assertThat(controllerOverlay.enrollHelper).isNotNull()
+ } else {
+ assertThat(controllerOverlay.enrollHelper).isNull()
+ }
+ }
+
+ @Test
+ fun hideUdfpsOverlay_bp() = withReason(REASON_AUTH_BP) { hideUdfpsOverlay() }
+
+ @Test
+ fun hideUdfpsOverlay_keyguard() = withReason(REASON_AUTH_KEYGUARD) { hideUdfpsOverlay() }
+
+ @Test
+ fun hideUdfpsOverlay_settings() = withReason(REASON_AUTH_SETTINGS) { hideUdfpsOverlay() }
+
+ @Test
+ fun hideUdfpsOverlay_locate() = withReason(REASON_ENROLL_FIND_SENSOR) { hideUdfpsOverlay() }
+
+ @Test
+ fun hideUdfpsOverlay_enroll() = withReason(REASON_ENROLL_ENROLLING) { hideUdfpsOverlay() }
+
+ @Test
+ fun hideUdfpsOverlay_other() = withReason(REASON_AUTH_OTHER) { hideUdfpsOverlay() }
+
+ private fun hideUdfpsOverlay() {
+ val didShow = controllerOverlay.show(udfpsController)
+ val view = controllerOverlay.overlayView
+ val didHide = controllerOverlay.hide()
+
+ verify(windowManager).removeView(eq(view))
+
+ assertThat(didShow).isTrue()
+ assertThat(didHide).isTrue()
+ assertThat(controllerOverlay.overlayView).isNull()
+ assertThat(controllerOverlay.animationViewController).isNull()
+ assertThat(controllerOverlay.isShowing).isFalse()
+ assertThat(controllerOverlay.isHiding).isTrue()
+ }
+
+ @Test
+ fun canNotHide() = withReason(REASON_AUTH_BP) {
+ assertThat(controllerOverlay.hide()).isFalse()
+ }
+
+ @Test
+ fun canNotReshow() = withReason(REASON_AUTH_BP) {
+ assertThat(controllerOverlay.show(udfpsController)).isTrue()
+ assertThat(controllerOverlay.show(udfpsController)).isFalse()
+ }
+
+ @Test
+ fun forwardEnrollProgressEvents() = withReason(REASON_ENROLL_ENROLLING) {
+ controllerOverlay.show(udfpsController)
+
+ with(EnrollListener(controllerOverlay)) {
+ controllerOverlay.onEnrollmentProgress(/* remaining */20)
+ controllerOverlay.onAcquiredGood()
+ assertThat(progress).isTrue()
+ assertThat(help).isFalse()
+ assertThat(acquired).isFalse()
+ }
+ }
+
+ @Test
+ fun forwardEnrollHelpEvents() = withReason(REASON_ENROLL_ENROLLING) {
+ controllerOverlay.show(udfpsController)
+
+ with(EnrollListener(controllerOverlay)) {
+ controllerOverlay.onEnrollmentHelp()
+ assertThat(progress).isFalse()
+ assertThat(help).isTrue()
+ assertThat(acquired).isFalse()
+ }
+ }
+
+ @Test
+ fun forwardEnrollAcquiredEvents() = withReason(REASON_ENROLL_ENROLLING) {
+ controllerOverlay.show(udfpsController)
+
+ with(EnrollListener(controllerOverlay)) {
+ controllerOverlay.onEnrollmentProgress(/* remaining */ 1)
+ controllerOverlay.onAcquiredGood()
+ assertThat(progress).isTrue()
+ assertThat(help).isFalse()
+ assertThat(acquired).isTrue()
+ }
+ }
+
+ @Test
+ fun cancels() = withReason(REASON_AUTH_BP) {
+ controllerOverlay.cancel()
+ verify(controllerCallback).onUserCanceled()
+ }
+
+ @Test
+ fun stopIlluminatingOnHide() = withReason(REASON_AUTH_BP) {
+ whenever(udfpsView.isIlluminationRequested).thenReturn(true)
+
+ controllerOverlay.show(udfpsController)
+ controllerOverlay.hide()
+ verify(udfpsView).stopIllumination()
+ }
+}
+
+private class EnrollListener(
+ overlay: UdfpsControllerOverlay,
+ var progress: Boolean = false,
+ var help: Boolean = false,
+ var acquired: Boolean = false
+) : UdfpsEnrollHelper.Listener {
+
+ init {
+ overlay.enrollHelper!!.setListener(this)
+ }
+
+ override fun onEnrollmentProgress(remaining: Int, totalSteps: Int) {
+ progress = true
+ }
+
+ override fun onEnrollmentHelp(remaining: Int, totalSteps: Int) {
+ help = true
+ }
+
+ override fun onLastStepAcquired() {
+ acquired = true
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 1dea678..2afcbda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -24,6 +24,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -53,6 +54,7 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -81,6 +83,7 @@
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -154,7 +157,8 @@
private SystemClock mSystemClock;
@Mock
private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
-
+ @Mock
+ private LatencyTracker mLatencyTracker;
private FakeExecutor mFgExecutor;
// Stuff for configuring mocks
@@ -163,9 +167,13 @@
@Mock
private UdfpsEnrollView mEnrollView;
@Mock
- private UdfpsKeyguardView mKeyguardView;
+ private UdfpsBpView mBpView;
@Mock
- private UdfpsKeyguardViewController mUdfpsKeyguardViewController;
+ private UdfpsFpmOtherView mFpmOtherView;
+ @Mock
+ private UdfpsKeyguardView mKeyguardView;
+ private UdfpsAnimationViewController mUdfpsKeyguardViewController =
+ mock(UdfpsKeyguardViewController.class);
@Mock
private TypedArray mBrightnessValues;
@Mock
@@ -192,6 +200,10 @@
.thenReturn(mEnrollView); // for showOverlay REASON_ENROLL_ENROLLING
when(mLayoutInflater.inflate(R.layout.udfps_keyguard_view, null))
.thenReturn(mKeyguardView); // for showOverlay REASON_AUTH_FPM_KEYGUARD
+ when(mLayoutInflater.inflate(R.layout.udfps_bp_view, null))
+ .thenReturn(mBpView);
+ when(mLayoutInflater.inflate(R.layout.udfps_fpm_other_view, null))
+ .thenReturn(mFpmOtherView);
when(mEnrollView.getContext()).thenReturn(mContext);
when(mKeyguardStateController.isOccluded()).thenReturn(false);
final List<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
@@ -239,7 +251,8 @@
mConfigurationController,
mSystemClock,
mUnlockedScreenOffAnimationController,
- mSystemUIDialogManager);
+ mSystemUIDialogManager,
+ mLatencyTracker);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
@@ -340,7 +353,7 @@
when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
when(mUdfpsView.getAnimationViewController()).thenReturn(
- mock(UdfpsEnrollViewController.class));
+ (UdfpsAnimationViewController) mock(UdfpsEnrollViewController.class));
// GIVEN that the overlay is showing
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
@@ -406,83 +419,6 @@
}
@Test
- public void showUdfpsOverlay_addsViewToWindow_bp() throws RemoteException {
- showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_AUTH_BP);
- }
-
- @Test
- public void showUdfpsOverlay_addsViewToWindow_keyguard() throws RemoteException {
- showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_AUTH_KEYGUARD);
- }
-
- @Test
- public void showUdfpsOverlay_addsViewToWindow_settings() throws RemoteException {
- showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_AUTH_SETTINGS);
- }
-
- @Test
- public void showUdfpsOverlay_addsViewToWindow_enroll_locate() throws RemoteException {
- showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR);
- }
-
- @Test
- public void showUdfpsOverlay_addsViewToWindow_enroll() throws RemoteException {
- showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_ENROLL_ENROLLING);
- }
-
- @Test
- public void showUdfpsOverlay_addsViewToWindow_other() throws RemoteException {
- showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_AUTH_OTHER);
- }
-
- private void showUdfpsOverlay_addsViewToWindow(
- @BiometricOverlayConstants.ShowReason int reason) throws RemoteException {
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID, reason,
- mUdfpsOverlayControllerCallback);
- mFgExecutor.runAllReady();
- verify(mWindowManager).addView(eq(mUdfpsView), any());
- }
-
- @Test
- public void hideUdfpsOverlay_removesViewFromWindow_bp() throws RemoteException {
- hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_AUTH_BP);
- }
-
- @Test
- public void hideUdfpsOverlay_removesViewFromWindow_keyguard() throws RemoteException {
- hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_AUTH_KEYGUARD);
- }
-
- @Test
- public void hideUdfpsOverlay_removesViewFromWindow_settings() throws RemoteException {
- hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_AUTH_SETTINGS);
- }
-
- @Test
- public void hideUdfpsOverlay_removesViewFromWindow_enroll_locate() throws RemoteException {
- hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR);
- }
-
- @Test
- public void hideUdfpsOverlay_removesViewFromWindow_enroll() throws RemoteException {
- hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_ENROLL_ENROLLING);
- }
-
- @Test
- public void hideUdfpsOverlay_removesViewFromWindow_other() throws RemoteException {
- hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_AUTH_OTHER);
- }
-
- private void hideUdfpsOverlay_removesViewFromWindow(
- @BiometricOverlayConstants.ShowReason int reason) throws RemoteException {
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
- mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
- mFgExecutor.runAllReady();
- verify(mWindowManager).removeView(eq(mUdfpsView));
- }
-
- @Test
public void hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing() throws RemoteException {
// GIVEN overlay was showing and the udfps bouncer is showing
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
@@ -532,11 +468,15 @@
// THEN FingerprintManager is notified about onPointerDown
verify(mFingerprintManager).onPointerDown(eq(mUdfpsController.mSensorProps.sensorId), eq(0),
eq(0), eq(0f), eq(0f));
+ verify(mLatencyTracker).onActionStart(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
// AND illumination begins
verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
+ verify(mLatencyTracker, never()).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
// AND onIlluminatedRunnable notifies FingerprintManager about onUiReady
mOnIlluminatedRunnableCaptor.getValue().run();
- verify(mFingerprintManager).onUiReady(eq(mUdfpsController.mSensorProps.sensorId));
+ InOrder inOrder = inOrder(mFingerprintManager, mLatencyTracker);
+ inOrder.verify(mFingerprintManager).onUiReady(eq(mUdfpsController.mSensorProps.sensorId));
+ inOrder.verify(mLatencyTracker).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
new file mode 100644
index 0000000..2cd470e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics
+
+import android.graphics.PointF
+import android.graphics.RectF
+import android.hardware.biometrics.SensorLocationInternal
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.ViewUtils
+import android.view.LayoutInflater
+import android.view.Surface
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.nullable
+import org.mockito.Mockito.never
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+private const val DISPLAY_ID = "" // default display id
+private const val SENSOR_X = 50
+private const val SENSOR_Y = 250
+private const val SENSOR_RADIUS = 10
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class UdfpsViewTest : SysuiTestCase() {
+
+ @JvmField @Rule
+ var rule = MockitoJUnit.rule()
+
+ @Mock
+ lateinit var hbmProvider: UdfpsHbmProvider
+ @Mock
+ lateinit var animationViewController: UdfpsAnimationViewController<UdfpsAnimationView>
+
+ private lateinit var view: UdfpsView
+
+ @Before
+ fun setup() {
+ context.setTheme(R.style.Theme_AppCompat)
+ context.orCreateTestableResources.addOverride(
+ com.android.internal.R.integer.config_udfps_illumination_transition_ms, 0)
+ view = LayoutInflater.from(context).inflate(R.layout.udfps_view, null) as UdfpsView
+ view.animationViewController = animationViewController
+ view.sensorProperties =
+ SensorLocationInternal(DISPLAY_ID, SENSOR_X, SENSOR_Y, SENSOR_RADIUS)
+ .asFingerprintSensorProperties()
+ view.setHbmProvider(hbmProvider)
+ ViewUtils.attachView(view)
+ }
+
+ @After
+ fun cleanup() {
+ ViewUtils.detachView(view)
+ }
+
+ @Test
+ fun forwardsEvents() {
+ view.dozeTimeTick()
+ verify(animationViewController).dozeTimeTick()
+
+ view.onTouchOutsideView()
+ verify(animationViewController).onTouchOutsideView()
+ }
+
+ @Test
+ fun layoutSizeFitsSensor() {
+ val params = withArgCaptor<RectF> {
+ verify(animationViewController).onSensorRectUpdated(capture())
+ }
+ assertThat(params.width()).isAtLeast(2f * SENSOR_RADIUS)
+ assertThat(params.height()).isAtLeast(2f * SENSOR_RADIUS)
+ }
+
+ @Test
+ fun isWithinSensorAreaAndPaused() = isWithinSensorArea(paused = true)
+
+ @Test
+ fun isWithinSensorAreaAndNotPaused() = isWithinSensorArea(paused = false)
+
+ private fun isWithinSensorArea(paused: Boolean) {
+ whenever(animationViewController.shouldPauseAuth()).thenReturn(paused)
+ whenever(animationViewController.touchTranslation).thenReturn(PointF(0f, 0f))
+ val end = (SENSOR_RADIUS * 2) - 1
+ for (x in 1 until end) {
+ for (y in 1 until end) {
+ assertThat(view.isWithinSensorArea(x.toFloat(), y.toFloat())).isEqualTo(!paused)
+ }
+ }
+ }
+
+ @Test
+ fun isWithinSensorAreaWhenTranslated() {
+ val offset = PointF(100f, 200f)
+ whenever(animationViewController.touchTranslation).thenReturn(offset)
+ val end = (SENSOR_RADIUS * 2) - 1
+ for (x in 0 until offset.x.toInt() step 2) {
+ for (y in 0 until offset.y.toInt() step 2) {
+ assertThat(view.isWithinSensorArea(x.toFloat(), y.toFloat())).isFalse()
+ }
+ }
+ for (x in offset.x.toInt() + 1 until offset.x.toInt() + end) {
+ for (y in offset.y.toInt() + 1 until offset.y.toInt() + end) {
+ assertThat(view.isWithinSensorArea(x.toFloat(), y.toFloat())).isTrue()
+ }
+ }
+ }
+
+ @Test
+ fun isNotWithinSensorArea() {
+ whenever(animationViewController.touchTranslation).thenReturn(PointF(0f, 0f))
+ assertThat(view.isWithinSensorArea(SENSOR_RADIUS * 2.5f, SENSOR_RADIUS.toFloat())).isFalse()
+ assertThat(view.isWithinSensorArea(SENSOR_RADIUS.toFloat(), SENSOR_RADIUS * 2.5f)).isFalse()
+ }
+
+ @Test
+ fun startAndStopIllumination() {
+ val onDone: Runnable = mock()
+ view.startIllumination(onDone)
+
+ val illuminator = withArgCaptor<Runnable> {
+ verify(hbmProvider).enableHbm(anyInt(), nullable(Surface::class.java), capture())
+ }
+
+ assertThat(view.isIlluminationRequested).isTrue()
+ verify(animationViewController).onIlluminationStarting()
+ verify(animationViewController, never()).onIlluminationStopped()
+ verify(onDone, never()).run()
+
+ // fake illumination event
+ illuminator.run()
+ waitForLooper()
+ verify(onDone).run()
+ verify(hbmProvider, never()).disableHbm(any())
+
+ view.stopIllumination()
+ assertThat(view.isIlluminationRequested).isFalse()
+ verify(animationViewController).onIlluminationStopped()
+ verify(hbmProvider).disableHbm(nullable(Runnable::class.java))
+ }
+
+ private fun waitForLooper() = TestableLooper.get(this).processAllMessages()
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
index 55af51d..e5a75e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
@@ -27,8 +27,6 @@
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -43,10 +41,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
-import com.android.systemui.unfold.FoldAodAnimationController;
-import com.android.systemui.unfold.SysUIUnfoldComponent;
import com.android.systemui.util.wakelock.WakeLockFake;
import org.junit.After;
@@ -56,8 +51,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.Optional;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public class DozeUiTest extends SysuiTestCase {
@@ -82,12 +75,6 @@
private DozeUi mDozeUi;
@Mock
private StatusBarStateController mStatusBarStateController;
- @Mock
- private FoldAodAnimationController mFoldAodAnimationController;
- @Mock
- private SysUIUnfoldComponent mSysUIUnfoldComponent;
- @Mock
- private ConfigurationController mConfigurationController;
@Before
public void setUp() throws Exception {
@@ -98,13 +85,8 @@
mWakeLock = new WakeLockFake();
mHandler = mHandlerThread.getThreadHandler();
- when(mSysUIUnfoldComponent.getFoldAodAnimationController())
- .thenReturn(mFoldAodAnimationController);
-
mDozeUi = new DozeUi(mContext, mAlarmManager, mWakeLock, mHost, mHandler,
- mDozeParameters, mKeyguardUpdateMonitor, mDozeLog, mTunerService,
- mStatusBarStateController, Optional.of(mSysUIUnfoldComponent),
- mConfigurationController);
+ mDozeParameters, mKeyguardUpdateMonitor, mStatusBarStateController, mDozeLog);
mDozeUi.setDozeMachine(mMachine);
}
@@ -116,7 +98,7 @@
}
@Test
- public void pausingAndUnpausingAod_registersTimeTickAfterUnpausing() throws Exception {
+ public void pausingAndUnpausingAod_registersTimeTickAfterUnpausing() {
mDozeUi.transitionTo(UNINITIALIZED, INITIALIZED);
mDozeUi.transitionTo(INITIALIZED, DOZE_AOD);
mDozeUi.transitionTo(DOZE_AOD, DOZE_AOD_PAUSED);
@@ -129,60 +111,9 @@
}
@Test
- public void propagatesAnimateScreenOff_noAlwaysOn() {
- reset(mHost);
- when(mDozeParameters.getAlwaysOn()).thenReturn(false);
- when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false);
- when(mDozeParameters.shouldAnimateDozingChange()).thenReturn(true);
-
- mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(false);
- verify(mHost).setAnimateScreenOff(eq(false));
- }
-
- @Test
- public void propagatesAnimateScreenOff_alwaysOn() {
- reset(mHost);
- when(mDozeParameters.getAlwaysOn()).thenReturn(true);
- when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false);
- when(mDozeParameters.shouldAnimateDozingChange()).thenReturn(true);
-
- // Take over when the keyguard is visible.
- mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(true);
- verify(mHost).setAnimateScreenOff(eq(true));
-
- // Do not animate screen-off when keyguard isn't visible - PowerManager will do it.
- mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(false);
- verify(mHost).setAnimateScreenOff(eq(false));
- }
-
- @Test
- public void propagatesAnimateScreenOff_alwaysOn_shouldAnimateDozingChangeIsFalse() {
- reset(mHost);
- when(mDozeParameters.getAlwaysOn()).thenReturn(true);
- when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false);
- when(mDozeParameters.shouldAnimateDozingChange()).thenReturn(false);
-
- // Take over when the keyguard is visible.
- mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(true);
- verify(mHost).setAnimateScreenOff(eq(false));
- }
-
- @Test
- public void neverAnimateScreenOff_whenNotSupported() {
- // Re-initialize DozeParameters saying that the display requires blanking.
- reset(mDozeParameters);
- reset(mHost);
- when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true);
- mDozeUi = new DozeUi(mContext, mAlarmManager, mWakeLock, mHost, mHandler,
- mDozeParameters, mKeyguardUpdateMonitor, mDozeLog, mTunerService,
- mStatusBarStateController, Optional.of(mSysUIUnfoldComponent),
- mConfigurationController);
- mDozeUi.setDozeMachine(mMachine);
-
- // Never animate if display doesn't support it.
- mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(true);
- mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(false);
- verify(mHost, never()).setAnimateScreenOff(eq(false));
+ public void transitionSetsAnimateWakeup_noAlwaysOn() {
+ mDozeUi.transitionTo(UNINITIALIZED, DOZE);
+ verify(mHost).setAnimateWakeup(eq(false));
}
@Test
@@ -192,49 +123,4 @@
mDozeUi.transitionTo(UNINITIALIZED, DOZE);
verify(mHost).setAnimateWakeup(eq(true));
}
-
- @Test
- public void keyguardVisibility_changesControlScreenOffAnimation() {
- // Pre-condition
- reset(mDozeParameters);
- when(mDozeParameters.getAlwaysOn()).thenReturn(true);
- when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false);
-
- mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(false);
- verify(mDozeParameters).setControlScreenOffAnimation(eq(false));
- mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(true);
- verify(mDozeParameters).setControlScreenOffAnimation(eq(true));
- }
-
- @Test
- public void transitionSetsAnimateWakeup_noAlwaysOn() {
- mDozeUi.transitionTo(UNINITIALIZED, DOZE);
- verify(mHost).setAnimateWakeup(eq(false));
- }
-
- @Test
- public void controlScreenOffTrueWhenKeyguardNotShowingAndControlUnlockedScreenOff() {
- when(mDozeParameters.getAlwaysOn()).thenReturn(true);
- when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true);
-
- // Tell doze that keyguard is not visible.
- mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(false /* showing */);
-
- // Since we're controlling the unlocked screen off animation, verify that we've asked to
- // control the screen off animation despite being unlocked.
- verify(mDozeParameters).setControlScreenOffAnimation(true);
- }
-
- @Test
- public void controlScreenOffFalseWhenKeyguardNotShowingAndControlUnlockedScreenOffFalse() {
- when(mDozeParameters.getAlwaysOn()).thenReturn(true);
- when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(false);
-
- // Tell doze that keyguard is not visible.
- mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(false /* showing */);
-
- // Since we're not controlling the unlocked screen off animation, verify that we haven't
- // asked to control the screen off animation since we're unlocked.
- verify(mDozeParameters).setControlScreenOffAnimation(false);
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
new file mode 100644
index 0000000..cf53ccf
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.res.Resources;
+import android.testing.AndroidTestingRunner;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
+ private static final int DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT = 100;
+
+ @Mock
+ Resources mResources;
+
+ @Mock
+ ViewTreeObserver mViewTreeObserver;
+
+ @Mock
+ DreamOverlayStatusBarViewController mDreamOverlayStatusBarViewController;
+
+ @Mock
+ DreamOverlayContainerView mDreamOverlayContainerView;
+
+ @Mock
+ ViewGroup mDreamOverlayContentView;
+
+ DreamOverlayContainerViewController mController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mResources.getDimensionPixelSize(
+ R.dimen.dream_overlay_notifications_drag_area_height)).thenReturn(
+ DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT);
+ when(mDreamOverlayContainerView.getResources()).thenReturn(mResources);
+ when(mDreamOverlayContainerView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
+
+ mController = new DreamOverlayContainerViewController(
+ mDreamOverlayContainerView, mDreamOverlayContentView,
+ mDreamOverlayStatusBarViewController);
+ }
+
+ @Test
+ public void testDreamOverlayStatusBarViewControllerInitialized() {
+ mController.init();
+ verify(mDreamOverlayStatusBarViewController).init();
+ }
+
+ @Test
+ public void testSetsDreamOverlayNotificationsDragAreaHeight() {
+ assertEquals(
+ mController.getDreamOverlayNotificationsDragAreaHeight(),
+ DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT);
+ }
+
+ @Test
+ public void testAddOverlayAddsOverlayToContentView() {
+ View overlay = new View(getContext());
+ ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(100, 100);
+ mController.addOverlay(overlay, layoutParams);
+ verify(mDreamOverlayContentView).addView(overlay, layoutParams);
+ }
+
+ @Test
+ public void testRemoveAllOverlaysRemovesOverlaysFromContentView() {
+ mController.removeAllOverlays();
+ verify(mDreamOverlayContentView).removeAllViews();
+ }
+
+ @Test
+ public void testOnViewAttachedRegistersComputeInsetsListener() {
+ mController.onViewAttached();
+ verify(mViewTreeObserver).addOnComputeInternalInsetsListener(any());
+ }
+
+ @Test
+ public void testOnViewDetachedUnregistersComputeInsetsListener() {
+ mController.onViewDetached();
+ verify(mViewTreeObserver).removeOnComputeInternalInsetsListener(any());
+ }
+
+ @Test
+ public void testComputeInsetsListenerReturnsRegion() {
+ final ArgumentCaptor<ViewTreeObserver.OnComputeInternalInsetsListener>
+ computeInsetsListenerCapture =
+ ArgumentCaptor.forClass(ViewTreeObserver.OnComputeInternalInsetsListener.class);
+ mController.onViewAttached();
+ verify(mViewTreeObserver).addOnComputeInternalInsetsListener(
+ computeInsetsListenerCapture.capture());
+ final ViewTreeObserver.InternalInsetsInfo info = new ViewTreeObserver.InternalInsetsInfo();
+ computeInsetsListenerCapture.getValue().onComputeInternalInsets(info);
+ assertNotNull(info.touchableRegion);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index 5fa710f..8cd8e4d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -17,7 +17,6 @@
package com.android.systemui.dreams;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -55,8 +54,8 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamOverlayServiceTest extends SysuiTestCase {
- private FakeSystemClock mFakeSystemClock = new FakeSystemClock();
- private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
+ private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
+ private final FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
@Rule
public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck();
@@ -80,51 +79,55 @@
DreamOverlayStateController mDreamOverlayStateController;
@Mock
- DreamOverlayComponent.Factory mDreamOverlayStatusBarViewComponentFactory;
+ DreamOverlayComponent.Factory mDreamOverlayComponentFactory;
@Mock
DreamOverlayComponent mDreamOverlayComponent;
@Mock
- DreamOverlayStatusBarViewController mDreamOverlayStatusBarViewController;
-
- @Mock
DreamOverlayContainerView mDreamOverlayContainerView;
@Mock
- ViewGroup mDreamOverlayContentView;
+ DreamOverlayContainerViewController mDreamOverlayContainerViewController;
+
+ DreamOverlayService mService;
@Before
- public void setup() {
+ public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
mContext.addMockSystemService(WindowManager.class, mWindowManager);
- when(mDreamOverlayComponent.getDreamOverlayContentView())
- .thenReturn(mDreamOverlayContentView);
- when(mDreamOverlayComponent.getDreamOverlayContainerView())
- .thenReturn(mDreamOverlayContainerView);
- when(mDreamOverlayComponent.getDreamOverlayStatusBarViewController())
- .thenReturn(mDreamOverlayStatusBarViewController);
- when(mDreamOverlayStatusBarViewComponentFactory.create())
+ when(mDreamOverlayComponent.getDreamOverlayContainerViewController())
+ .thenReturn(mDreamOverlayContainerViewController);
+ when(mDreamOverlayComponentFactory.create())
.thenReturn(mDreamOverlayComponent);
+ when(mDreamOverlayContainerViewController.getContainerView())
+ .thenReturn(mDreamOverlayContainerView);
- }
-
- @Test
- public void testInteraction() throws Exception {
- final DreamOverlayService service = new DreamOverlayService(mContext, mMainExecutor,
- mDreamOverlayStateController, mDreamOverlayStatusBarViewComponentFactory);
- final IBinder proxy = service.onBind(new Intent());
+ mService = new DreamOverlayService(mContext, mMainExecutor,
+ mDreamOverlayStateController, mDreamOverlayComponentFactory);
+ final IBinder proxy = mService.onBind(new Intent());
final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
- clearInvocations(mWindowManager);
// Inform the overlay service of dream starting.
overlay.startDream(mWindowParams, mDreamOverlayCallback);
mMainExecutor.runAllReady();
- verify(mWindowManager).addView(any(), any());
+ }
+ @Test
+ public void testOverlayContainerViewAddedToWindow() {
+ verify(mWindowManager).addView(any(), any());
+ }
+
+ @Test
+ public void testDreamOverlayContainerViewControllerInitialized() {
+ verify(mDreamOverlayContainerViewController).init();
+ }
+
+ @Test
+ public void testAddingOverlayToDream() throws Exception {
// Add overlay.
- service.addComplication(mProvider);
+ mService.addComplication(mProvider);
mMainExecutor.runAllReady();
final ArgumentCaptor<ComplicationHost.CreationCallback> creationCallbackCapture =
@@ -139,9 +142,26 @@
// Inform service of overlay view creation.
final View view = new View(mContext);
- creationCallbackCapture.getValue().onCreated(view, new ConstraintLayout.LayoutParams(
+ final ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
- ));
+ );
+ creationCallbackCapture.getValue().onCreated(view, lp);
+ mMainExecutor.runAllReady();
+
+ // Verify that DreamOverlayContainerViewController is asked to add an overlay for the view.
+ verify(mDreamOverlayContainerViewController).addOverlay(view, lp);
+ }
+
+ @Test
+ public void testDreamOverlayExit() throws Exception {
+ // Add overlay.
+ mService.addComplication(mProvider);
+ mMainExecutor.runAllReady();
+
+ // Capture interaction callback from overlay creation.
+ final ArgumentCaptor<ComplicationHost.InteractionCallback> interactionCallbackCapture =
+ ArgumentCaptor.forClass(ComplicationHost.InteractionCallback.class);
+ verify(mProvider).onCreateComplication(any(), any(), interactionCallbackCapture.capture());
// Ask service to exit.
interactionCallbackCapture.getValue().onExit();
@@ -152,17 +172,7 @@
}
@Test
- public void testListening() throws Exception {
- final DreamOverlayService service = new DreamOverlayService(mContext, mMainExecutor,
- mDreamOverlayStateController, mDreamOverlayStatusBarViewComponentFactory);
-
- final IBinder proxy = service.onBind(new Intent());
- final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
-
- // Inform the overlay service of dream starting.
- overlay.startDream(mWindowParams, mDreamOverlayCallback);
- mMainExecutor.runAllReady();
-
+ public void testListenerRegisteredWithDreamOverlayStateController() {
// Verify overlay service registered as listener with DreamOverlayStateController
// and inform callback of addition.
final ArgumentCaptor<DreamOverlayStateController.Callback> callbackCapture =
@@ -178,33 +188,11 @@
}
@Test
- public void testDreamOverlayStatusBarViewControllerInitialized() throws Exception {
- final DreamOverlayService service = new DreamOverlayService(mContext, mMainExecutor,
- mDreamOverlayStateController, mDreamOverlayStatusBarViewComponentFactory);
-
- final IBinder proxy = service.onBind(new Intent());
- final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
-
- // Inform the overlay service of dream starting.
- overlay.startDream(mWindowParams, mDreamOverlayCallback);
- mMainExecutor.runAllReady();
-
- verify(mDreamOverlayStatusBarViewController).init();
- }
-
- @Test
- public void testRootViewAttachListenerIsAddedToDreamOverlayContentView() throws Exception {
- final DreamOverlayService service = new DreamOverlayService(mContext, mMainExecutor,
- mDreamOverlayStateController, mDreamOverlayStatusBarViewComponentFactory);
-
- final IBinder proxy = service.onBind(new Intent());
- final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
-
- // Inform the overlay service of dream starting.
- overlay.startDream(mWindowParams, mDreamOverlayCallback);
- mMainExecutor.runAllReady();
-
- verify(mDreamOverlayContentView).addOnAttachStateChangeListener(
- any(View.OnAttachStateChangeListener.class));
+ public void testOnDestroyRemovesOverlayStateCallback() {
+ final ArgumentCaptor<DreamOverlayStateController.Callback> callbackCapture =
+ ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
+ verify(mDreamOverlayStateController).addCallback(callbackCapture.capture());
+ mService.onDestroy();
+ verify(mDreamOverlayStateController).removeCallback(callbackCapture.getValue());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
index a6e567e..d2be1f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -36,6 +36,7 @@
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
import javax.inject.Provider
private val DATA = MediaData(
@@ -74,6 +75,7 @@
@Mock lateinit var falsingCollector: FalsingCollector
@Mock lateinit var falsingManager: FalsingManager
@Mock lateinit var dumpManager: DumpManager
+ @Mock lateinit var mediaFlags: MediaFlags
private val clock = FakeSystemClock()
private lateinit var mediaCarouselController: MediaCarouselController
@@ -81,7 +83,7 @@
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
-
+ whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
mediaCarouselController = MediaCarouselController(
context,
mediaControlPanelFactory,
@@ -94,7 +96,8 @@
configurationController,
falsingCollector,
falsingManager,
- dumpManager
+ dumpManager,
+ mediaFlags
)
MediaPlayerData.clear()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 7cc0172..7763e75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -43,7 +43,6 @@
import com.android.systemui.media.dialog.MediaOutputDialogFactory
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
-import com.android.systemui.statusbar.phone.KeyguardDismissUtil
import com.android.systemui.util.animation.TransitionLayout
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.eq
@@ -87,11 +86,11 @@
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var holder: PlayerViewHolder
+ @Mock private lateinit var sessionHolder: PlayerSessionViewHolder
@Mock private lateinit var view: TransitionLayout
@Mock private lateinit var seekBarViewModel: SeekBarViewModel
@Mock private lateinit var seekBarData: LiveData<SeekBarViewModel.Progress>
@Mock private lateinit var mediaViewController: MediaViewController
- @Mock private lateinit var keyguardDismissUtil: KeyguardDismissUtil
@Mock private lateinit var mediaDataManager: MediaDataManager
@Mock private lateinit var expandedSet: ConstraintSet
@Mock private lateinit var collapsedSet: ConstraintSet
@@ -104,6 +103,8 @@
private lateinit var titleText: TextView
private lateinit var artistText: TextView
private lateinit var seamless: ViewGroup
+ private lateinit var seamlessButton: View
+ @Mock private lateinit var seamlessBackground: RippleDrawable
private lateinit var seamlessIcon: ImageView
private lateinit var seamlessText: TextView
private lateinit var seekBar: SeekBar
@@ -114,6 +115,11 @@
private lateinit var action2: ImageButton
private lateinit var action3: ImageButton
private lateinit var action4: ImageButton
+ private lateinit var actionPlayPause: ImageButton
+ private lateinit var actionNext: ImageButton
+ private lateinit var actionPrev: ImageButton
+ private lateinit var actionStart: ImageButton
+ private lateinit var actionEnd: ImageButton
@Mock private lateinit var longPressText: TextView
@Mock private lateinit var handler: Handler
private lateinit var settings: View
@@ -137,62 +143,30 @@
whenever(mediaViewController.collapsedLayout).thenReturn(collapsedSet)
player = MediaControlPanel(context, bgExecutor, activityStarter, mediaViewController,
- seekBarViewModel, Lazy { mediaDataManager }, keyguardDismissUtil,
+ seekBarViewModel, Lazy { mediaDataManager },
mediaOutputDialogFactory, mediaCarouselController, falsingManager, mediaFlags, clock)
whenever(seekBarViewModel.progress).thenReturn(seekBarData)
- // Mock out a view holder for the player to attach to.
- whenever(holder.player).thenReturn(view)
+ // Set up mock views for the players
appIcon = ImageView(context)
- whenever(holder.appIcon).thenReturn(appIcon)
albumView = ImageView(context)
- whenever(holder.albumView).thenReturn(albumView)
titleText = TextView(context)
- whenever(holder.titleText).thenReturn(titleText)
artistText = TextView(context)
- whenever(holder.artistText).thenReturn(artistText)
seamless = FrameLayout(context)
- val seamlessBackground = mock(RippleDrawable::class.java)
seamless.foreground = seamlessBackground
- whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
- whenever(holder.seamless).thenReturn(seamless)
+ seamlessButton = View(context)
seamlessIcon = ImageView(context)
- whenever(holder.seamlessIcon).thenReturn(seamlessIcon)
seamlessText = TextView(context)
- whenever(holder.seamlessText).thenReturn(seamlessText)
seekBar = SeekBar(context)
- whenever(holder.seekBar).thenReturn(seekBar)
elapsedTimeView = TextView(context)
- whenever(holder.elapsedTimeView).thenReturn(elapsedTimeView)
totalTimeView = TextView(context)
- whenever(holder.totalTimeView).thenReturn(totalTimeView)
- action0 = ImageButton(context)
- whenever(holder.action0).thenReturn(action0)
- whenever(holder.getAction(R.id.action0)).thenReturn(action0)
- action1 = ImageButton(context)
- whenever(holder.action1).thenReturn(action1)
- whenever(holder.getAction(R.id.action1)).thenReturn(action1)
- action2 = ImageButton(context)
- whenever(holder.action2).thenReturn(action2)
- whenever(holder.getAction(R.id.action2)).thenReturn(action2)
- action3 = ImageButton(context)
- whenever(holder.action3).thenReturn(action3)
- whenever(holder.getAction(R.id.action3)).thenReturn(action3)
- action4 = ImageButton(context)
- whenever(holder.action4).thenReturn(action4)
- whenever(holder.getAction(R.id.action4)).thenReturn(action4)
- whenever(holder.longPressText).thenReturn(longPressText)
- whenever(longPressText.handler).thenReturn(handler)
settings = View(context)
- whenever(holder.settings).thenReturn(settings)
settingsText = TextView(context)
- whenever(holder.settingsText).thenReturn(settingsText)
cancel = View(context)
- whenever(holder.cancel).thenReturn(cancel)
dismiss = FrameLayout(context)
- whenever(holder.dismiss).thenReturn(dismiss)
dismissLabel = View(context)
- whenever(holder.dismissLabel).thenReturn(dismissLabel)
+ initPlayerHolderMocks()
+ initSessionHolderMocks()
// Create media session
val metadataBuilder = MediaMetadata.Builder().apply {
@@ -230,6 +204,89 @@
whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(false)
}
+ /** Mock view holder for the notification player */
+ private fun initPlayerHolderMocks() {
+ whenever(holder.player).thenReturn(view)
+ whenever(holder.appIcon).thenReturn(appIcon)
+ whenever(holder.albumView).thenReturn(albumView)
+ whenever(holder.titleText).thenReturn(titleText)
+ whenever(holder.artistText).thenReturn(artistText)
+ whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
+ whenever(holder.seamless).thenReturn(seamless)
+ whenever(holder.seamlessButton).thenReturn(seamlessButton)
+ whenever(holder.seamlessIcon).thenReturn(seamlessIcon)
+ whenever(holder.seamlessText).thenReturn(seamlessText)
+ whenever(holder.seekBar).thenReturn(seekBar)
+ whenever(holder.elapsedTimeView).thenReturn(elapsedTimeView)
+ whenever(holder.totalTimeView).thenReturn(totalTimeView)
+
+ // Action buttons
+ action0 = ImageButton(context)
+ whenever(holder.action0).thenReturn(action0)
+ whenever(holder.getAction(R.id.action0)).thenReturn(action0)
+ action1 = ImageButton(context)
+ whenever(holder.action1).thenReturn(action1)
+ whenever(holder.getAction(R.id.action1)).thenReturn(action1)
+ action2 = ImageButton(context)
+ whenever(holder.action2).thenReturn(action2)
+ whenever(holder.getAction(R.id.action2)).thenReturn(action2)
+ action3 = ImageButton(context)
+ whenever(holder.action3).thenReturn(action3)
+ whenever(holder.getAction(R.id.action3)).thenReturn(action3)
+ action4 = ImageButton(context)
+ whenever(holder.action4).thenReturn(action4)
+ whenever(holder.getAction(R.id.action4)).thenReturn(action4)
+
+ // Long press menu
+ whenever(holder.longPressText).thenReturn(longPressText)
+ whenever(longPressText.handler).thenReturn(handler)
+ whenever(holder.settings).thenReturn(settings)
+ whenever(holder.settingsText).thenReturn(settingsText)
+ whenever(holder.cancel).thenReturn(cancel)
+ whenever(holder.dismiss).thenReturn(dismiss)
+ whenever(holder.dismissLabel).thenReturn(dismissLabel)
+ }
+
+ /** Mock view holder for session player */
+ private fun initSessionHolderMocks() {
+ whenever(sessionHolder.player).thenReturn(view)
+ whenever(sessionHolder.appIcon).thenReturn(appIcon)
+ whenever(sessionHolder.titleText).thenReturn(titleText)
+ whenever(sessionHolder.artistText).thenReturn(artistText)
+ val seamlessBackground = mock(RippleDrawable::class.java)
+ whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
+ whenever(sessionHolder.seamless).thenReturn(seamless)
+ whenever(sessionHolder.seamlessButton).thenReturn(seamlessButton)
+ whenever(sessionHolder.seamlessIcon).thenReturn(seamlessIcon)
+ whenever(sessionHolder.seamlessText).thenReturn(seamlessText)
+ whenever(sessionHolder.seekBar).thenReturn(seekBar)
+
+ // Action buttons
+ actionPlayPause = ImageButton(context)
+ whenever(sessionHolder.actionPlayPause).thenReturn(actionPlayPause)
+ whenever(sessionHolder.getAction(R.id.actionPlayPause)).thenReturn(actionPlayPause)
+ actionNext = ImageButton(context)
+ whenever(sessionHolder.actionNext).thenReturn(actionNext)
+ whenever(sessionHolder.getAction(R.id.actionNext)).thenReturn(actionNext)
+ actionPrev = ImageButton(context)
+ whenever(sessionHolder.actionPrev).thenReturn(actionPrev)
+ whenever(sessionHolder.getAction(R.id.actionPrev)).thenReturn(actionPrev)
+ actionStart = ImageButton(context)
+ whenever(sessionHolder.actionStart).thenReturn(actionStart)
+ whenever(sessionHolder.getAction(R.id.actionStart)).thenReturn(actionStart)
+ actionEnd = ImageButton(context)
+ whenever(sessionHolder.actionEnd).thenReturn(actionEnd)
+ whenever(sessionHolder.getAction(R.id.actionEnd)).thenReturn(actionEnd)
+
+ // Long press menu
+ whenever(sessionHolder.longPressText).thenReturn(longPressText)
+ whenever(sessionHolder.settings).thenReturn(settings)
+ whenever(sessionHolder.settingsText).thenReturn(settingsText)
+ whenever(sessionHolder.cancel).thenReturn(cancel)
+ whenever(sessionHolder.dismiss).thenReturn(dismiss)
+ whenever(sessionHolder.dismissLabel).thenReturn(dismissLabel)
+ }
+
@After
fun tearDown() {
session.release()
@@ -255,32 +312,28 @@
)
val state = mediaData.copy(semanticActions = semanticActions)
- player.attachPlayer(holder)
+ player.attachPlayer(sessionHolder, MediaViewController.TYPE.PLAYER_SESSION)
player.bindPlayer(state, PACKAGE)
- verify(expandedSet).setVisibility(R.id.action0, ConstraintSet.VISIBLE)
- assertThat(action0.contentDescription).isEqualTo("custom 1")
- assertThat(action0.isEnabled()).isFalse()
+ assertThat(actionStart.contentDescription).isEqualTo("custom 1")
+ assertThat(actionStart.isEnabled()).isFalse()
- verify(expandedSet).setVisibility(R.id.action1, ConstraintSet.INVISIBLE)
- assertThat(action1.isEnabled()).isFalse()
+ assertThat(actionPrev.isEnabled()).isFalse()
+ assertThat(actionPrev.drawable).isNull()
- verify(expandedSet).setVisibility(R.id.action2, ConstraintSet.VISIBLE)
- assertThat(action2.isEnabled()).isTrue()
- assertThat(action2.contentDescription).isEqualTo("play")
+ assertThat(actionPlayPause.isEnabled()).isTrue()
+ assertThat(actionPlayPause.contentDescription).isEqualTo("play")
- verify(expandedSet).setVisibility(R.id.action3, ConstraintSet.VISIBLE)
- assertThat(action3.isEnabled()).isTrue()
- assertThat(action3.contentDescription).isEqualTo("next")
+ assertThat(actionNext.isEnabled()).isTrue()
+ assertThat(actionNext.contentDescription).isEqualTo("next")
- verify(expandedSet).setVisibility(R.id.action4, ConstraintSet.VISIBLE)
- assertThat(action4.contentDescription).isEqualTo("custom 2")
- assertThat(action4.isEnabled()).isFalse()
+ assertThat(actionEnd.contentDescription).isEqualTo("custom 2")
+ assertThat(actionEnd.isEnabled()).isFalse()
}
@Test
fun bindText() {
- player.attachPlayer(holder)
+ player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
player.bindPlayer(mediaData, PACKAGE)
assertThat(titleText.getText()).isEqualTo(TITLE)
assertThat(artistText.getText()).isEqualTo(ARTIST)
@@ -288,7 +341,7 @@
@Test
fun bindDevice() {
- player.attachPlayer(holder)
+ player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
player.bindPlayer(mediaData, PACKAGE)
assertThat(seamlessText.getText()).isEqualTo(DEVICE_NAME)
assertThat(seamless.contentDescription).isEqualTo(DEVICE_NAME)
@@ -299,7 +352,7 @@
fun bindDisabledDevice() {
seamless.id = 1
val fallbackString = context.getString(R.string.media_seamless_other_device)
- player.attachPlayer(holder)
+ player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
val state = mediaData.copy(device = disabledDevice)
player.bindPlayer(state, PACKAGE)
assertThat(seamless.isEnabled()).isFalse()
@@ -310,7 +363,7 @@
@Test
fun bindNullDevice() {
val fallbackString = context.getResources().getString(R.string.media_seamless_other_device)
- player.attachPlayer(holder)
+ player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
val state = mediaData.copy(device = null)
player.bindPlayer(state, PACKAGE)
assertThat(seamless.isEnabled()).isTrue()
@@ -320,7 +373,7 @@
@Test
fun bindDeviceResumptionPlayer() {
- player.attachPlayer(holder)
+ player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
val state = mediaData.copy(resumption = true)
player.bindPlayer(state, PACKAGE)
assertThat(seamlessText.getText()).isEqualTo(DEVICE_NAME)
@@ -329,7 +382,7 @@
@Test
fun longClick_gutsClosed() {
- player.attachPlayer(holder)
+ player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
whenever(mediaViewController.isGutsVisible).thenReturn(false)
val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
@@ -341,7 +394,7 @@
@Test
fun longClick_gutsOpen() {
- player.attachPlayer(holder)
+ player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
whenever(mediaViewController.isGutsVisible).thenReturn(true)
val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
@@ -354,7 +407,7 @@
@Test
fun cancelButtonClick_animation() {
- player.attachPlayer(holder)
+ player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
cancel.callOnClick()
@@ -363,7 +416,7 @@
@Test
fun settingsButtonClick() {
- player.attachPlayer(holder)
+ player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
settings.callOnClick()
@@ -376,7 +429,7 @@
@Test
fun dismissButtonClick() {
val mediaKey = "key for dismissal"
- player.attachPlayer(holder)
+ player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
val state = mediaData.copy(notificationKey = KEY)
player.bindPlayer(state, mediaKey)
@@ -388,7 +441,7 @@
@Test
fun dismissButtonDisabled() {
val mediaKey = "key for dismissal"
- player.attachPlayer(holder)
+ player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
val state = mediaData.copy(isClearable = false, notificationKey = KEY)
player.bindPlayer(state, mediaKey)
@@ -400,7 +453,7 @@
val mediaKey = "key for dismissal"
whenever(mediaDataManager.dismissMediaData(eq(mediaKey), anyLong())).thenReturn(false)
- player.attachPlayer(holder)
+ player.attachPlayer(holder, MediaViewController.TYPE.PLAYER)
val state = mediaData.copy(notificationKey = KEY)
player.bindPlayer(state, mediaKey)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
index e77802f..3c2392a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
@@ -62,7 +62,7 @@
whenever(mockHolder.elapsedTimeView).thenReturn(elapsedTimeView)
whenever(mockHolder.totalTimeView).thenReturn(totalTimeView)
- observer = SeekBarObserver(mockHolder)
+ observer = SeekBarObserver(mockHolder, false /* useSessionLayout */)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
index 9b2d3eb..dec5a10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
@@ -18,6 +18,12 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver
+import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
+import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender
+import com.android.systemui.media.taptotransfer.sender.MoveCloserToTransfer
+import com.android.systemui.media.taptotransfer.sender.TransferInitiated
+import com.android.systemui.media.taptotransfer.sender.TransferSucceeded
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.util.concurrency.FakeExecutor
@@ -42,80 +48,118 @@
private lateinit var mediaTttCommandLineHelper: MediaTttCommandLineHelper
@Mock
- private lateinit var mediaTttChipController: MediaTttChipController
+ private lateinit var mediaTttChipControllerSender: MediaTttChipControllerSender
+ @Mock
+ private lateinit var mediaTttChipControllerReceiver: MediaTttChipControllerReceiver
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
mediaTttCommandLineHelper =
MediaTttCommandLineHelper(
- commandRegistry, mediaTttChipController, FakeExecutor(FakeSystemClock())
+ commandRegistry,
+ context,
+ mediaTttChipControllerSender,
+ mediaTttChipControllerReceiver,
+ FakeExecutor(FakeSystemClock())
)
}
@Test(expected = IllegalStateException::class)
- fun constructor_addCommandAlreadyRegistered() {
+ fun constructor_addSenderCommandAlreadyRegistered() {
// Since creating the chip controller should automatically register the add command, it
// should throw when registering it again.
commandRegistry.registerCommand(
- ADD_CHIP_COMMAND_TAG
+ ADD_CHIP_COMMAND_SENDER_TAG
) { EmptyCommand() }
}
@Test(expected = IllegalStateException::class)
- fun constructor_removeCommandAlreadyRegistered() {
+ fun constructor_removeSenderCommandAlreadyRegistered() {
// Since creating the chip controller should automatically register the remove command, it
// should throw when registering it again.
commandRegistry.registerCommand(
- REMOVE_CHIP_COMMAND_TAG
+ REMOVE_CHIP_COMMAND_SENDER_TAG
+ ) { EmptyCommand() }
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun constructor_addReceiverCommandAlreadyRegistered() {
+ // Since creating the chip controller should automatically register the add command, it
+ // should throw when registering it again.
+ commandRegistry.registerCommand(
+ ADD_CHIP_COMMAND_RECEIVER_TAG
+ ) { EmptyCommand() }
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun constructor_removeReceiverCommandAlreadyRegistered() {
+ // Since creating the chip controller should automatically register the remove command, it
+ // should throw when registering it again.
+ commandRegistry.registerCommand(
+ REMOVE_CHIP_COMMAND_RECEIVER_TAG
) { EmptyCommand() }
}
@Test
- fun moveCloserToTransfer_chipDisplayWithCorrectState() {
+ fun sender_moveCloserToTransfer_chipDisplayWithCorrectState() {
commandRegistry.onShellCommand(pw, getMoveCloserToTransferCommand())
- verify(mediaTttChipController).displayChip(any(MoveCloserToTransfer::class.java))
+ verify(mediaTttChipControllerSender).displayChip(any(MoveCloserToTransfer::class.java))
}
@Test
- fun transferInitiated_chipDisplayWithCorrectState() {
+ fun sender_transferInitiated_chipDisplayWithCorrectState() {
commandRegistry.onShellCommand(pw, getTransferInitiatedCommand())
- verify(mediaTttChipController).displayChip(any(TransferInitiated::class.java))
+ verify(mediaTttChipControllerSender).displayChip(any(TransferInitiated::class.java))
}
@Test
- fun transferSucceeded_chipDisplayWithCorrectState() {
+ fun sender_transferSucceeded_chipDisplayWithCorrectState() {
commandRegistry.onShellCommand(pw, getTransferSucceededCommand())
- verify(mediaTttChipController).displayChip(any(TransferSucceeded::class.java))
+ verify(mediaTttChipControllerSender).displayChip(any(TransferSucceeded::class.java))
}
@Test
- fun removeCommand_chipRemoved() {
- commandRegistry.onShellCommand(pw, arrayOf(REMOVE_CHIP_COMMAND_TAG))
+ fun sender_removeCommand_chipRemoved() {
+ commandRegistry.onShellCommand(pw, arrayOf(REMOVE_CHIP_COMMAND_SENDER_TAG))
- verify(mediaTttChipController).removeChip()
+ verify(mediaTttChipControllerSender).removeChip()
+ }
+
+ @Test
+ fun receiver_addCommand_chipAdded() {
+ commandRegistry.onShellCommand(pw, arrayOf(ADD_CHIP_COMMAND_RECEIVER_TAG))
+
+ verify(mediaTttChipControllerReceiver).displayChip(any(ChipStateReceiver::class.java))
+ }
+
+ @Test
+ fun receiver_removeCommand_chipRemoved() {
+ commandRegistry.onShellCommand(pw, arrayOf(REMOVE_CHIP_COMMAND_RECEIVER_TAG))
+
+ verify(mediaTttChipControllerReceiver).removeChip()
}
private fun getMoveCloserToTransferCommand(): Array<String> =
arrayOf(
- ADD_CHIP_COMMAND_TAG,
+ ADD_CHIP_COMMAND_SENDER_TAG,
DEVICE_NAME,
MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME
)
private fun getTransferInitiatedCommand(): Array<String> =
arrayOf(
- ADD_CHIP_COMMAND_TAG,
+ ADD_CHIP_COMMAND_SENDER_TAG,
DEVICE_NAME,
TRANSFER_INITIATED_COMMAND_NAME
)
private fun getTransferSucceededCommand(): Array<String> =
arrayOf(
- ADD_CHIP_COMMAND_TAG,
+ ADD_CHIP_COMMAND_SENDER_TAG,
DEVICE_NAME,
TRANSFER_SUCCEEDED_COMMAND_NAME
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
new file mode 100644
index 0000000..927ca7a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.taptotransfer.common
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.Icon
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowManager
+import android.widget.ImageView
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class MediaTttChipControllerCommonTest : SysuiTestCase() {
+ private lateinit var controllerCommon: MediaTttChipControllerCommon<MediaTttChipState>
+
+ private lateinit var appIconDrawable: Drawable
+ @Mock
+ private lateinit var windowManager: WindowManager
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ appIconDrawable = Icon.createWithResource(context, R.drawable.ic_cake).loadDrawable(context)
+ controllerCommon = TestControllerCommon(context, windowManager)
+ }
+
+ @Test
+ fun displayChip_chipAdded() {
+ controllerCommon.displayChip(getState())
+
+ verify(windowManager).addView(any(), any())
+ }
+
+ @Test
+ fun displayChip_twice_chipNotAddedTwice() {
+ controllerCommon.displayChip(getState())
+ reset(windowManager)
+
+ controllerCommon.displayChip(getState())
+ verify(windowManager, never()).addView(any(), any())
+ }
+
+ @Test
+ fun removeChip_chipRemoved() {
+ // First, add the chip
+ controllerCommon.displayChip(getState())
+
+ // Then, remove it
+ controllerCommon.removeChip()
+
+ verify(windowManager).removeView(any())
+ }
+
+ @Test
+ fun removeChip_noAdd_viewNotRemoved() {
+ controllerCommon.removeChip()
+
+ verify(windowManager, never()).removeView(any())
+ }
+
+ @Test
+ fun setIcon_viewHasIconAndContentDescription() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+ val drawable = Icon.createWithResource(context, R.drawable.ic_cake).loadDrawable(context)
+ val contentDescription = "test description"
+
+ controllerCommon.setIcon(MediaTttChipState(drawable, contentDescription), chipView)
+
+ assertThat(chipView.getAppIconView().drawable).isEqualTo(drawable)
+ assertThat(chipView.getAppIconView().contentDescription).isEqualTo(contentDescription)
+ }
+
+ private fun getState() = MediaTttChipState(appIconDrawable, APP_ICON_CONTENT_DESCRIPTION)
+
+ private fun getChipView(): ViewGroup {
+ val viewCaptor = ArgumentCaptor.forClass(View::class.java)
+ verify(windowManager).addView(viewCaptor.capture(), any())
+ return viewCaptor.value as ViewGroup
+ }
+
+ private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
+
+ inner class TestControllerCommon(
+ context: Context,
+ windowManager: WindowManager
+ ) : MediaTttChipControllerCommon<MediaTttChipState>(
+ context, windowManager, R.layout.media_ttt_chip
+ ) {
+ override fun updateChipView(chipState: MediaTttChipState, currentChipView: ViewGroup) {
+ }
+ }
+}
+
+private const val APP_ICON_CONTENT_DESCRIPTION = "Content description"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
new file mode 100644
index 0000000..afaab80
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.taptotransfer.receiver
+
+import android.graphics.drawable.Icon
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowManager
+import android.widget.ImageView
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class MediaTttChipControllerReceiverTest : SysuiTestCase() {
+ private lateinit var controllerReceiver: MediaTttChipControllerReceiver
+
+ @Mock
+ private lateinit var windowManager: WindowManager
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ controllerReceiver = MediaTttChipControllerReceiver(context, windowManager)
+ }
+
+ @Test
+ fun displayChip_chipContainsIcon() {
+ val drawable = Icon.createWithResource(context, R.drawable.ic_cake).loadDrawable(context)
+ val contentDescription = "Test description"
+
+ controllerReceiver.displayChip(ChipStateReceiver(drawable, contentDescription))
+
+ assertThat(getChipView().getAppIconView().drawable).isEqualTo(drawable)
+ assertThat(getChipView().getAppIconView().contentDescription).isEqualTo(contentDescription)
+ }
+
+ private fun getChipView(): ViewGroup {
+ val viewCaptor = ArgumentCaptor.forClass(View::class.java)
+ Mockito.verify(windowManager).addView(viewCaptor.capture(), any())
+ return viewCaptor.value as ViewGroup
+ }
+
+ private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttChipControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
similarity index 67%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttChipControllerTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
index 8749917..caef5b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttChipControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
@@ -14,10 +14,13 @@
* limitations under the License.
*/
-package com.android.systemui.media.taptotransfer
+package com.android.systemui.media.taptotransfer.sender
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.Icon
import android.view.View
import android.view.WindowManager
+import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.test.filters.SmallTest
@@ -32,20 +35,19 @@
import org.junit.Test
import org.mockito.ArgumentCaptor
import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import java.util.concurrent.Future
@SmallTest
-class MediaTttChipControllerTest : SysuiTestCase() {
-
+class MediaTttChipControllerSenderTest : SysuiTestCase() {
+ private lateinit var appIconDrawable: Drawable
private lateinit var fakeMainClock: FakeSystemClock
private lateinit var fakeMainExecutor: FakeExecutor
private lateinit var fakeBackgroundClock: FakeSystemClock
private lateinit var fakeBackgroundExecutor: FakeExecutor
- private lateinit var mediaTttChipController: MediaTttChipController
+ private lateinit var controllerSender: MediaTttChipControllerSender
@Mock
private lateinit var windowManager: WindowManager
@@ -53,68 +55,39 @@
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ appIconDrawable = Icon.createWithResource(context, R.drawable.ic_cake).loadDrawable(context)
fakeMainClock = FakeSystemClock()
fakeMainExecutor = FakeExecutor(fakeMainClock)
fakeBackgroundClock = FakeSystemClock()
fakeBackgroundExecutor = FakeExecutor(fakeBackgroundClock)
- mediaTttChipController = MediaTttChipController(
+ controllerSender = MediaTttChipControllerSender(
context, windowManager, fakeMainExecutor, fakeBackgroundExecutor
)
}
@Test
- fun displayChip_chipAdded() {
- mediaTttChipController.displayChip(MoveCloserToTransfer(DEVICE_NAME))
-
- verify(windowManager).addView(any(), any())
- }
-
- @Test
- fun displayChip_twice_chipNotAddedTwice() {
- mediaTttChipController.displayChip(MoveCloserToTransfer(DEVICE_NAME))
- reset(windowManager)
-
- mediaTttChipController.displayChip(MoveCloserToTransfer(DEVICE_NAME))
- verify(windowManager, never()).addView(any(), any())
- }
-
- @Test
- fun removeChip_chipRemoved() {
- // First, add the chip
- mediaTttChipController.displayChip(MoveCloserToTransfer(DEVICE_NAME))
-
- // Then, remove it
- mediaTttChipController.removeChip()
-
- verify(windowManager).removeView(any())
- }
-
- @Test
- fun removeChip_noAdd_viewNotRemoved() {
- mediaTttChipController.removeChip()
-
- verify(windowManager, never()).removeView(any())
- }
-
- @Test
- fun moveCloserToTransfer_chipTextContainsDeviceName_noLoadingIcon_noUndo() {
- mediaTttChipController.displayChip(MoveCloserToTransfer(DEVICE_NAME))
+ fun moveCloserToTransfer_appIcon_chipTextContainsDeviceName_noLoadingIcon_noUndo() {
+ controllerSender.displayChip(moveCloserToTransfer())
val chipView = getChipView()
+ assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable)
+ assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC)
assertThat(chipView.getChipText()).contains(DEVICE_NAME)
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
}
@Test
- fun transferInitiated_futureNotResolvedYet_loadingIcon_noUndo() {
+ fun transferInitiated_futureNotResolvedYet_appIcon_loadingIcon_noUndo() {
val future: SettableFuture<Runnable?> = SettableFuture.create()
- mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, future))
+ controllerSender.displayChip(transferInitiated(future))
// Don't resolve the future in any way and don't run our executors
// Assert we're still in the loading state
val chipView = getChipView()
+ assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable)
+ assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC)
assertThat(chipView.getChipText()).contains(DEVICE_NAME)
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -125,7 +98,7 @@
val future: SettableFuture<Runnable?> = SettableFuture.create()
val undoRunnable = Runnable { }
- mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, future))
+ controllerSender.displayChip(transferInitiated(future))
future.set(undoRunnable)
fakeBackgroundExecutor.advanceClockToLast()
@@ -146,7 +119,7 @@
fun transferInitiated_futureCancelled_chipRemoved() {
val future: SettableFuture<Runnable?> = SettableFuture.create()
- mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, future))
+ controllerSender.displayChip(transferInitiated(future))
future.cancel(true)
fakeBackgroundExecutor.advanceClockToLast()
@@ -163,7 +136,7 @@
@Test
fun transferInitiated_futureNotResolvedAfterTimeout_chipRemoved() {
val future: SettableFuture<Runnable?> = SettableFuture.create()
- mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, future))
+ controllerSender.displayChip(transferInitiated(future))
// We won't set anything on the future, but we will still run the executors so that we're
// waiting on the future resolving. If we have a bug in our code, then this test will time
@@ -180,22 +153,29 @@
}
@Test
- fun transferSucceededNullUndoRunnable_chipTextContainsDeviceName_noLoadingIcon_noUndo() {
- mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME, undoRunnable = null))
+ fun transferSucceeded_appIcon_chipTextContainsDeviceName_noLoadingIcon() {
+ controllerSender.displayChip(transferSucceeded())
val chipView = getChipView()
+ assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable)
+ assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC)
assertThat(chipView.getChipText()).contains(DEVICE_NAME)
assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
+ }
+
+ @Test
+ fun transferSucceededNullUndoRunnable_noUndo() {
+ controllerSender.displayChip(transferSucceeded(undoRunnable = null))
+
+ val chipView = getChipView()
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
}
@Test
- fun transferSucceededWithUndoRunnable_chipTextContainsDeviceName_noLoadingIcon_undoWithClick() {
- mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME) { })
+ fun transferSucceededWithUndoRunnable_undoWithClick() {
+ controllerSender.displayChip(transferSucceeded { })
val chipView = getChipView()
- assertThat(chipView.getChipText()).contains(DEVICE_NAME)
- assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
assertThat(chipView.getUndoButton().hasOnClickListeners()).isTrue()
}
@@ -205,7 +185,7 @@
var runnableRun = false
val runnable = Runnable { runnableRun = true }
- mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME, runnable))
+ controllerSender.displayChip(transferSucceeded(undoRunnable = runnable))
getChipView().getUndoButton().performClick()
assertThat(runnableRun).isTrue()
@@ -213,36 +193,38 @@
@Test
fun changeFromCloserToTransferToTransferInitiated_loadingIconAppears() {
- mediaTttChipController.displayChip(MoveCloserToTransfer(DEVICE_NAME))
- mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, TEST_FUTURE))
+ controllerSender.displayChip(moveCloserToTransfer())
+ controllerSender.displayChip(transferInitiated())
assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
}
@Test
fun changeFromTransferInitiatedToTransferSucceeded_loadingIconDisappears() {
- mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, TEST_FUTURE))
- mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME))
+ controllerSender.displayChip(transferInitiated())
+ controllerSender.displayChip(transferSucceeded())
assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.GONE)
}
@Test
fun changeFromTransferInitiatedToTransferSucceeded_undoButtonAppears() {
- mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, TEST_FUTURE))
- mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME) { })
+ controllerSender.displayChip(transferInitiated())
+ controllerSender.displayChip(transferSucceeded { })
assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.VISIBLE)
}
@Test
fun changeFromTransferSucceededToMoveCloser_undoButtonDisappears() {
- mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME))
- mediaTttChipController.displayChip(MoveCloserToTransfer(DEVICE_NAME))
+ controllerSender.displayChip(transferSucceeded())
+ controllerSender.displayChip(moveCloserToTransfer())
assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.GONE)
}
+ private fun LinearLayout.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
+
private fun LinearLayout.getChipText(): String =
(this.requireViewById<TextView>(R.id.text)).text as String
@@ -256,9 +238,24 @@
verify(windowManager).addView(viewCaptor.capture(), any())
return viewCaptor.value as LinearLayout
}
+
+ /** Helper method providing default parameters to not clutter up the tests. */
+ private fun moveCloserToTransfer() =
+ MoveCloserToTransfer(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME)
+
+ /** Helper method providing default parameters to not clutter up the tests. */
+ private fun transferInitiated(
+ future: Future<Runnable?> = TEST_FUTURE
+ ) = TransferInitiated(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME, future)
+
+ /** Helper method providing default parameters to not clutter up the tests. */
+ private fun transferSucceeded(
+ undoRunnable: Runnable? = null
+ ) = TransferSucceeded(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME, undoRunnable)
}
private const val DEVICE_NAME = "My Tablet"
+private const val APP_ICON_CONTENT_DESC = "Content description"
// Use a settable future that hasn't yet been set so that we don't immediately switch to the success
// state.
private val TEST_FUTURE: SettableFuture<Runnable?> = SettableFuture.create()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
new file mode 100644
index 0000000..55c51b2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+
+import static junit.framework.TestCase.assertEquals;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.content.pm.PackageManager;
+import android.hardware.SensorPrivacyManager;
+import android.os.Handler;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.DeviceStateRotationLockSettingController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.wrapper.RotationPolicyWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class RotationLockTileTest extends SysuiTestCase {
+
+ private static final String PACKAGE_NAME = "package_name";
+ private static final String[] DEFAULT_SETTINGS = new String[]{
+ "0:0",
+ "1:2"
+ };
+
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private ActivityStarter mActivityStarter;
+ @Mock
+ private QSTileHost mHost;
+ @Mock
+ private MetricsLogger mMetricsLogger;
+ @Mock
+ private StatusBarStateController mStatusBarStateController;
+ @Mock
+ private QSLogger mQSLogger;
+ @Mock
+ private SensorPrivacyManager mPrivacyManager;
+ @Mock
+ private BatteryController mBatteryController;
+ @Mock
+ DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
+ @Mock
+ RotationPolicyWrapper mRotationPolicyWrapper;
+
+ private RotationLockController mController;
+ private TestableLooper mTestableLooper;
+ private RotationLockTile mLockTile;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mTestableLooper = TestableLooper.get(this);
+
+ when(mHost.getContext()).thenReturn(mContext);
+ when(mHost.getUserContext()).thenReturn(mContext);
+
+ mController = new RotationLockControllerImpl(mRotationPolicyWrapper,
+ mDeviceStateRotationLockSettingController, DEFAULT_SETTINGS);
+
+ mLockTile = new RotationLockTile(
+ mHost,
+ mTestableLooper.getLooper(),
+ new Handler(mTestableLooper.getLooper()),
+ new FalsingManagerFake(),
+ mMetricsLogger,
+ mStatusBarStateController,
+ mActivityStarter,
+ mQSLogger,
+ mController,
+ mPrivacyManager,
+ mBatteryController,
+ new FakeSettings()
+ );
+
+ mLockTile.initialize();
+
+ // We are not setting the mocks to listening, so we trigger a first refresh state to
+ // set the initial state
+ mLockTile.refreshState();
+
+ mTestableLooper.processAllMessages();
+
+ mContext.setMockPackageManager(mPackageManager);
+ doReturn(PACKAGE_NAME).when(mPackageManager).getRotationResolverPackageName();
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission(
+ Manifest.permission.CAMERA, PACKAGE_NAME);
+
+ when(mBatteryController.isPowerSave()).thenReturn(false);
+ when(mPrivacyManager.isSensorPrivacyEnabled(CAMERA)).thenReturn(false);
+ enableAutoRotation();
+ enableCameraBasedRotation();
+
+ mLockTile.refreshState();
+ mTestableLooper.processAllMessages();
+ }
+
+ @Test
+ public void testSecondaryString_cameraRotateOn_returnsFaceBased() {
+ assertEquals(mContext.getString(R.string.rotation_lock_camera_rotation_on),
+ mLockTile.getState().secondaryLabel.toString());
+ }
+
+ @Test
+ public void testSecondaryString_rotateOff_isEmpty() {
+ disableAutoRotation();
+
+ mLockTile.refreshState();
+ mTestableLooper.processAllMessages();
+
+ assertEquals("", mLockTile.getState().secondaryLabel.toString());
+ }
+
+ @Test
+ public void testSecondaryString_cameraRotateOff_isEmpty() {
+ disableCameraBasedRotation();
+
+ mLockTile.refreshState();
+ mTestableLooper.processAllMessages();
+
+ assertEquals("", mLockTile.getState().secondaryLabel.toString());
+ }
+
+ @Test
+ public void testSecondaryString_powerSaveEnabled_isEmpty() {
+ when(mBatteryController.isPowerSave()).thenReturn(true);
+
+ mLockTile.refreshState();
+ mTestableLooper.processAllMessages();
+
+ assertEquals("", mLockTile.getState().secondaryLabel.toString());
+ }
+
+ @Test
+ public void testSecondaryString_cameraDisabled_isEmpty() {
+ when(mPrivacyManager.isSensorPrivacyEnabled(CAMERA)).thenReturn(true);
+
+ mLockTile.refreshState();
+ mTestableLooper.processAllMessages();
+
+ assertEquals("", mLockTile.getState().secondaryLabel.toString());
+ }
+
+ @Test
+ public void testSecondaryString_noCameraPermission_isEmpty() {
+ doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
+ Manifest.permission.CAMERA, PACKAGE_NAME);
+
+ mLockTile.refreshState();
+ mTestableLooper.processAllMessages();
+
+ assertEquals("", mLockTile.getState().secondaryLabel.toString());
+ }
+
+ private void enableAutoRotation() {
+ when(mRotationPolicyWrapper.isRotationLocked()).thenReturn(false);
+ }
+
+ private void disableAutoRotation() {
+ when(mRotationPolicyWrapper.isRotationLocked()).thenReturn(true);
+ }
+
+ private void enableCameraBasedRotation() {
+ when(mRotationPolicyWrapper.isCameraRotationEnabled()).thenReturn(true);
+ }
+
+ private void disableCameraBasedRotation() {
+ when(mRotationPolicyWrapper.isCameraRotationEnabled()).thenReturn(false);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
index c5dc2b4..3ddff49 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
@@ -120,7 +120,7 @@
private NotifFilter captureFilter(MediaCoordinator coordinator) {
ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
coordinator.attach(mNotifPipeline);
- verify(mNotifPipeline).addFinalizeFilter(filterCaptor.capture());
+ verify(mNotifPipeline).addPreGroupFilter(filterCaptor.capture());
return filterCaptor.getValue();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
index 3c84c01..d3c1dc9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
@@ -32,7 +32,6 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -44,7 +43,6 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.HashSet;
@@ -59,8 +57,6 @@
private Runnable mRoundnessCallback = mock(Runnable.class);
private ExpandableNotificationRow mFirst;
private ExpandableNotificationRow mSecond;
- @Mock
- private FeatureFlags mFeatureFlags;
private float mSmallRadiusRatio;
@Before
@@ -70,8 +66,7 @@
mSmallRadiusRatio = resources.getDimension(R.dimen.notification_corner_radius_small)
/ resources.getDimension(R.dimen.notification_corner_radius);
mRoundnessManager = new NotificationRoundnessManager(
- new NotificationSectionsFeatureManager(new DeviceConfigProxy(), mContext),
- mFeatureFlags);
+ new NotificationSectionsFeatureManager(new DeviceConfigProxy(), mContext));
allowTestableLooperAsMainThread();
NotificationTestHelper testHelper = new NotificationTestHelper(
mContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index e4db072..a14ea54 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -17,11 +17,12 @@
package com.android.systemui.statusbar.phone;
import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.when;
import android.content.res.Resources;
@@ -32,14 +33,19 @@
import androidx.test.runner.AndroidJUnit4;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
+import com.android.systemui.unfold.FoldAodAnimationController;
+import com.android.systemui.unfold.SysUIUnfoldComponent;
import org.junit.Assert;
import org.junit.Before;
@@ -48,10 +54,11 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Optional;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DozeParametersTest extends SysuiTestCase {
-
private DozeParameters mDozeParameters;
@Mock Resources mResources;
@@ -63,10 +70,37 @@
@Mock private FeatureFlags mFeatureFlags;
@Mock private DumpManager mDumpManager;
@Mock private ScreenOffAnimationController mScreenOffAnimationController;
+ @Mock private FoldAodAnimationController mFoldAodAnimationController;
+ @Mock private SysUIUnfoldComponent mSysUIUnfoldComponent;
+ @Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+ @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock private StatusBarStateController mStatusBarStateController;
+ @Mock private ConfigurationController mConfigurationController;
+
+ /**
+ * The current value of PowerManager's dozeAfterScreenOff property.
+ *
+ * This property controls whether System UI is controlling the screen off animation. If it's
+ * false (PowerManager should not doze after screen off) then System UI is controlling the
+ * animation. If true, we're not controlling it and PowerManager will doze immediately.
+ */
+ private boolean mPowerManagerDozeAfterScreenOff;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+
+ // Save the current value set for dozeAfterScreenOff so we can make assertions. This method
+ // is only called if the value changes, which makes it difficult to check that it was set
+ // correctly in tests.
+ doAnswer(invocation -> {
+ mPowerManagerDozeAfterScreenOff = invocation.getArgument(0);
+ return mPowerManagerDozeAfterScreenOff;
+ }).when(mPowerManager).setDozeAfterScreenOff(anyBoolean());
+
+ when(mSysUIUnfoldComponent.getFoldAodAnimationController())
+ .thenReturn(mFoldAodAnimationController);
+
mDozeParameters = new DozeParameters(
mResources,
mAmbientDisplayConfiguration,
@@ -76,23 +110,31 @@
mTunerService,
mDumpManager,
mFeatureFlags,
- mScreenOffAnimationController
+ mScreenOffAnimationController,
+ Optional.of(mSysUIUnfoldComponent),
+ mUnlockedScreenOffAnimationController,
+ mKeyguardUpdateMonitor,
+ mConfigurationController,
+ mStatusBarStateController
);
- }
- @Test
- public void testSetControlScreenOffAnimation_setsDozeAfterScreenOff_false() {
- mDozeParameters.setControlScreenOffAnimation(true);
- reset(mPowerManager);
- mDozeParameters.setControlScreenOffAnimation(false);
- verify(mPowerManager).setDozeAfterScreenOff(eq(true));
+
+ when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)).thenReturn(true);
+ setAodEnabledForTest(true);
+ setShouldControlUnlockedScreenOffForTest(true);
+ setDisplayNeedsBlankingForTest(false);
}
@Test
- public void testSetControlScreenOffAnimation_setsDozeAfterScreenOff_true() {
- mDozeParameters.setControlScreenOffAnimation(false);
- reset(mPowerManager);
+ public void testSetControlScreenOffAnimation_setsDozeAfterScreenOff_correctly() {
+ // If we want to control screen off, we do NOT want PowerManager to doze after screen off.
+ // Obviously.
mDozeParameters.setControlScreenOffAnimation(true);
- verify(mPowerManager).setDozeAfterScreenOff(eq(false));
+ assertFalse(mPowerManagerDozeAfterScreenOff);
+
+ // If we don't want to control screen off, PowerManager is free to doze after screen off if
+ // that's what'll make it happy.
+ mDozeParameters.setControlScreenOffAnimation(false);
+ assertTrue(mPowerManagerDozeAfterScreenOff);
}
@Test
@@ -121,35 +163,124 @@
assertThat(mDozeParameters.getAlwaysOn()).isFalse();
}
+ /**
+ * PowerManager.setDozeAfterScreenOff(true) means we are not controlling screen off, and calling
+ * it with false means we are. Confusing, but sure - make sure that we call PowerManager with
+ * the correct value depending on whether we want to control screen off.
+ */
@Test
public void testControlUnlockedScreenOffAnimation_dozeAfterScreenOff_false() {
- when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
- mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "1");
- when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)).thenReturn(true);
- when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true);
+ // If AOD is disabled, we shouldn't want to control screen off. Also, let's double check
+ // that when that value is updated, we called through to PowerManager.
+ setAodEnabledForTest(false);
+ assertFalse(mDozeParameters.shouldControlScreenOff());
+ assertTrue(mPowerManagerDozeAfterScreenOff);
- // Trigger the setter for the current value.
- mDozeParameters.setControlScreenOffAnimation(mDozeParameters.shouldControlScreenOff());
-
- // We should have asked power manager not to doze after screen off no matter what, since
- // we're animating and controlling screen off.
- verify(mPowerManager).setDozeAfterScreenOff(eq(false));
+ // And vice versa...
+ setAodEnabledForTest(true);
+ assertTrue(mDozeParameters.shouldControlScreenOff());
+ assertFalse(mPowerManagerDozeAfterScreenOff);
}
@Test
public void testControlUnlockedScreenOffAnimationDisabled_dozeAfterScreenOff() {
- when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
- mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "1");
+ setShouldControlUnlockedScreenOffForTest(true);
when(mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)).thenReturn(false);
assertFalse(mDozeParameters.shouldControlUnlockedScreenOff());
// Trigger the setter for the current value.
mDozeParameters.setControlScreenOffAnimation(mDozeParameters.shouldControlScreenOff());
+ assertFalse(mDozeParameters.shouldControlScreenOff());
+ }
- // We should have asked power manager to doze only if we're not controlling screen off
- // normally.
- verify(mPowerManager).setDozeAfterScreenOff(
- eq(!mDozeParameters.shouldControlScreenOff()));
+ @Test
+ public void propagatesAnimateScreenOff_noAlwaysOn() {
+ setAodEnabledForTest(false);
+ setDisplayNeedsBlankingForTest(false);
+
+ mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(false);
+ assertFalse(mDozeParameters.shouldControlScreenOff());
+ }
+
+ @Test
+ public void propagatesAnimateScreenOff_alwaysOn() {
+ setAodEnabledForTest(true);
+ setDisplayNeedsBlankingForTest(false);
+ setShouldControlUnlockedScreenOffForTest(false);
+
+ // Take over when the keyguard is visible.
+ mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(true);
+ assertTrue(mDozeParameters.shouldControlScreenOff());
+
+ // Do not animate screen-off when keyguard isn't visible.
+ mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(false);
+ assertFalse(mDozeParameters.shouldControlScreenOff());
+ }
+
+
+ @Test
+ public void neverAnimateScreenOff_whenNotSupported() {
+ setDisplayNeedsBlankingForTest(true);
+
+ // Never animate if display doesn't support it.
+ mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(true);
+ assertFalse(mDozeParameters.shouldControlScreenOff());
+ mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(false);
+ assertFalse(mDozeParameters.shouldControlScreenOff());
+ }
+
+
+ @Test
+ public void controlScreenOffTrueWhenKeyguardNotShowingAndControlUnlockedScreenOff() {
+ setShouldControlUnlockedScreenOffForTest(true);
+
+ // Tell doze that keyguard is not visible.
+ mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(
+ false /* showing */);
+
+ // Since we're controlling the unlocked screen off animation, verify that we've asked to
+ // control the screen off animation despite being unlocked.
+ assertTrue(mDozeParameters.shouldControlScreenOff());
+ }
+
+
+ @Test
+ public void keyguardVisibility_changesControlScreenOffAnimation() {
+ setShouldControlUnlockedScreenOffForTest(false);
+
+ mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(false);
+ assertFalse(mDozeParameters.shouldControlScreenOff());
+ mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(true);
+ assertTrue(mDozeParameters.shouldControlScreenOff());
+ }
+
+ @Test
+ public void keyguardVisibility_changesControlScreenOffAnimation_respectsUnlockedScreenOff() {
+ setShouldControlUnlockedScreenOffForTest(true);
+
+ // Even if the keyguard is gone, we should control screen off if we can control unlocked
+ // screen off.
+ mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(false);
+ assertTrue(mDozeParameters.shouldControlScreenOff());
+
+ mDozeParameters.mKeyguardVisibilityCallback.onKeyguardVisibilityChanged(true);
+ assertTrue(mDozeParameters.shouldControlScreenOff());
+ }
+
+ private void setDisplayNeedsBlankingForTest(boolean needsBlanking) {
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_displayBlanksAfterDoze)).thenReturn(
+ needsBlanking);
+ }
+
+ private void setAodEnabledForTest(boolean enabled) {
+ when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(enabled);
+ mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "");
+ }
+
+ private void setShouldControlUnlockedScreenOffForTest(boolean shouldControl) {
+ when(mUnlockedScreenOffAnimationController.shouldPlayUnlockedScreenOffAnimation())
+ .thenReturn(shouldControl);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 1182695..1827c7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -62,6 +62,7 @@
private float mPanelExpansion;
private int mKeyguardStatusBarHeaderHeight;
private int mKeyguardStatusHeight;
+ private int mUserSwitchHeight;
private float mDark;
private float mQsExpansion;
private int mCutoutTopInset = 0;
@@ -264,8 +265,7 @@
@Test
public void clockPositionedDependingOnMarginInSplitShade() {
- when(mResources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin))
- .thenReturn(400);
+ setSplitShadeTopMargin(400);
mClockPositionAlgorithm.loadDimens(mResources);
givenLockScreen();
mIsSplitShade = true;
@@ -291,6 +291,32 @@
}
@Test
+ public void notifPaddingAccountsForMultiUserSwitcherInSplitShade() {
+ setSplitShadeTopMargin(100);
+ mUserSwitchHeight = 150;
+ mClockPositionAlgorithm.loadDimens(mResources);
+ givenLockScreen();
+ mIsSplitShade = true;
+ // WHEN the position algorithm is run
+ positionClock();
+ // THEN the notif padding is split shade top margin + user switch height
+ assertThat(mClockPosition.stackScrollerPadding).isEqualTo(250);
+ }
+
+ @Test
+ public void clockDoesntAccountForMultiUserSwitcherInSplitShade() {
+ setSplitShadeTopMargin(100);
+ mUserSwitchHeight = 150;
+ mClockPositionAlgorithm.loadDimens(mResources);
+ givenLockScreen();
+ mIsSplitShade = true;
+ // WHEN the position algorithm is run
+ positionClock();
+ // THEN clockY = split shade top margin
+ assertThat(mClockPosition.clockY).isEqualTo(100);
+ }
+
+ @Test
public void notifPaddingExpandedAlignedWithClockInSplitShadeMode() {
givenLockScreen();
mIsSplitShade = true;
@@ -495,6 +521,11 @@
assertThat(mClockPosition.clockY).isEqualTo(mCutoutTopInset);
}
+ private void setSplitShadeTopMargin(int value) {
+ when(mResources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin))
+ .thenReturn(value);
+ }
+
private void givenHighestBurnInOffset() {
when(BurnInHelperKt.getBurnInOffset(anyInt(), anyBoolean())).then(returnsFirstArg());
}
@@ -529,7 +560,7 @@
mKeyguardStatusBarHeaderHeight,
mPanelExpansion,
mKeyguardStatusHeight,
- 0 /* userSwitchHeight */,
+ mUserSwitchHeight,
0 /* userSwitchPreferredY */,
mDark,
ZERO_DRAG,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
index a8a33da..24a56bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
@@ -21,6 +21,7 @@
import android.testing.TestableLooper.RunWithLooper
import android.view.View
import androidx.test.filters.SmallTest
+import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.WakefulnessLifecycle
@@ -59,6 +60,8 @@
private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
@Mock
private lateinit var statusBarStateController: StatusBarStateControllerImpl
+ @Mock
+ private lateinit var interactionJankMonitor: InteractionJankMonitor
@Before
fun setUp() {
@@ -71,7 +74,8 @@
dagger.Lazy<KeyguardViewMediator> { keyguardViewMediator },
keyguardStateController,
dagger.Lazy<DozeParameters> { dozeParameters },
- globalSettings
+ globalSettings,
+ interactionJankMonitor
)
controller.initialize(statusbar, lightRevealScrim)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
index 30717f4..db7b2f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
@@ -225,6 +225,11 @@
}
@Override
+ public boolean isCameraRotationEnabled() {
+ throw new AssertionError("Not implemented");
+ }
+
+ @Override
public void registerRotationPolicyListener(RotationPolicy.RotationPolicyListener listener,
int userHandle) {
throw new AssertionError("Not implemented");
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
index be836d4..087f2e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
@@ -15,9 +15,7 @@
package com.android.systemui.statusbar.policy;
import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -27,18 +25,25 @@
import android.location.LocationManager;
import android.os.Handler;
import android.os.UserHandle;
+import android.provider.DeviceConfig;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import androidx.test.filters.SmallTest;
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.systemui.BootCompleteCache;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.appops.AppOpItem;
import com.android.systemui.appops.AppOpsController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback;
+import com.android.systemui.util.DeviceConfigProxy;
+import com.android.systemui.util.DeviceConfigProxyFake;
+
+import com.google.common.collect.ImmutableList;
import org.junit.Before;
import org.junit.Test;
@@ -53,6 +58,7 @@
private LocationControllerImpl mLocationController;
private TestableLooper mTestableLooper;
+ private DeviceConfigProxy mDeviceConfigProxy;
@Mock private AppOpsController mAppOpsController;
@Mock private UserTracker mUserTracker;
@@ -62,15 +68,17 @@
MockitoAnnotations.initMocks(this);
when(mUserTracker.getUserId()).thenReturn(UserHandle.USER_SYSTEM);
when(mUserTracker.getUserHandle()).thenReturn(UserHandle.SYSTEM);
+ mDeviceConfigProxy = new DeviceConfigProxyFake();
mTestableLooper = TestableLooper.get(this);
- mLocationController = spy(new LocationControllerImpl(mContext,
+ mLocationController = new LocationControllerImpl(mContext,
mAppOpsController,
+ mDeviceConfigProxy,
mTestableLooper.getLooper(),
new Handler(mTestableLooper.getLooper()),
mock(BroadcastDispatcher.class),
mock(BootCompleteCache.class),
- mUserTracker));
+ mUserTracker);
mTestableLooper.processAllMessages();
}
@@ -86,10 +94,13 @@
mLocationController.addCallback(callback);
mLocationController.addCallback(mock(LocationChangeCallback.class));
- doReturn(false).when(mLocationController).areActiveHighPowerLocationRequests();
+ when(mAppOpsController.getActiveAppOps()).thenReturn(ImmutableList.of());
mLocationController.onActiveStateChanged(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0,
"", false);
- doReturn(true).when(mLocationController).areActiveHighPowerLocationRequests();
+ when(mAppOpsController.getActiveAppOps())
+ .thenReturn(ImmutableList.of(
+ new AppOpItem(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0, "",
+ System.currentTimeMillis())));
mLocationController.onActiveStateChanged(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0,
"", true);
@@ -135,7 +146,10 @@
verify(callback, times(2)).onLocationSettingsChanged(anyBoolean());
- doReturn(true).when(mLocationController).areActiveHighPowerLocationRequests();
+ when(mAppOpsController.getActiveAppOps())
+ .thenReturn(ImmutableList.of(
+ new AppOpItem(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0, "",
+ System.currentTimeMillis())));
mLocationController.onActiveStateChanged(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0,
"", true);
@@ -145,6 +159,46 @@
}
@Test
+ public void testCallbackNotified_additionalOps() {
+ LocationChangeCallback callback = mock(LocationChangeCallback.class);
+
+ mLocationController.addCallback(callback);
+
+ mTestableLooper.processAllMessages();
+
+ mLocationController.onReceive(mContext, new Intent(LocationManager.MODE_CHANGED_ACTION));
+
+ mTestableLooper.processAllMessages();
+
+ verify(callback, times(2)).onLocationSettingsChanged(anyBoolean());
+
+ mDeviceConfigProxy.setProperty(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ SystemUiDeviceConfigFlags.PROPERTY_LOCATION_INDICATORS_SMALL_ENABLED,
+ "true",
+ true);
+ mTestableLooper.processAllMessages();
+
+ when(mAppOpsController.getActiveAppOps())
+ .thenReturn(ImmutableList.of(
+ new AppOpItem(AppOpsManager.OP_FINE_LOCATION, 0, "",
+ System.currentTimeMillis())));
+ mLocationController.onActiveStateChanged(AppOpsManager.OP_FINE_LOCATION, 0,
+ "", true);
+
+ mTestableLooper.processAllMessages();
+
+ verify(callback, times(1)).onLocationActiveChanged(true);
+
+ when(mAppOpsController.getActiveAppOps()).thenReturn(ImmutableList.of());
+ mLocationController.onActiveStateChanged(AppOpsManager.OP_FINE_LOCATION, 0,
+ "", false);
+ mTestableLooper.processAllMessages();
+
+ verify(callback, times(1)).onLocationActiveChanged(false);
+ }
+
+ @Test
public void testCallbackRemoved() {
LocationChangeCallback callback = mock(LocationChangeCallback.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeRotationLockController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
index be11024..4f9cb35 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
@@ -51,6 +51,11 @@
}
@Override
+ public boolean isCameraRotationEnabled() {
+ return false;
+ }
+
+ @Override
public void setRotationLockedAtAngle(boolean locked, int rotation) {
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 52a6dc1..e59a3d6 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -193,6 +193,8 @@
private static final int OWN_PROCESS_ID = android.os.Process.myPid();
+ public static final int INVALID_SERVICE_ID = -1;
+
// Each service has an ID. Also provide one for magnification gesture handling
public static final int MAGNIFICATION_GESTURE_HANDLER_ID = 0;
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index 38615fe..72bc850 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -19,6 +19,8 @@
import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;
+import static com.android.server.accessibility.AccessibilityManagerService.INVALID_SERVICE_ID;
+
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
@@ -117,8 +119,7 @@
private final int mDisplayId;
- private static final int INVALID_ID = -1;
- private int mIdOfLastServiceToMagnify = INVALID_ID;
+ private int mIdOfLastServiceToMagnify = INVALID_SERVICE_ID;
private boolean mMagnificationActivated = false;
DisplayMagnification(int displayId) {
@@ -425,7 +426,7 @@
}
final float scale = getScale();
- offsetMagnifiedRegion(scrollX * scale, scrollY * scale, INVALID_ID);
+ offsetMagnifiedRegion(scrollX * scale, scrollY * scale, INVALID_SERVICE_ID);
}
}
@@ -472,7 +473,7 @@
spec.clear();
onMagnificationChangedLocked();
}
- mIdOfLastServiceToMagnify = INVALID_ID;
+ mIdOfLastServiceToMagnify = INVALID_SERVICE_ID;
mForceShowMagnifiableBounds = false;
sendSpecToAnimation(spec, animationCallback);
return changed;
@@ -519,7 +520,7 @@
}
final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY);
sendSpecToAnimation(mCurrentMagnificationSpec, animationCallback);
- if (isMagnifying() && (id != INVALID_ID)) {
+ if (isMagnifying() && (id != INVALID_SERVICE_ID)) {
mIdOfLastServiceToMagnify = id;
mMagnificationInfoChangedCallback.onRequestMagnificationSpec(mDisplayId,
mIdOfLastServiceToMagnify);
@@ -583,7 +584,7 @@
if (updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY)) {
onMagnificationChangedLocked();
}
- if (id != INVALID_ID) {
+ if (id != INVALID_SERVICE_ID) {
mIdOfLastServiceToMagnify = id;
}
sendSpecToAnimation(mCurrentMagnificationSpec, null);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 791da69..a63dd00 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -22,6 +22,8 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;
+import static com.android.server.accessibility.AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID;
+
import android.accessibilityservice.MagnificationConfig;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -240,9 +242,10 @@
* @param config The targeting magnification config
* @param animate {@code true} to animate the transition, {@code false}
* to transition immediately
+ * @param id The ID of the service requesting the change
*/
public void transitionMagnificationConfigMode(int displayId, MagnificationConfig config,
- boolean animate) {
+ boolean animate, int id) {
synchronized (mLock) {
final int targetMode = config.getMode();
final PointF currentBoundsCenter = getCurrentMagnificationBoundsCenterLocked(displayId,
@@ -273,7 +276,7 @@
screenMagnificationController.reset(displayId, false);
windowMagnificationMgr.enableWindowMagnification(displayId,
scale, magnificationCenter.x, magnificationCenter.y,
- animate ? STUB_ANIMATION_CALLBACK : null);
+ animate ? STUB_ANIMATION_CALLBACK : null, id);
} else if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) {
windowMagnificationMgr.disableWindowMagnification(displayId, false, null);
if (!screenMagnificationController.isRegistered(displayId)) {
@@ -281,7 +284,7 @@
}
screenMagnificationController.setScaleAndCenter(displayId, scale,
magnificationCenter.x, magnificationCenter.y, animate,
- AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
+ id);
}
}
}
@@ -337,7 +340,7 @@
public void onRequestMagnificationSpec(int displayId, int serviceId) {
final WindowMagnificationManager windowMagnificationManager;
synchronized (mLock) {
- if (serviceId == AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID) {
+ if (serviceId == MAGNIFICATION_GESTURE_HANDLER_ID) {
return;
}
updateMagnificationButton(displayId, ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
@@ -718,11 +721,12 @@
}
fullScreenMagnificationController.setScaleAndCenter(mDisplayId, mCurrentScale,
mCurrentCenter.x, mCurrentCenter.y, mAnimate,
- AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
+ MAGNIFICATION_GESTURE_HANDLER_ID);
} else {
getWindowMagnificationMgr().enableWindowMagnification(mDisplayId,
mCurrentScale, mCurrentCenter.x,
- mCurrentCenter.y, mAnimate ? STUB_ANIMATION_CALLBACK : null);
+ mCurrentCenter.y, mAnimate ? STUB_ANIMATION_CALLBACK : null,
+ MAGNIFICATION_GESTURE_HANDLER_ID);
}
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java
index 7a525ee..40f77b0 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationProcessor.java
@@ -99,7 +99,7 @@
*/
public boolean setMagnificationConfig(int displayId, @NonNull MagnificationConfig config,
boolean animate, int id) {
- if (transitionModeIfNeeded(displayId, config, animate)) {
+ if (transitionModeIfNeeded(displayId, config, animate, id)) {
return true;
}
@@ -114,7 +114,8 @@
} else if (configMode == MAGNIFICATION_MODE_WINDOW) {
return mController.getWindowMagnificationMgr().enableWindowMagnification(displayId,
config.getScale(), config.getCenterX(), config.getCenterY(),
- animate ? STUB_ANIMATION_CALLBACK : null);
+ animate ? STUB_ANIMATION_CALLBACK : null,
+ id);
}
return false;
}
@@ -136,13 +137,13 @@
* mode when the controlling mode is unchanged or the controlling magnifier is not activated.
*/
private boolean transitionModeIfNeeded(int displayId, MagnificationConfig config,
- boolean animate) {
+ boolean animate, int id) {
int currentMode = getControllingMode(displayId);
if (currentMode == config.getMode()
|| !mController.hasDisableMagnificationCallback(displayId)) {
return false;
}
- mController.transitionMagnificationConfigMode(displayId, config, animate);
+ mController.transitionMagnificationConfigMode(displayId, config, animate, id);
return true;
}
@@ -237,7 +238,8 @@
if (mode == MAGNIFICATION_MODE_FULLSCREEN) {
return mController.getFullScreenMagnificationController().reset(displayId, animate);
} else if (mode == MAGNIFICATION_MODE_WINDOW) {
- return mController.getWindowMagnificationMgr().reset(displayId);
+ return mController.getWindowMagnificationMgr().disableWindowMagnification(displayId,
+ false, animate ? STUB_ANIMATION_CALLBACK : null);
}
return false;
}
@@ -256,11 +258,15 @@
}
/**
- * {@link FullScreenMagnificationController#resetIfNeeded(int, boolean)}
+ * Resets all the magnifiers on all the displays.
+ * Called when the a11y service connection that has changed the current magnification spec is
+ * unbound or the binder died.
+ *
+ * @param connectionId The connection id
*/
- // TODO: support window magnification
public void resetAllIfNeeded(int connectionId) {
mController.getFullScreenMagnificationController().resetAllIfNeeded(connectionId);
+ mController.getWindowMagnificationMgr().resetAllIfNeeded(connectionId);
}
/**
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index 3f6ff25..336f0bb 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -20,6 +20,9 @@
import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK;
import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;
+import static com.android.server.accessibility.AccessibilityManagerService.INVALID_SERVICE_ID;
+import static com.android.server.accessibility.AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -253,7 +256,26 @@
}
mWindowMagnifiers.clear();
}
+ }
+ /**
+ * Resets the window magnifier on all displays that had been controlled by the
+ * specified service connection. Called when the service connection is unbound
+ * or binder died.
+ *
+ * @param connectionId The connection id
+ */
+ public void resetAllIfNeeded(int connectionId) {
+ synchronized (mLock) {
+ for (int i = 0; i < mWindowMagnifiers.size(); i++) {
+ final WindowMagnifier magnifier = mWindowMagnifiers.valueAt(i);
+ if (magnifier != null
+ && magnifier.mEnabled
+ && connectionId == magnifier.getIdOfLastServiceToControl()) {
+ magnifier.disableWindowMagnificationInternal(null);
+ }
+ }
+ }
}
private void resetWindowMagnifiers() {
@@ -310,7 +332,7 @@
public boolean enableWindowMagnification(int displayId, float scale, float centerX,
float centerY) {
return enableWindowMagnification(displayId, scale, centerX, centerY,
- STUB_ANIMATION_CALLBACK);
+ STUB_ANIMATION_CALLBACK, MAGNIFICATION_GESTURE_HANDLER_ID);
}
/**
@@ -324,12 +346,13 @@
* @param centerY The screen-relative Y coordinate around which to center for magnification,
* or {@link Float#NaN} to leave unchanged.
* @param animationCallback Called when the animation result is valid.
+ * @param id The connection ID
* @return {@code true} if the magnification is enabled successfully.
*/
public boolean enableWindowMagnification(int displayId, float scale, float centerX,
- float centerY, @Nullable MagnificationAnimationCallback animationCallback) {
+ float centerY, @Nullable MagnificationAnimationCallback animationCallback, int id) {
return enableWindowMagnification(displayId, scale, centerX, centerY, animationCallback,
- WINDOW_POSITION_AT_CENTER);
+ WINDOW_POSITION_AT_CENTER, id);
}
/**
@@ -348,7 +371,7 @@
public boolean enableWindowMagnification(int displayId, float scale, float centerX,
float centerY, @WindowPosition int windowPosition) {
return enableWindowMagnification(displayId, scale, centerX, centerY,
- STUB_ANIMATION_CALLBACK, windowPosition);
+ STUB_ANIMATION_CALLBACK, windowPosition, MAGNIFICATION_GESTURE_HANDLER_ID);
}
/**
@@ -367,7 +390,7 @@
*/
public boolean enableWindowMagnification(int displayId, float scale, float centerX,
float centerY, @Nullable MagnificationAnimationCallback animationCallback,
- @WindowPosition int windowPosition) {
+ @WindowPosition int windowPosition, int id) {
final boolean enabled;
boolean previousEnabled;
synchronized (mLock) {
@@ -380,7 +403,7 @@
}
previousEnabled = magnifier.mEnabled;
enabled = magnifier.enableWindowMagnificationInternal(scale, centerX, centerY,
- animationCallback, windowPosition);
+ animationCallback, windowPosition, id);
}
if (enabled && !previousEnabled) {
@@ -394,9 +417,10 @@
*
* @param displayId The logical display id.
* @param clear {@true} Clears the state of window magnification.
+ * @return {@code true} if the magnification is turned to be disabled successfully
*/
- void disableWindowMagnification(int displayId, boolean clear) {
- disableWindowMagnification(displayId, clear, STUB_ANIMATION_CALLBACK);
+ boolean disableWindowMagnification(int displayId, boolean clear) {
+ return disableWindowMagnification(displayId, clear, STUB_ANIMATION_CALLBACK);
}
/**
@@ -405,14 +429,15 @@
* @param displayId The logical display id.
* @param clear {@true} Clears the state of window magnification.
* @param animationCallback Called when the animation result is valid.
+ * @return {@code true} if the magnification is turned to be disabled successfully
*/
- void disableWindowMagnification(int displayId, boolean clear,
+ public boolean disableWindowMagnification(int displayId, boolean clear,
MagnificationAnimationCallback animationCallback) {
final boolean disabled;
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null || mConnectionWrapper == null) {
- return;
+ return false;
}
disabled = magnifier.disableWindowMagnificationInternal(animationCallback);
if (clear) {
@@ -423,6 +448,7 @@
if (disabled) {
mCallback.onWindowMagnificationActivationState(displayId, false);
}
+ return disabled;
}
/**
@@ -490,7 +516,7 @@
public float getScale(int displayId) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
- if (magnifier == null) {
+ if (magnifier == null || !magnifier.mEnabled) {
return 1.0f;
}
return magnifier.getScale();
@@ -548,7 +574,7 @@
public float getCenterX(int displayId) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
- if (magnifier == null) {
+ if (magnifier == null || !magnifier.mEnabled) {
return Float.NaN;
}
return magnifier.getCenterX();
@@ -564,7 +590,7 @@
public float getCenterY(int displayId) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
- if (magnifier == null) {
+ if (magnifier == null || !magnifier.mEnabled) {
return Float.NaN;
}
return magnifier.getCenterY();
@@ -581,7 +607,7 @@
public void getMagnificationSourceBounds(int displayId, @NonNull Region outRegion) {
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
- if (magnifier == null) {
+ if (magnifier == null || !magnifier.mEnabled) {
outRegion.setEmpty();
} else {
outRegion.set(magnifier.mSourceBounds);
@@ -590,24 +616,6 @@
}
/**
- * Resets the magnification scale and center.
- *
- * @param displayId The logical display id.
- * @return {@code true} if the magnification spec changed, {@code false} if
- * the spec did not change
- */
- public boolean reset(int displayId) {
- synchronized (mLock) {
- WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
- if (magnifier == null) {
- return false;
- }
- magnifier.reset();
- return true;
- }
- }
-
- /**
* Creates the windowMagnifier based on the specified display and stores it.
*
* @param displayId logical display id.
@@ -722,6 +730,9 @@
/**
* A class manipulates window magnification per display and contains the magnification
* information.
+ * <p>
+ * This class requires to hold the lock when controlling the magnifier.
+ * </p>
*/
private static class WindowMagnifier {
@@ -735,6 +746,8 @@
// The magnified bounds on the screen.
private final Rect mSourceBounds = new Rect();
+ private int mIdOfLastServiceToControl = INVALID_SERVICE_ID;
+
private PointF mMagnificationFrameOffsetRatio = new PointF(0f, 0f);
WindowMagnifier(int displayId, WindowMagnificationManager windowMagnificationManager) {
@@ -745,7 +758,7 @@
@GuardedBy("mLock")
boolean enableWindowMagnificationInternal(float scale, float centerX, float centerY,
@Nullable MagnificationAnimationCallback animationCallback,
- @WindowPosition int windowPosition) {
+ @WindowPosition int windowPosition, int id) {
// Handle defaults. The scale may be NAN when just updating magnification center.
if (Float.isNaN(scale)) {
scale = getScale();
@@ -757,7 +770,7 @@
mMagnificationFrameOffsetRatio.y, animationCallback)) {
mScale = normScale;
mEnabled = true;
-
+ mIdOfLastServiceToControl = id;
return true;
}
return false;
@@ -785,7 +798,7 @@
if (mWindowMagnificationManager.disableWindowMagnificationInternal(
mDisplayId, animationResultCallback)) {
mEnabled = false;
-
+ mIdOfLastServiceToControl = INVALID_SERVICE_ID;
return true;
}
return false;
@@ -813,6 +826,13 @@
mBounds.set(rect);
}
+ /**
+ * Returns the ID of the last service that changed the magnification config.
+ */
+ int getIdOfLastServiceToControl() {
+ return mIdOfLastServiceToControl;
+ }
+
@GuardedBy("mLock")
int pointersInWindow(MotionEvent motionEvent) {
int count = 0;
@@ -840,6 +860,8 @@
@GuardedBy("mLock")
void reset() {
mEnabled = false;
+ mIdOfLastServiceToControl = INVALID_SERVICE_ID;
+ mSourceBounds.setEmpty();
}
@GuardedBy("mLock")
@@ -849,12 +871,12 @@
@GuardedBy("mLock")
float getCenterX() {
- return mEnabled ? mSourceBounds.exactCenterX() : Float.NaN;
+ return mSourceBounds.exactCenterX();
}
@GuardedBy("mLock")
float getCenterY() {
- return mEnabled ? mSourceBounds.exactCenterY() : Float.NaN;
+ return mSourceBounds.exactCenterY();
}
}
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index 637994f..1914164 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -22,7 +22,6 @@
import static android.companion.CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME;
import static android.content.ComponentName.createRelative;
-import static com.android.internal.util.CollectionUtils.filter;
import static com.android.server.companion.CompanionDeviceManagerService.DEBUG;
import static com.android.server.companion.CompanionDeviceManagerService.LOG_TAG;
import static com.android.server.companion.PermissionsUtils.enforcePermissionsForAssociation;
@@ -57,6 +56,7 @@
import java.util.Arrays;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
/**
@@ -124,14 +124,17 @@
private static final int ASSOCIATE_WITHOUT_PROMPT_MAX_PER_TIME_WINDOW = 5;
private static final long ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS = 60 * 60 * 1000; // 60 min;
- private final Context mContext;
- private final CompanionDeviceManagerService mService;
- private final PackageManagerInternal mPackageManager;
+ private final @NonNull Context mContext;
+ private final @NonNull CompanionDeviceManagerService mService;
+ private final @NonNull PackageManagerInternal mPackageManager;
+ private final @NonNull AssociationStore mAssociationStore;
- AssociationRequestsProcessor(CompanionDeviceManagerService service) {
+ AssociationRequestsProcessor(@NonNull CompanionDeviceManagerService service,
+ @NonNull AssociationStore associationStore) {
mContext = service.getContext();
mService = service;
mPackageManager = service.mPackageManagerInternal;
+ mAssociationStore = associationStore;
}
/**
@@ -330,18 +333,24 @@
}
// Throttle frequent associations
- long now = System.currentTimeMillis();
- Set<AssociationInfo> recentAssociations = filter(
- mService.getAssociations(userId, packageName),
- a -> now - a.getTimeApprovedMs() < ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS);
-
- if (recentAssociations.size() >= ASSOCIATE_WITHOUT_PROMPT_MAX_PER_TIME_WINDOW) {
- Slog.w(TAG, "Too many associations. " + packageName
- + " already associated " + recentAssociations.size()
- + " devices within the last " + ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS
- + "ms: " + recentAssociations);
- return false;
+ final long now = System.currentTimeMillis();
+ final List<AssociationInfo> associationForPackage =
+ mAssociationStore.getAssociationsForPackage(userId, packageName);
+ // Number of "recent" associations.
+ int recent = 0;
+ for (AssociationInfo association : associationForPackage) {
+ final boolean isRecent =
+ now - association.getTimeApprovedMs() < ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS;
+ if (isRecent) {
+ if (++recent >= ASSOCIATE_WITHOUT_PROMPT_MAX_PER_TIME_WINDOW) {
+ Slog.w(TAG, "Too many associations: " + packageName + " already "
+ + "associated " + recent + " devices within the last "
+ + ASSOCIATE_WITHOUT_PROMPT_WINDOW_MS + "ms");
+ return false;
+ }
+ }
}
+
String[] sameOemCerts = mContext.getResources()
.getStringArray(com.android.internal.R.array.config_companionDeviceCerts);
diff --git a/services/companion/java/com/android/server/companion/AssociationStore.java b/services/companion/java/com/android/server/companion/AssociationStore.java
new file mode 100644
index 0000000..58fc8f7
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/AssociationStore.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.companion;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.companion.AssociationInfo;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Interface for a store of {@link AssociationInfo}-s.
+ */
+public interface AssociationStore {
+
+ @IntDef(prefix = { "CHANGE_TYPE_" }, value = {
+ CHANGE_TYPE_ADDED,
+ CHANGE_TYPE_REMOVED,
+ CHANGE_TYPE_UPDATED_ADDRESS_CHANGED,
+ CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface ChangeType {}
+
+ int CHANGE_TYPE_ADDED = 0;
+ int CHANGE_TYPE_REMOVED = 1;
+ int CHANGE_TYPE_UPDATED_ADDRESS_CHANGED = 2;
+ int CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED = 3;
+
+ /** Listener for any changes to {@link AssociationInfo}-s. */
+ interface OnChangeListener {
+ default void onAssociationChanged(
+ @ChangeType int changeType, AssociationInfo association) {}
+
+ default void onAssociationAdded(AssociationInfo association) {}
+
+ default void onAssociationRemoved(AssociationInfo association) {}
+
+ default void onAssociationUpdated(AssociationInfo association, boolean addressChanged) {}
+ }
+
+ /**
+ * @return all CDM associations.
+ */
+ @NonNull
+ Collection<AssociationInfo> getAssociations();
+
+ /**
+ * @return a {@link List} of associations that belong to the user.
+ */
+ @NonNull
+ List<AssociationInfo> getAssociationsForUser(@UserIdInt int userId);
+
+ /**
+ * @return a {@link List} of association that belong to the package.
+ */
+ @NonNull
+ List<AssociationInfo> getAssociationsForPackage(
+ @UserIdInt int userId, @NonNull String packageName);
+
+ /**
+ * @return an association with the given address that belong to the given package if such an
+ * association exists, otherwise {@code null}.
+ */
+ @Nullable
+ AssociationInfo getAssociationsForPackageWithAddress(
+ @UserIdInt int userId, @NonNull String packageName, @NonNull String macAddress);
+
+ /**
+ * @return an association with the given id if such an association exists, otherwise
+ * {@code null}.
+ */
+ @Nullable
+ AssociationInfo getAssociationById(int id);
+
+ /**
+ * @return all associations with the given MAc address.
+ */
+ @NonNull
+ List<AssociationInfo> getAssociationsByAddress(@NonNull String macAddress);
+
+ /** Register a {@link OnChangeListener} */
+ void registerListener(@NonNull OnChangeListener listener);
+
+ /** Un-register a previously registered {@link OnChangeListener} */
+ void unregisterListener(@NonNull OnChangeListener listener);
+
+ /** @hide */
+ static String changeTypeToString(@ChangeType int changeType) {
+ switch (changeType) {
+ case CHANGE_TYPE_ADDED:
+ return "ASSOCIATION_ADDED";
+
+ case CHANGE_TYPE_REMOVED:
+ return "ASSOCIATION_REMOVED";
+
+ case CHANGE_TYPE_UPDATED_ADDRESS_CHANGED:
+ return "ASSOCIATION_UPDATED";
+
+ case CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED:
+ return "ASSOCIATION_UPDATED_ADDRESS_UNCHANGED";
+
+ default:
+ return "Unknown (" + changeType + ")";
+ }
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/AssociationStoreImpl.java b/services/companion/java/com/android/server/companion/AssociationStoreImpl.java
new file mode 100644
index 0000000..3f0200e
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/AssociationStoreImpl.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.companion;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.companion.AssociationInfo;
+import android.net.MacAddress;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Implementation of the {@link AssociationStore}, with addition of the methods for modification.
+ * <ul>
+ * <li> {@link #addAssociation(AssociationInfo)}
+ * <li> {@link #removeAssociation(int)}
+ * <li> {@link #updateAssociation(AssociationInfo)}
+ * </ul>
+ *
+ * The class has package-private access level, and instances of the class should only be created by
+ * the {@link CompanionDeviceManagerService}.
+ * Other system component (both inside and outside if the com.android.server.companion package)
+ * should use public {@link AssociationStore} interface.
+ */
+class AssociationStoreImpl implements AssociationStore {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "AssociationStore";
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private final Map<Integer, AssociationInfo> mIdMap;
+ @GuardedBy("mLock")
+ private final Map<MacAddress, Set<Integer>> mAddressMap;
+ @GuardedBy("mLock")
+ private final SparseArray<List<AssociationInfo>> mCachedPerUser = new SparseArray<>();
+
+ @GuardedBy("mListeners")
+ private final Set<OnChangeListener> mListeners = new LinkedHashSet<>();
+
+ AssociationStoreImpl(Collection<AssociationInfo> associations) {
+ synchronized (mLock) {
+ final int size = associations.size();
+ mIdMap = new HashMap<>(size);
+ mAddressMap = new HashMap<>(size);
+
+ for (AssociationInfo association : associations) {
+ final int id = association.getId();
+ mIdMap.put(id, association);
+
+ final MacAddress address = association.getDeviceMacAddress();
+ if (address != null) {
+ mAddressMap.computeIfAbsent(address, it -> new HashSet<>()).add(id);
+ }
+ }
+ }
+ }
+
+ void addAssociation(@NonNull AssociationInfo association) {
+ final int id = association.getId();
+
+ if (DEBUG) {
+ Log.i(TAG, "addAssociation() " + association.toShortString());
+ Log.d(TAG, " association=" + association);
+ }
+
+ synchronized (mLock) {
+ if (mIdMap.containsKey(id)) {
+ if (DEBUG) Log.w(TAG, "Association already stored.");
+ return;
+ }
+ mIdMap.put(id, association);
+
+ final MacAddress address = association.getDeviceMacAddress();
+ if (address != null) {
+ mAddressMap.computeIfAbsent(address, it -> new HashSet<>()).add(id);
+ }
+
+ invalidateCacheForUserLocked(association.getUserId());
+ }
+
+ broadcastChange(CHANGE_TYPE_ADDED, association);
+ }
+
+ void updateAssociation(@NonNull AssociationInfo updated) {
+ final int id = updated.getId();
+
+ if (DEBUG) {
+ Log.i(TAG, "updateAssociation() " + updated.toShortString());
+ Log.d(TAG, " updated=" + updated);
+ }
+
+ final AssociationInfo current;
+ final boolean macAddressChanged;
+ synchronized (mLock) {
+ current = mIdMap.get(id);
+ if (current == null) {
+ if (DEBUG) Log.w(TAG, "Association with id " + id + " does not exist.");
+ return;
+ }
+ if (DEBUG) Log.d(TAG, " current=" + current);
+
+ if (current.equals(updated)) {
+ if (DEBUG) Log.w(TAG, " No changes.");
+ return;
+ }
+
+ // Update the ID-to-Association map.
+ mIdMap.put(id, updated);
+
+ // Update the MacAddress-to-List<Association> map if needed.
+ final MacAddress updatedAddress = updated.getDeviceMacAddress();
+ final MacAddress currentAddress = current.getDeviceMacAddress();
+ macAddressChanged = Objects.equals(
+ current.getDeviceMacAddress(), updated.getDeviceMacAddress());
+ if (macAddressChanged) {
+ if (currentAddress != null) {
+ mAddressMap.get(currentAddress).remove(id);
+ }
+ if (updatedAddress != null) {
+ mAddressMap.computeIfAbsent(updatedAddress, it -> new HashSet<>()).add(id);
+ }
+ }
+ }
+
+ final int changeType = macAddressChanged ? CHANGE_TYPE_UPDATED_ADDRESS_CHANGED
+ : CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED;
+ broadcastChange(changeType, updated);
+ }
+
+ void removeAssociation(int id) {
+ if (DEBUG) Log.i(TAG, "removeAssociation() id=" + id);
+
+ final AssociationInfo association;
+ synchronized (mLock) {
+ association = mIdMap.remove(id);
+
+ if (association == null) {
+ if (DEBUG) Log.w(TAG, "Association with id " + id + " is not stored.");
+ return;
+ } else {
+ if (DEBUG) {
+ Log.i(TAG, "removed " + association.toShortString());
+ Log.d(TAG, " association=" + association);
+ }
+ }
+
+ final MacAddress macAddress = association.getDeviceMacAddress();
+ if (macAddress != null) {
+ mAddressMap.get(macAddress).remove(id);
+ }
+
+ invalidateCacheForUserLocked(association.getUserId());
+ }
+
+ broadcastChange(CHANGE_TYPE_REMOVED, association);
+ }
+
+ public @NonNull Collection<AssociationInfo> getAssociations() {
+ final Collection<AssociationInfo> allAssociations;
+ synchronized (mLock) {
+ allAssociations = mIdMap.values();
+ }
+ return Collections.unmodifiableCollection(allAssociations);
+ }
+
+ public @NonNull List<AssociationInfo> getAssociationsForUser(@UserIdInt int userId) {
+ synchronized (mLock) {
+ return getAssociationsForUserLocked(userId);
+ }
+ }
+
+ public @NonNull List<AssociationInfo> getAssociationsForPackage(
+ @UserIdInt int userId, @NonNull String packageName) {
+ final List<AssociationInfo> associationsForUser = getAssociationsForUser(userId);
+ final List<AssociationInfo> associationsForPackage =
+ CollectionUtils.filter(associationsForUser,
+ it -> it.getPackageName().equals(packageName));
+ return Collections.unmodifiableList(associationsForPackage);
+ }
+
+ public @Nullable AssociationInfo getAssociationsForPackageWithAddress(
+ @UserIdInt int userId, @NonNull String packageName, @NonNull String macAddress) {
+ final List<AssociationInfo> associations = getAssociationsByAddress(macAddress);
+ return CollectionUtils.find(associations,
+ it -> it.belongsToPackage(userId, packageName));
+ }
+
+ public @Nullable AssociationInfo getAssociationById(int id) {
+ synchronized (mLock) {
+ return mIdMap.get(id);
+ }
+ }
+
+ public @NonNull List<AssociationInfo> getAssociationsByAddress(@NonNull String macAddress) {
+ final MacAddress address = MacAddress.fromString(macAddress);
+
+ synchronized (mLock) {
+ final Set<Integer> ids = mAddressMap.get(address);
+ if (ids == null) return Collections.emptyList();
+
+ final List<AssociationInfo> associations = new ArrayList<>();
+ for (AssociationInfo association : mIdMap.values()) {
+ if (address.equals(association.getDeviceMacAddress())) {
+ associations.add(association);
+ }
+ }
+
+ return Collections.unmodifiableList(associations);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private @NonNull List<AssociationInfo> getAssociationsForUserLocked(@UserIdInt int userId) {
+ final List<AssociationInfo> cached = mCachedPerUser.get(userId);
+ if (cached != null) {
+ return cached;
+ }
+
+ final List<AssociationInfo> associationsForUser = new ArrayList<>();
+ for (AssociationInfo association : mIdMap.values()) {
+ if (association.getUserId() == userId) {
+ associationsForUser.add(association);
+ }
+ }
+ final List<AssociationInfo> set = Collections.unmodifiableList(associationsForUser);
+ mCachedPerUser.set(userId, set);
+ return set;
+ }
+
+ @GuardedBy("mLock")
+ private void invalidateCacheForUserLocked(@UserIdInt int userId) {
+ mCachedPerUser.delete(userId);
+ }
+
+ public void registerListener(@NonNull OnChangeListener listener) {
+ synchronized (mListeners) {
+ mListeners.add(listener);
+ }
+ }
+
+ public void unregisterListener(@NonNull OnChangeListener listener) {
+ synchronized (mListeners) {
+ mListeners.remove(listener);
+ }
+ }
+
+ private void broadcastChange(@ChangeType int changeType, AssociationInfo association) {
+ synchronized (mListeners) {
+ for (OnChangeListener listener : mListeners) {
+ listener.onAssociationChanged(changeType, association);
+
+ switch (changeType) {
+ case CHANGE_TYPE_ADDED:
+ listener.onAssociationAdded(association);
+ break;
+
+ case CHANGE_TYPE_REMOVED:
+ listener.onAssociationRemoved(association);
+ break;
+
+ case CHANGE_TYPE_UPDATED_ADDRESS_CHANGED:
+ listener.onAssociationUpdated(association, true);
+ break;
+
+ case CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED:
+ listener.onAssociationUpdated(association, false);
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 626128a..5aa1c93 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -27,15 +27,12 @@
import static android.os.Process.SYSTEM_UID;
import static android.os.UserHandle.getCallingUserId;
-import static com.android.internal.util.CollectionUtils.add;
import static com.android.internal.util.CollectionUtils.any;
-import static com.android.internal.util.CollectionUtils.filter;
import static com.android.internal.util.CollectionUtils.find;
-import static com.android.internal.util.CollectionUtils.forEach;
-import static com.android.internal.util.CollectionUtils.map;
import static com.android.internal.util.Preconditions.checkState;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
+import static com.android.server.companion.AssociationStore.CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED;
import static com.android.server.companion.PermissionsUtils.checkCallerCanManageAssociationsForPackage;
import static com.android.server.companion.PermissionsUtils.checkCallerCanManageCompanionDevice;
import static com.android.server.companion.PermissionsUtils.enforceCallerCanInteractWithUserId;
@@ -45,8 +42,6 @@
import static com.android.server.companion.RolesUtils.addRoleHolderForAssociation;
import static com.android.server.companion.RolesUtils.removeRoleHolderForAssociation;
-import static java.util.Collections.emptySet;
-import static java.util.Collections.unmodifiableSet;
import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.MINUTES;
@@ -82,7 +77,6 @@
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.UserInfo;
import android.net.MacAddress;
import android.net.NetworkPolicyManager;
import android.os.Binder;
@@ -90,6 +84,7 @@
import android.os.Handler;
import android.os.Parcel;
import android.os.PowerWhitelistManager;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -111,9 +106,7 @@
import com.android.internal.notification.NotificationAccessConfirmationActivityContract;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
-import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -126,6 +119,7 @@
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -134,12 +128,11 @@
import java.util.Objects;
import java.util.Set;
import java.util.TimeZone;
-import java.util.function.Function;
-import java.util.function.Predicate;
/** @hide */
@SuppressLint("LongLogTag")
-public class CompanionDeviceManagerService extends SystemService {
+public class CompanionDeviceManagerService extends SystemService
+ implements AssociationStore.OnChangeListener {
static final String LOG_TAG = "CompanionDeviceManagerService";
static final boolean DEBUG = false;
@@ -161,10 +154,11 @@
sDateFormat.setTimeZone(TimeZone.getDefault());
}
- private final CompanionDeviceManagerImpl mImpl;
// Persistent data store for all Associations.
- private final PersistentDataStore mPersistentDataStore;
- private final AssociationRequestsProcessor mAssociationRequestsProcessor;
+ private PersistentDataStore mPersistentStore;
+ private AssociationStoreImpl mAssociationStore;
+ private AssociationRequestsProcessor mAssociationRequestsProcessor;
+
private PowerWhitelistManager mPowerWhitelistManager;
private IAppOpsService mAppOpsManager;
private BluetoothAdapter mBluetoothAdapter;
@@ -183,21 +177,19 @@
mUnbindDeviceListenersRunnable = new UnbindDeviceListenersRunnable();
private ArrayMap<String, TriggerDeviceDisappearedRunnable> mTriggerDeviceDisappearedRunnables =
new ArrayMap<>();
+ private final RemoteCallbackList<IOnAssociationsChangedListener> mListeners =
+ new RemoteCallbackList<>();
- final Object mLock = new Object();
final Handler mMainHandler = Handler.getMain();
private CompanionDevicePresenceController mCompanionDevicePresenceController;
- /** Maps a {@link UserIdInt} to a set of associations for the user. */
- @GuardedBy("mLock")
- private final SparseArray<Set<AssociationInfo>> mCachedAssociations = new SparseArray<>();
/**
* A structure that consist of two nested maps, and effectively maps (userId + packageName) to
* a list of IDs that have been previously assigned to associations for that package.
* We maintain this structure so that we never re-use association IDs for the same package
* (until it's uninstalled).
*/
- @GuardedBy("mLock")
+ @GuardedBy("mPreviouslyUsedIds")
private final SparseArray<Map<String, Set<Integer>>> mPreviouslyUsedIds = new SparseArray<>();
ActivityTaskManagerInternal mAtmInternal;
@@ -206,8 +198,6 @@
public CompanionDeviceManagerService(Context context) {
super(context);
- mImpl = new CompanionDeviceManagerImpl();
- mPersistentDataStore = new PersistentDataStore();
mPowerWhitelistManager = context.getSystemService(PowerWhitelistManager.class);
mAppOpsManager = IAppOpsService.Stub.asInterface(
@@ -218,49 +208,36 @@
mPermissionControllerManager = requireNonNull(
context.getSystemService(PermissionControllerManager.class));
mUserManager = context.getSystemService(UserManager.class);
- mCompanionDevicePresenceController = new CompanionDevicePresenceController(this);
- mAssociationRequestsProcessor = new AssociationRequestsProcessor(this);
-
- registerPackageMonitor();
- }
-
- private void registerPackageMonitor() {
- new PackageMonitor() {
- @Override
- public void onPackageRemoved(String packageName, int uid) {
- final int userId = getChangingUserId();
- Slog.i(LOG_TAG, "onPackageRemoved() u" + userId + "/" + packageName);
-
- clearAssociationForPackage(userId, packageName);
- }
-
- @Override
- public void onPackageDataCleared(String packageName, int uid) {
- final int userId = getChangingUserId();
- Slog.i(LOG_TAG, "onPackageDataCleared() u" + userId + "/" + packageName);
-
- clearAssociationForPackage(userId, packageName);
- }
-
- @Override
- public void onPackageModified(String packageName) {
- final int userId = getChangingUserId();
- Slog.i(LOG_TAG, "onPackageModified() u" + userId + "/" + packageName);
-
- forEach(getAssociations(userId, packageName), association ->
- updateSpecialAccessPermissionForAssociatedPackage(association));
- }
- }.register(getContext(), FgThread.get().getLooper(), UserHandle.ALL, true);
}
@Override
public void onStart() {
- publishBinderService(Context.COMPANION_DEVICE_SERVICE, mImpl);
+ mPersistentStore = new PersistentDataStore();
+ final Set<AssociationInfo> allAssociations = new ArraySet<>();
+
+ synchronized (mPreviouslyUsedIds) {
+ // The data is stored in DE directories, so we can read the data for all users now
+ // (which would not be possible if the data was stored to CE directories).
+ mPersistentStore.readStateForUsers(
+ mUserManager.getAliveUsers(), allAssociations, mPreviouslyUsedIds);
+ }
+
+ mAssociationStore = new AssociationStoreImpl(allAssociations);
+ mAssociationStore.registerListener(this);
+
+ mCompanionDevicePresenceController = new CompanionDevicePresenceController(this);
+ mAssociationRequestsProcessor = new AssociationRequestsProcessor(this, mAssociationStore);
+
+ // Publish "binder service"
+ final CompanionDeviceManagerImpl impl = new CompanionDeviceManagerImpl();
+ publishBinderService(Context.COMPANION_DEVICE_SERVICE, impl);
}
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ registerPackageMonitor();
+
// Init Bluetooth
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter != null) {
@@ -279,7 +256,7 @@
@Override
public void onUserUnlocking(@NonNull TargetUser user) {
final int userId = user.getUserIdentifier();
- final Set<AssociationInfo> associations = getAllAssociationsForUser(userId);
+ final List<AssociationInfo> associations = mAssociationStore.getAssociationsForUser(userId);
if (associations.isEmpty()) return;
@@ -290,42 +267,18 @@
MINUTES.toMillis(10));
}
- @NonNull
- Set<AssociationInfo> getAllAssociationsForUser(@UserIdInt int userId) {
- synchronized (mLock) {
- readPersistedStateForUserIfNeededLocked(userId);
- // This returns non-null, because the readAssociationsInfoForUserIfNeededLocked() method
- // we just called adds an empty set, if there was no previously saved data.
- return mCachedAssociations.get(userId);
- }
- }
-
- @NonNull
- Set<AssociationInfo> getAssociations(@UserIdInt int userId, @NonNull String packageName) {
- return filter(getAllAssociationsForUser(userId),
- a -> a.belongsToPackage(userId, packageName));
- }
-
- @Nullable
- private AssociationInfo getAssociation(int associationId) {
- return find(getAllAssociations(), association -> association.getId() == associationId);
- }
-
- @Nullable
- AssociationInfo getAssociation(
- @UserIdInt int userId, @NonNull String packageName, @NonNull String macAddress) {
- return find(getAssociations(userId, packageName), a -> a.isLinkedTo(macAddress));
- }
-
@Nullable
AssociationInfo getAssociationWithCallerChecks(
@UserIdInt int userId, @NonNull String packageName, @NonNull String macAddress) {
- return sanitizeWithCallerChecks(getAssociation(userId, packageName, macAddress));
+ final AssociationInfo association = mAssociationStore.getAssociationsForPackageWithAddress(
+ userId, packageName, macAddress);
+ return sanitizeWithCallerChecks(association);
}
@Nullable
AssociationInfo getAssociationWithCallerChecks(int associationId) {
- return sanitizeWithCallerChecks(getAssociation(associationId));
+ final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
+ return sanitizeWithCallerChecks(association);
}
@Nullable
@@ -341,19 +294,6 @@
return association;
}
- private Set<AssociationInfo> getAllAssociations() {
- final long identity = Binder.clearCallingIdentity();
- try {
- final Set<AssociationInfo> result = new ArraySet<>();
- for (UserInfo user : mUserManager.getAliveUsers()) {
- result.addAll(getAllAssociationsForUser(user.id));
- }
- return result;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
void maybeGrantAutoRevokeExemptions() {
Slog.d(LOG_TAG, "maybeGrantAutoRevokeExemptions()");
PackageManager pm = getContext().getPackageManager();
@@ -366,10 +306,8 @@
}
try {
- Set<AssociationInfo> associations = getAllAssociationsForUser(userId);
- if (associations == null) {
- continue;
- }
+ final List<AssociationInfo> associations =
+ mAssociationStore.getAssociationsForUser(userId);
for (AssociationInfo a : associations) {
try {
int uid = pm.getPackageUidAsUser(a.getPackageName(), userId);
@@ -384,6 +322,61 @@
}
}
+ @Override
+ public void onAssociationChanged(
+ @AssociationStore.ChangeType int changeType, AssociationInfo association) {
+ final int id = association.getId();
+ final int userId = association.getUserId();
+ final String packageName = association.getPackageName();
+
+ if (changeType == AssociationStore.CHANGE_TYPE_REMOVED) {
+ markIdAsPreviouslyUsedForPackage(id, userId, packageName);
+ }
+
+ final List<AssociationInfo> updatedAssociations =
+ mAssociationStore.getAssociationsForUser(userId);
+ final Map<String, Set<Integer>> usedIdsForUser = getPreviouslyUsedIdsForUser(userId);
+ BackgroundThread.getHandler().post(() ->
+ mPersistentStore.persistStateForUser(userId, updatedAssociations, usedIdsForUser));
+
+ // Notify listeners if ADDED, REMOVED or UPDATED_ADDRESS_CHANGED.
+ // Do NOT notify when UPDATED_ADDRESS_UNCHANGED, which means a minor tweak in association's
+ // configs, which "listeners" won't (and shouldn't) be able to see.
+ if (changeType != CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED) {
+ notifyListeners(userId, updatedAssociations);
+ }
+ updateAtm(userId, updatedAssociations);
+
+ restartBleScan();
+ }
+
+ private void notifyListeners(
+ @UserIdInt int userId, @NonNull List<AssociationInfo> associations) {
+ mListeners.broadcast((listener, callbackUserId) -> {
+ if ((int) callbackUserId == userId) {
+ try {
+ listener.onAssociationsChanged(associations);
+ } catch (RemoteException ignored) {
+ }
+ }
+ });
+ }
+
+ private void markIdAsPreviouslyUsedForPackage(
+ int associationId, @UserIdInt int userId, @NonNull String packageName) {
+ synchronized (mPreviouslyUsedIds) {
+ Map<String, Set<Integer>> usedIdsForUser = mPreviouslyUsedIds.get(userId);
+ if (usedIdsForUser == null) {
+ usedIdsForUser = new HashMap<>();
+ mPreviouslyUsedIds.put(userId, usedIdsForUser);
+ }
+
+ final Set<Integer> usedIdsForPackage =
+ usedIdsForUser.computeIfAbsent(packageName, it -> new HashSet<>());
+ usedIdsForPackage.add(associationId);
+ }
+ }
+
class CompanionDeviceManagerImpl extends ICompanionDeviceManager.Stub {
@Override
@@ -421,8 +414,7 @@
checkUsesFeature(packageName, getCallingUserId());
}
- return new ArrayList<>(
- CompanionDeviceManagerService.this.getAssociations(userId, packageName));
+ return mAssociationStore.getAssociationsForPackage(userId, packageName);
}
@Override
@@ -430,8 +422,7 @@
enforceCallerCanInteractWithUserId(getContext(), userId);
enforceCallerCanManageCompanionDevice(getContext(), "getAllAssociationsForUser");
- return new ArrayList<>(
- CompanionDeviceManagerService.this.getAllAssociationsForUser(userId));
+ return mAssociationStore.getAssociationsForUser(userId);
}
@Override
@@ -441,13 +432,17 @@
enforceCallerCanManageCompanionDevice(getContext(),
"addOnAssociationsChangedListener");
- //TODO: Implement.
+ mListeners.register(listener, userId);
}
@Override
public void removeOnAssociationsChangedListener(IOnAssociationsChangedListener listener,
int userId) {
- //TODO: Implement.
+ enforceCallerCanInteractWithUserId(getContext(), userId);
+ enforceCallerCanManageCompanionDevice(
+ getContext(), "removeOnAssociationsChangedListener");
+
+ mListeners.unregister(listener);
}
@Override
@@ -463,7 +458,7 @@
+ "(ie. it belongs to a different package or a different user).");
}
- disassociateInternal(userId, association.getId());
+ disassociateInternal(association.getId());
}
@Override
@@ -476,7 +471,7 @@
+ "or belongs to a different user");
}
- disassociateInternal(association.getUserId(), associationId);
+ disassociateInternal(associationId);
}
@Override
@@ -533,7 +528,7 @@
return true;
}
- return any(CompanionDeviceManagerService.this.getAssociations(userId, packageName),
+ return any(mAssociationStore.getAssociationsForPackage(userId, packageName),
a -> a.isLinkedTo(macAddress));
}
@@ -616,25 +611,18 @@
final int userId = getCallingUserId();
enforceCallerIsSystemOr(userId, packageName);
- Set<AssociationInfo> deviceAssociations = filter(
- CompanionDeviceManagerService.this.getAssociations(userId, packageName),
- a -> a.isLinkedTo(deviceAddress));
+ final AssociationInfo association =
+ mAssociationStore.getAssociationsForPackageWithAddress(
+ userId, packageName, deviceAddress);
- if (deviceAssociations.isEmpty()) {
+ if (association == null) {
throw new RemoteException(new DeviceNotAssociatedException("App " + packageName
+ " is not associated with device " + deviceAddress
+ " for user " + userId));
}
- updateAssociations(associations -> map(associations, association -> {
- if (association.belongsToPackage(userId, packageName)
- && association.isLinkedTo(deviceAddress)) {
- association.setNotifyOnDeviceNearby(active);
- }
- return association;
- }), userId);
-
- restartBleScan();
+ association.setNotifyOnDeviceNearby(active);
+ mAssociationStore.updateAssociation(association);
}
@Override
@@ -657,14 +645,16 @@
enforceCallerIsSystemOr(userId, callingPackage);
checkState(!ArrayUtils.isEmpty(
- CompanionDeviceManagerService.this.getAssociations(userId, callingPackage)),
+ mAssociationStore.getAssociationsForPackage(userId, callingPackage)),
"App must have an association before calling this API");
checkUsesFeature(callingPackage, userId);
}
@Override
public boolean canPairWithoutPrompt(String packageName, String macAddress, int userId) {
- final AssociationInfo association = getAssociation(userId, packageName, macAddress);
+ final AssociationInfo association =
+ mAssociationStore.getAssociationsForPackageWithAddress(
+ userId, packageName, macAddress);
if (association == null) {
return false;
}
@@ -677,7 +667,8 @@
String[] args, ShellCallback callback, ResultReceiver resultReceiver)
throws RemoteException {
enforceCallerCanManageCompanionDevice(getContext(), "onShellCommand");
- new CompanionDeviceShellCommand(CompanionDeviceManagerService.this)
+ new CompanionDeviceShellCommand(
+ CompanionDeviceManagerService.this, mAssociationStore)
.exec(this, in, out, err, args, callback, resultReceiver);
}
@@ -690,13 +681,8 @@
}
fout.append("Companion Device Associations:").append('\n');
- synchronized (mLock) {
- for (UserInfo user : getAllUsers()) {
- forEach(mCachedAssociations.get(user.id), a -> {
- fout.append(" ").append(a.toString()).append('\n');
- });
- }
-
+ for (AssociationInfo a : mAssociationStore.getAssociations()) {
+ fout.append(" ").append(a.toString()).append('\n');
}
fout.append("Currently Connected Devices:").append('\n');
@@ -747,31 +733,56 @@
@Nullable String deviceProfile, boolean selfManaged) {
final int id = getNewAssociationIdForPackage(userId, packageName);
final long timestamp = System.currentTimeMillis();
+
final AssociationInfo association = new AssociationInfo(id, userId, packageName,
macAddress, displayName, deviceProfile, selfManaged, false, timestamp);
+ Slog.i(LOG_TAG, "New CDM association created=" + association);
+ mAssociationStore.addAssociation(association);
updateSpecialAccessPermissionForAssociatedPackage(association);
- recordAssociation(association, userId);
return association;
}
- @GuardedBy("mLock")
+ @NonNull
+ private Map<String, Set<Integer>> getPreviouslyUsedIdsForUser(@UserIdInt int userId) {
+ synchronized (mPreviouslyUsedIds) {
+ return getPreviouslyUsedIdsForUserLocked(userId);
+ }
+ }
+
+ @GuardedBy("mPreviouslyUsedIds")
+ @NonNull
+ private Map<String, Set<Integer>> getPreviouslyUsedIdsForUserLocked(@UserIdInt int userId) {
+ final Map<String, Set<Integer>> usedIdsForUser = mPreviouslyUsedIds.get(userId);
+ if (usedIdsForUser == null) {
+ return Collections.emptyMap();
+ }
+ return deepUnmodifiableCopy(usedIdsForUser);
+ }
+
+ @GuardedBy("mPreviouslyUsedIds")
@NonNull
private Set<Integer> getPreviouslyUsedIdsForPackageLocked(
@UserIdInt int userId, @NonNull String packageName) {
- final Set<Integer> previouslyUsedIds = mPreviouslyUsedIds.get(userId).get(packageName);
- if (previouslyUsedIds != null) return previouslyUsedIds;
- return emptySet();
+ // "Deeply unmodifiable" map: the map itself and the Set<Integer> values it contains are all
+ // unmodifiable.
+ final Map<String, Set<Integer>> usedIdsForUser = getPreviouslyUsedIdsForUserLocked(userId);
+ final Set<Integer> usedIdsForPackage = usedIdsForUser.get(packageName);
+
+ if (usedIdsForPackage == null) {
+ return Collections.emptySet();
+ }
+
+ //The set is already unmodifiable.
+ return usedIdsForPackage;
}
private int getNewAssociationIdForPackage(@UserIdInt int userId, @NonNull String packageName) {
- synchronized (mLock) {
- readPersistedStateForUserIfNeededLocked(userId);
-
+ synchronized (mPreviouslyUsedIds) {
// First: collect all IDs currently in use for this user's Associations.
final SparseBooleanArray usedIds = new SparseBooleanArray();
- for (AssociationInfo it : getAllAssociationsForUser(userId)) {
+ for (AssociationInfo it : mAssociationStore.getAssociationsForUser(userId)) {
usedIds.put(it.getId(), true);
}
@@ -797,41 +808,14 @@
}
}
- //TODO also revoke notification access
- void disassociateInternal(@UserIdInt int userId, int associationId) {
- updateAssociations(associations ->
- filterOut(associations, it -> {
- if (it.getId() != associationId) return false;
-
- onAssociationPreRemove(it);
- markIdAsPreviouslyUsedForPackage(
- it.getId(), it.getUserId(), it.getPackageName());
- return true;
- }), userId);
-
- restartBleScan();
+ //TODO: also revoke notification access
+ void disassociateInternal(int associationId) {
+ onAssociationPreRemove(associationId);
+ mAssociationStore.removeAssociation(associationId);
}
- void clearAssociationForPackage(@UserIdInt int userId, @NonNull String packageName) {
- if (DEBUG) Slog.d(LOG_TAG, "clearAssociationForPackage() u" + userId + "/" + packageName);
-
- mCompanionDevicePresenceController.unbindDevicePresenceListener(packageName, userId);
- updateAssociations(set -> filterOut(set, it -> it.belongsToPackage(userId, packageName)),
- userId);
- }
-
- private void markIdAsPreviouslyUsedForPackage(
- int associationId, @UserIdInt int userId, @NonNull String packageName) {
- synchronized (mLock) {
- // Mark as previously used.
- readPersistedStateForUserIfNeededLocked(userId);
- mPreviouslyUsedIds.get(userId)
- .computeIfAbsent(packageName, it -> new HashSet<>())
- .add(associationId);
- }
- }
-
- void onAssociationPreRemove(AssociationInfo association) {
+ void onAssociationPreRemove(int associationId) {
+ final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
if (association.isNotifyOnDeviceNearby()
|| (association.isSelfManaged()
&& mPresentSelfManagedDevices.contains(association.getId()))) {
@@ -842,7 +826,7 @@
String deviceProfile = association.getDeviceProfile();
if (deviceProfile != null) {
AssociationInfo otherAssociationWithDeviceProfile = find(
- getAllAssociationsForUser(association.getUserId()),
+ mAssociationStore.getAssociationsForUser(association.getUserId()),
a -> !a.equals(association) && deviceProfile.equals(a.getDeviceProfile()));
if (otherAssociationWithDeviceProfile != null) {
Slog.i(LOG_TAG, "Not revoking " + deviceProfile
@@ -934,37 +918,7 @@
.getPackageInfoAsUser(packageName, flags , userId));
}
- private void recordAssociation(AssociationInfo association, int userId) {
- Slog.i(LOG_TAG, "recordAssociation(" + association + ")");
- updateAssociations(associations -> add(associations, association), userId);
- }
-
- private void updateAssociations(Function<Set<AssociationInfo>, Set<AssociationInfo>> update,
- int userId) {
- synchronized (mLock) {
- if (DEBUG) Slog.d(LOG_TAG, "Updating Associations set...");
-
- final Set<AssociationInfo> prevAssociations = getAllAssociationsForUser(userId);
- if (DEBUG) Slog.d(LOG_TAG, " > Before : " + prevAssociations + "...");
-
- final Set<AssociationInfo> updatedAssociations = update.apply(
- new ArraySet<>(prevAssociations));
- if (DEBUG) Slog.d(LOG_TAG, " > After: " + updatedAssociations);
-
- mCachedAssociations.put(userId, unmodifiableSet(updatedAssociations));
-
- BackgroundThread.getHandler().sendMessage(
- PooledLambda.obtainMessage(
- (associations, usedIds) ->
- mPersistentDataStore
- .persistStateForUser(userId, associations, usedIds),
- updatedAssociations, deepCopy(mPreviouslyUsedIds.get(userId))));
-
- updateAtm(userId, updatedAssociations);
- }
- }
-
- private void updateAtm(int userId, Set<AssociationInfo> associations) {
+ private void updateAtm(int userId, List<AssociationInfo> associations) {
final Set<Integer> companionAppUids = new ArraySet<>();
for (AssociationInfo association : associations) {
final int uid = mPackageManagerInternal.getPackageUid(association.getPackageName(),
@@ -973,59 +927,24 @@
companionAppUids.add(uid);
}
}
- if (mAtmInternal != null) {
- mAtmInternal.setCompanionAppUids(userId, companionAppUids);
- }
if (mAmInternal != null) {
- // Make a copy of companionAppUids and send it to ActivityManager.
+ // Make a copy of the set and send it to ActivityManager.
mAmInternal.setCompanionAppUids(userId, new ArraySet<>(companionAppUids));
}
}
- @GuardedBy("mLock")
- private void readPersistedStateForUserIfNeededLocked(@UserIdInt int userId) {
- if (mCachedAssociations.get(userId) != null) return;
-
- Slog.i(LOG_TAG, "Reading state for user " + userId + " from the disk");
-
- final Set<AssociationInfo> associations = new ArraySet<>();
- final Map<String, Set<Integer>> previouslyUsedIds = new ArrayMap<>();
- mPersistentDataStore.readStateForUser(userId, associations, previouslyUsedIds);
-
- if (DEBUG) {
- Slog.d(LOG_TAG, " > associations=" + associations + "\n"
- + " > previouslyUsedIds=" + previouslyUsedIds);
- }
-
- mCachedAssociations.put(userId, unmodifiableSet(associations));
- mPreviouslyUsedIds.append(userId, previouslyUsedIds);
- }
-
- private List<UserInfo> getAllUsers() {
- final long identity = Binder.clearCallingIdentity();
- try {
- return mUserManager.getUsers();
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
void onDeviceConnected(String address) {
Slog.d(LOG_TAG, "onDeviceConnected(address = " + address + ")");
mCurrentlyConnectedDevices.add(address);
- for (UserInfo user : getAllUsers()) {
- for (AssociationInfo association : getAllAssociationsForUser(user.id)) {
- if (association.isLinkedTo(address)) {
- if (association.getDeviceProfile() != null) {
- Slog.i(LOG_TAG, "Granting role " + association.getDeviceProfile()
- + " to " + association.getPackageName()
- + " due to device connected: " + association.getDeviceMacAddress());
+ for (AssociationInfo association : mAssociationStore.getAssociationsByAddress(address)) {
+ if (association.getDeviceProfile() != null) {
+ Slog.i(LOG_TAG, "Granting role " + association.getDeviceProfile()
+ + " to " + association.getPackageName()
+ + " due to device connected: " + association.getDeviceMacAddress());
- addRoleHolderForAssociation(getContext(), association);
- }
- }
+ addRoleHolderForAssociation(getContext(), association);
}
}
@@ -1118,7 +1037,9 @@
Date lastNearby = mDevicesLastNearby.valueAt(i);
if (isDeviceDisappeared(lastNearby)) {
- for (AssociationInfo association : getAllAssociations(address)) {
+ final List<AssociationInfo> associations =
+ mAssociationStore.getAssociationsByAddress(address);
+ for (AssociationInfo association : associations) {
if (association.isNotifyOnDeviceNearby()) {
mCompanionDevicePresenceController.unbindDevicePresenceListener(
association.getPackageName(), association.getUserId());
@@ -1160,20 +1081,6 @@
}
}
- private Set<AssociationInfo> getAllAssociations(String deviceAddress) {
- List<UserInfo> aliveUsers = mUserManager.getAliveUsers();
- Set<AssociationInfo> result = new ArraySet<>();
- for (int i = 0, size = aliveUsers.size(); i < size; i++) {
- UserInfo user = aliveUsers.get(i);
- for (AssociationInfo association : getAllAssociationsForUser(user.id)) {
- if (association.isLinkedTo(deviceAddress)) {
- result.add(association);
- }
- }
- }
- return result;
- }
-
private void onDeviceNearby(String address) {
Date timestamp = new Date();
Date oldTimestamp = mDevicesLastNearby.put(address, timestamp);
@@ -1189,7 +1096,9 @@
|| timestamp.getTime() - oldTimestamp.getTime() >= DEVICE_DISAPPEARED_TIMEOUT_MS;
if (justAppeared) {
Slog.i(LOG_TAG, "onDeviceNearby(justAppeared, address = " + address + ")");
- for (AssociationInfo association : getAllAssociations(address)) {
+ final List<AssociationInfo> associations =
+ mAssociationStore.getAssociationsByAddress(address);
+ for (AssociationInfo association : associations) {
if (association.isNotifyOnDeviceNearby()) {
mCompanionDevicePresenceController.onDeviceNotifyAppeared(association,
getContext(), mMainHandler);
@@ -1202,7 +1111,9 @@
Slog.i(LOG_TAG, "onDeviceDisappeared(address = " + address + ")");
boolean hasDeviceListeners = false;
- for (AssociationInfo association : getAllAssociations(address)) {
+ final List<AssociationInfo> associations =
+ mAssociationStore.getAssociationsByAddress(address);
+ for (AssociationInfo association : associations) {
if (association.isNotifyOnDeviceNearby()) {
mCompanionDevicePresenceController.onDeviceNotifyDisappeared(
association, getContext(), mMainHandler);
@@ -1275,7 +1186,7 @@
private List<ScanFilter> getBleScanFilters() {
ArrayList<ScanFilter> result = new ArrayList<>();
ArraySet<String> addressesSeen = new ArraySet<>();
- for (AssociationInfo association : getAllAssociations()) {
+ for (AssociationInfo association : mAssociationStore.getAssociations()) {
if (association.isSelfManaged()) {
continue;
}
@@ -1315,17 +1226,6 @@
}
}
- private static @NonNull <T> Set<T> filterOut(
- @NonNull Set<T> set, @NonNull Predicate<? super T> predicate) {
- return CollectionUtils.filter(set, predicate.negate());
- }
-
- private Map<String, Set<Integer>> deepCopy(Map<String, Set<Integer>> orig) {
- final Map<String, Set<Integer>> copy = new HashMap<>(orig.size(), 1f);
- forEach(orig, (key, value) -> copy.put(key, new ArraySet<>(value)));
- return copy;
- }
-
void checkUsesFeature(@NonNull String pkg, @UserIdInt int userId) {
if (getCallingUid() == SYSTEM_UID) return;
@@ -1340,4 +1240,61 @@
+ FEATURE_COMPANION_DEVICE_SETUP
+ " in manifest to use this API");
}
+
+ private void registerPackageMonitor() {
+ new PackageMonitor() {
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ final int userId = getChangingUserId();
+ Slog.i(LOG_TAG, "onPackageRemoved() u" + userId + "/" + packageName);
+
+ clearAssociationForPackage(userId, packageName);
+ }
+
+ @Override
+ public void onPackageDataCleared(String packageName, int uid) {
+ final int userId = getChangingUserId();
+ Slog.i(LOG_TAG, "onPackageDataCleared() u" + userId + "/" + packageName);
+
+ clearAssociationForPackage(userId, packageName);
+ }
+
+ @Override
+ public void onPackageModified(String packageName) {
+ final int userId = getChangingUserId();
+ Slog.i(LOG_TAG, "onPackageModified() u" + userId + "/" + packageName);
+
+ final List<AssociationInfo> associationsForPackage =
+ mAssociationStore.getAssociationsForPackage(userId, packageName);
+ for (AssociationInfo association : associationsForPackage) {
+ updateSpecialAccessPermissionForAssociatedPackage(association);
+ }
+ }
+ }.register(getContext(), FgThread.get().getLooper(), UserHandle.ALL, true);
+ }
+
+ private void clearAssociationForPackage(@UserIdInt int userId, @NonNull String packageName) {
+ if (DEBUG) Slog.d(LOG_TAG, "clearAssociationForPackage() u" + userId + "/" + packageName);
+
+ // First, unbind CompanionService if needed.
+ mCompanionDevicePresenceController.unbindDevicePresenceListener(packageName, userId);
+
+ // Clear associations.
+ final List<AssociationInfo> associationsForPackage =
+ mAssociationStore.getAssociationsForPackage(userId, packageName);
+ for (AssociationInfo association : associationsForPackage) {
+ mAssociationStore.removeAssociation(association.getId());
+ }
+ }
+
+ private static Map<String, Set<Integer>> deepUnmodifiableCopy(Map<String, Set<Integer>> orig) {
+ final Map<String, Set<Integer>> copy = new HashMap<>();
+
+ for (Map.Entry<String, Set<Integer>> entry : orig.entrySet()) {
+ final Set<Integer> valueCopy = new HashSet<>(entry.getValue());
+ copy.put(entry.getKey(), Collections.unmodifiableSet(valueCopy));
+ }
+
+ return Collections.unmodifiableMap(copy);
+ }
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 5cb3079..5c0571d 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -16,7 +16,6 @@
package com.android.server.companion;
-import static com.android.internal.util.CollectionUtils.forEach;
import static com.android.server.companion.CompanionDeviceManagerService.LOG_TAG;
import android.companion.AssociationInfo;
@@ -24,24 +23,33 @@
import android.util.Slog;
import java.io.PrintWriter;
+import java.util.List;
class CompanionDeviceShellCommand extends android.os.ShellCommand {
private final CompanionDeviceManagerService mService;
+ private final AssociationStore mAssociationStore;
- CompanionDeviceShellCommand(CompanionDeviceManagerService service) {
+ CompanionDeviceShellCommand(CompanionDeviceManagerService service,
+ AssociationStore associationStore) {
mService = service;
+ mAssociationStore = associationStore;
}
@Override
public int onCommand(String cmd) {
+ final PrintWriter out = getOutPrintWriter();
try {
switch (cmd) {
case "list": {
- forEach(
- mService.getAllAssociationsForUser(getNextArgInt()),
- a -> getOutPrintWriter()
- .println(a.getPackageName() + " "
- + a.getDeviceMacAddress()));
+ final int userId = getNextArgInt();
+ final List<AssociationInfo> associationsForUser =
+ mAssociationStore.getAssociationsForUser(userId);
+ for (AssociationInfo association : associationsForUser) {
+ // TODO(b/212535524): use AssociationInfo.toShortString(), once it's not
+ // longer referenced in tests.
+ out.println(association.getPackageName() + " "
+ + association.getDeviceMacAddress());
+ }
}
break;
@@ -60,7 +68,7 @@
final AssociationInfo association =
mService.getAssociationWithCallerChecks(userId, packageName, address);
if (association != null) {
- mService.disassociateInternal(userId, association.getId());
+ mService.disassociateInternal(association.getId());
}
}
break;
diff --git a/services/companion/java/com/android/server/companion/PersistentDataStore.java b/services/companion/java/com/android/server/companion/PersistentDataStore.java
index 87558df..97ec3bb 100644
--- a/services/companion/java/com/android/server/companion/PersistentDataStore.java
+++ b/services/companion/java/com/android/server/companion/PersistentDataStore.java
@@ -33,15 +33,18 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.companion.AssociationInfo;
+import android.content.pm.UserInfo;
import android.net.MacAddress;
import android.os.Environment;
+import android.util.ArrayMap;
import android.util.AtomicFile;
-import android.util.ExceptionUtils;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.android.internal.util.FunctionalUtils.ThrowingConsumer;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -50,8 +53,11 @@
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.Collection;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -68,8 +74,8 @@
*
* Before Android T the data was stored using the v0 schema.
*
- * @see #readAssociationsV0(TypedXmlPullParser, int, Set)
- * @see #readAssociationV0(TypedXmlPullParser, int, int, Set)
+ * @see #readAssociationsV0(TypedXmlPullParser, int, Collection)
+ * @see #readAssociationV0(TypedXmlPullParser, int, int, Collection)
*
* The following snippet is a sample of a the file that is using v0 schema.
* <pre>{@code
@@ -100,8 +106,8 @@
* optional.
*
* @see #CURRENT_PERSISTENCE_VERSION
- * @see #readAssociationsV1(TypedXmlPullParser, int, Set)
- * @see #readAssociationV1(TypedXmlPullParser, int, Set)
+ * @see #readAssociationsV1(TypedXmlPullParser, int, Collection)
+ * @see #readAssociationV1(TypedXmlPullParser, int, Collection)
* @see #readPreviouslyUsedIdsV1(TypedXmlPullParser, Map)
*
* The following snippet is a sample of a the file that is using v0 schema.
@@ -168,6 +174,23 @@
private final @NonNull ConcurrentMap<Integer, AtomicFile> mUserIdToStorageFile =
new ConcurrentHashMap<>();
+ void readStateForUsers(@NonNull List<UserInfo> users,
+ @NonNull Set<AssociationInfo> allAssociationsOut,
+ @NonNull SparseArray<Map<String, Set<Integer>>> previouslyUsedIdsPerUserOut) {
+ for (UserInfo user : users) {
+ final int userId = user.id;
+ // Previously used IDs are stored in the "out" collection per-user.
+ final Map<String, Set<Integer>> previouslyUsedIds = new ArrayMap<>();
+
+ // Associations for all users are stored in a single "flat" set: so we read directly
+ // into it.
+ readStateForUser(userId, allAssociationsOut, previouslyUsedIds);
+
+ // Save previously used IDs for this user into the "out" structure.
+ previouslyUsedIdsPerUserOut.append(userId, previouslyUsedIds);
+ }
+ }
+
/**
* Reads previously persisted data for the given user "into" the provided containers.
*
@@ -176,7 +199,7 @@
* @param previouslyUsedIdsPerPackageOut a container to read the used IDs "into".
*/
void readStateForUser(@UserIdInt int userId,
- @NonNull Set<AssociationInfo> associationsOut,
+ @NonNull Collection<AssociationInfo> associationsOut,
@NonNull Map<String, Set<Integer>> previouslyUsedIdsPerPackageOut) {
Slog.i(LOG_TAG, "Reading associations for user " + userId + " from disk");
final AtomicFile file = getStorageFileForUser(userId);
@@ -237,7 +260,8 @@
* @param associations a set of user's associations.
* @param previouslyUsedIdsPerPackage a set previously used Association IDs for the user.
*/
- void persistStateForUser(@UserIdInt int userId, @NonNull Set<AssociationInfo> associations,
+ void persistStateForUser(@UserIdInt int userId,
+ @NonNull Collection<AssociationInfo> associations,
@NonNull Map<String, Set<Integer>> previouslyUsedIdsPerPackage) {
Slog.i(LOG_TAG, "Writing associations for user " + userId + " to disk");
if (DEBUG) Slog.d(LOG_TAG, " > " + associations);
@@ -250,7 +274,7 @@
}
private int readStateFromFileLocked(@UserIdInt int userId, @NonNull AtomicFile file,
- @NonNull String rootTag, @Nullable Set<AssociationInfo> associationsOut,
+ @NonNull String rootTag, @Nullable Collection<AssociationInfo> associationsOut,
@NonNull Map<String, Set<Integer>> previouslyUsedIdsPerPackageOut) {
try (FileInputStream in = file.openRead()) {
final TypedXmlPullParser parser = Xml.resolvePullParser(in);
@@ -282,28 +306,25 @@
}
private void persistStateToFileLocked(@NonNull AtomicFile file,
- @Nullable Set<AssociationInfo> associations,
+ @Nullable Collection<AssociationInfo> associations,
@NonNull Map<String, Set<Integer>> previouslyUsedIdsPerPackage) {
- file.write(out -> {
- try {
- final TypedXmlSerializer serializer = Xml.resolveSerializer(out);
- serializer.setFeature(
- "http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ // Writing to file could fail, for example, if the user has been recently removed and so was
+ // their DE (/data/system_de/<user-id>/) directory.
+ writeToFileSafely(file, out -> {
+ final TypedXmlSerializer serializer = Xml.resolveSerializer(out);
+ serializer.setFeature(
+ "http://xmlpull.org/v1/doc/features.html#indent-output", true);
- serializer.startDocument(null, true);
- serializer.startTag(null, XML_TAG_STATE);
- writeIntAttribute(serializer,
- XML_ATTR_PERSISTENCE_VERSION, CURRENT_PERSISTENCE_VERSION);
+ serializer.startDocument(null, true);
+ serializer.startTag(null, XML_TAG_STATE);
+ writeIntAttribute(serializer,
+ XML_ATTR_PERSISTENCE_VERSION, CURRENT_PERSISTENCE_VERSION);
- writeAssociations(serializer, associations);
- writePreviouslyUsedIds(serializer, previouslyUsedIdsPerPackage);
+ writeAssociations(serializer, associations);
+ writePreviouslyUsedIds(serializer, previouslyUsedIdsPerPackage);
- serializer.endTag(null, XML_TAG_STATE);
- serializer.endDocument();
- } catch (Exception e) {
- Slog.e(LOG_TAG, "Error while writing associations file", e);
- throw ExceptionUtils.propagate(e);
- }
+ serializer.endTag(null, XML_TAG_STATE);
+ serializer.endDocument();
});
}
@@ -321,7 +342,7 @@
}
private static void readAssociationsV0(@NonNull TypedXmlPullParser parser,
- @UserIdInt int userId, @NonNull Set<AssociationInfo> out)
+ @UserIdInt int userId, @NonNull Collection<AssociationInfo> out)
throws XmlPullParserException, IOException {
requireStartOfTag(parser, XML_TAG_ASSOCIATIONS);
@@ -342,7 +363,8 @@
}
private static void readAssociationV0(@NonNull TypedXmlPullParser parser, @UserIdInt int userId,
- int associationId, @NonNull Set<AssociationInfo> out) throws XmlPullParserException {
+ int associationId, @NonNull Collection<AssociationInfo> out)
+ throws XmlPullParserException {
requireStartOfTag(parser, XML_TAG_ASSOCIATION);
final String appPackage = readStringAttribute(parser, XML_ATTR_PACKAGE);
@@ -360,7 +382,7 @@
}
private static void readAssociationsV1(@NonNull TypedXmlPullParser parser,
- @UserIdInt int userId, @NonNull Set<AssociationInfo> out)
+ @UserIdInt int userId, @NonNull Collection<AssociationInfo> out)
throws XmlPullParserException, IOException {
requireStartOfTag(parser, XML_TAG_ASSOCIATIONS);
@@ -374,7 +396,7 @@
}
private static void readAssociationV1(@NonNull TypedXmlPullParser parser, @UserIdInt int userId,
- @NonNull Set<AssociationInfo> out) throws XmlPullParserException, IOException {
+ @NonNull Collection<AssociationInfo> out) throws XmlPullParserException, IOException {
requireStartOfTag(parser, XML_TAG_ASSOCIATION);
final int associationId = readIntAttribute(parser, XML_ATTR_ID);
@@ -421,9 +443,11 @@
}
private static void writeAssociations(@NonNull XmlSerializer parent,
- @Nullable Set<AssociationInfo> associations) throws IOException {
+ @Nullable Collection<AssociationInfo> associations) throws IOException {
final XmlSerializer serializer = parent.startTag(null, XML_TAG_ASSOCIATIONS);
- forEach(associations, it -> writeAssociation(serializer, it));
+ for (AssociationInfo association : associations) {
+ writeAssociation(serializer, association);
+ }
serializer.endTag(null, XML_TAG_ASSOCIATIONS);
}
@@ -498,4 +522,13 @@
}
return associationInfo;
}
+
+ private static void writeToFileSafely(@NonNull AtomicFile file,
+ @NonNull ThrowingConsumer<FileOutputStream> consumer) {
+ try {
+ file.write(consumer);
+ } catch (Exception e) {
+ Slog.e(LOG_TAG, "Error while writing to file " + file, e);
+ }
+ }
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 826b16a..7b17162 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -163,6 +163,7 @@
"android.hardware.oemlock-V1.0-java",
"android.hardware.configstore-V1.1-java",
"android.hardware.contexthub-V1.0-java",
+ "android.hardware.ir-V1-java",
"android.hardware.rebootescrow-V1-java",
"android.hardware.soundtrigger-V2.3-java",
"android.hardware.power.stats-V1-java",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 6fe2806..9b2948f 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -50,6 +50,7 @@
import com.android.server.pm.pkg.AndroidPackageApi;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.mutate.PackageStateMutator;
import java.io.IOException;
import java.lang.annotation.Retention;
@@ -885,17 +886,6 @@
public abstract boolean userNeedsBadging(int userId);
/**
- * Perform the given action for each package.
- * Note that packages lock will be held while performing the actions.
- *
- * If the caller does not need all packages, prefer the potentially non-locking
- * {@link #withPackageSettingsSnapshot(Consumer)}.
- *
- * @param actionLocked action to be performed
- */
- public abstract void forEachPackage(Consumer<AndroidPackage> actionLocked);
-
- /**
* Perform the given action for each {@link PackageSetting}.
* Note that packages lock will be held while performing the actions.
*
@@ -918,12 +908,24 @@
public abstract void forEachPackageState(boolean locked, Consumer<PackageStateInternal> action);
/**
+ * {@link #forEachPackageState(boolean, Consumer)} but filtered to only states with packages
+ * on device where {@link PackageStateInternal#getPkg()} is not null.
+ */
+ public abstract void forEachPackage(Consumer<AndroidPackage> action);
+
+ /**
* Perform the given action for each installed package for a user.
* Note that packages lock will be held while performing the actions.
*/
public abstract void forEachInstalledPackage(
@NonNull Consumer<AndroidPackage> actionLocked, @UserIdInt int userId);
+ /**
+ * Perform the given action for each installed package for a user.
+ */
+ public abstract void forEachInstalledPackage(boolean locked,
+ @NonNull Consumer<AndroidPackage> action, @UserIdInt int userId);
+
/** Returns the list of enabled components */
public abstract ArraySet<String> getEnabledComponents(String packageName, int userId);
@@ -1265,4 +1267,62 @@
*/
public abstract void reconcileAppsData(int userId, @StorageManager.StorageFlags int flags,
boolean migrateAppsData);
+
+ /**
+ * Initiates a package state mutation request, returning the current state as known by
+ * PackageManager. This allows the later commit request to compare the initial values and
+ * determine if any state was changed or any packages were updated since the whole request
+ * was initiated.
+ *
+ * As a concrete example, consider the following steps:
+ * <ol>
+ * <li>Read a package state without taking a lock</li>
+ * <li>Check some values in that state, determine that a mutation needs to occur</li>
+ * <li>Call to commit the change with the new value, takes lock</li>
+ * </ol>
+ *
+ * Between steps 1 and 3, because the lock was not taken for the entire flow, it's possible
+ * a package state was changed by another consumer or a package was updated/installed.
+ *
+ * If anything has changed,
+ * {@link #commitPackageStateMutation(PackageStateMutator.InitialState, Consumer)} will return
+ * a {@link PackageStateMutator.Result} indicating so. If the caller has not indicated it can
+ * ignore changes, it can opt to re-run the commit logic from the top with a true write lock
+ * around all of its read-logic-commit loop.
+ *
+ * Note that if the caller does not care about potential race conditions or package/state
+ * changes between steps 1 and 3, it can simply opt to not call this method and pass in null
+ * for the initial state. This is useful to avoid long running data structure locks when the
+ * caller is changing a value as part of a one-off request. Perhaps from an app side API which
+ * mutates only a single package, where it doesn't care what the state of that package is or
+ * any other packages on the devices.
+ *
+ * Important to note is that if no locking is enforced, callers themselves will not be
+ * synchronized with themselves. The caller may be relying on the PackageManager lock to
+ * enforce ordering within their own code path, and that has to be adjusted if migrated off
+ * the lock.
+ */
+ @NonNull
+ public abstract PackageStateMutator.InitialState recordInitialState();
+
+ /**
+ * Some questions to ask when designing a mutation:
+ * <ol>
+ * <li>What external system state is required and is it synchronized properly?</li>
+ * <li>Are there any package/state changes that could happen to the target (or another)
+ * package that could result in the commit being invalid?</li>
+ * <li>Is the caller synchronized with itself and can handle multiple mutations being
+ * requested from different threads?</li>
+ * <li>What should be done in case of a conflict and the commit can't be finished?</li>
+ * </ol>
+ *
+ * @param state See {@link #recordInitialState()}. If null, no result is returned.
+ * @param consumer Lean wrapper around just the logic that changes state values
+ * @return result if anything changed since initial state, or null if nothing changed and
+ * commit was successful
+ */
+ @Nullable
+ public abstract PackageStateMutator.Result commitPackageStateMutation(
+ @Nullable PackageStateMutator.InitialState state,
+ @NonNull Consumer<PackageStateMutator> consumer);
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 450e988..bc8da84 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -17,12 +17,11 @@
package com.android.server;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
-import static android.content.PermissionChecker.PERMISSION_HARD_DENIED;
-import static android.content.PermissionChecker.PID_UNKNOWN;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.UserHandle.USER_SYSTEM;
+import static android.permission.PermissionCheckerManager.PERMISSION_HARD_DENIED;
import android.Manifest;
import android.annotation.NonNull;
@@ -54,7 +53,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.PermissionChecker;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
@@ -76,6 +74,7 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
+import android.permission.PermissionManager;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
@@ -110,10 +109,6 @@
private static final String BLUETOOTH_PRIVILEGED =
android.Manifest.permission.BLUETOOTH_PRIVILEGED;
- private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid";
- private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS = "bluetooth_address";
- private static final String SECURE_SETTINGS_BLUETOOTH_NAME = "bluetooth_name";
-
private static final int ACTIVE_LOG_MAX_SIZE = 20;
private static final int CRASH_LOG_MAX_SIZE = 100;
@@ -641,7 +636,7 @@
if (mContext.getResources()
.getBoolean(com.android.internal.R.bool.config_bluetooth_address_validation)
&& Settings.Secure.getIntForUser(mContentResolver,
- SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0, mUserId)
+ Settings.Secure.BLUETOOTH_NAME, 0, mUserId)
== 0) {
// if the valid flag is not set, don't load the address and name
if (DBG) {
@@ -650,9 +645,9 @@
return;
}
mName = Settings.Secure.getStringForUser(
- mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, mUserId);
+ mContentResolver, Settings.Secure.BLUETOOTH_NAME, mUserId);
mAddress = Settings.Secure.getStringForUser(
- mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, mUserId);
+ mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS, mUserId);
if (DBG) {
Slog.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
}
@@ -666,30 +661,30 @@
*/
private void storeNameAndAddress(String name, String address) {
if (name != null) {
- Settings.Secure.putStringForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name,
+ Settings.Secure.putStringForUser(mContentResolver, Settings.Secure.BLUETOOTH_NAME, name,
mUserId);
mName = name;
if (DBG) {
Slog.d(TAG, "Stored Bluetooth name: " + Settings.Secure.getStringForUser(
- mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME,
+ mContentResolver, Settings.Secure.BLUETOOTH_NAME,
mUserId));
}
}
if (address != null) {
- Settings.Secure.putStringForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS,
+ Settings.Secure.putStringForUser(mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS,
address, mUserId);
mAddress = address;
if (DBG) {
Slog.d(TAG,
"Stored Bluetoothaddress: " + Settings.Secure.getStringForUser(
- mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS,
+ mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS,
mUserId));
}
}
if ((name != null) && (address != null)) {
- Settings.Secure.putIntForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1,
+ Settings.Secure.putIntForUser(mContentResolver, Settings.Secure.BLUETOOTH_ADDR_VALID, 1,
mUserId);
}
}
@@ -2912,9 +2907,16 @@
@SuppressLint("AndroidFrameworkRequiresPermission")
private static boolean checkPermissionForDataDelivery(Context context, String permission,
AttributionSource attributionSource, String message) {
- final int result = PermissionChecker.checkPermissionForDataDeliveryFromDataSource(
- context, permission, PID_UNKNOWN,
- new AttributionSource(context.getAttributionSource(), attributionSource), message);
+ PermissionManager pm = context.getSystemService(PermissionManager.class);
+ if (pm == null) {
+ return false;
+ }
+ AttributionSource currentAttribution = new AttributionSource
+ .Builder(context.getAttributionSource())
+ .setNext(attributionSource)
+ .build();
+ final int result = pm.checkPermissionForDataDeliveryFromDataSource(permission,
+ currentAttribution, message);
if (result == PERMISSION_GRANTED) {
return true;
}
diff --git a/services/core/java/com/android/server/ConsumerIrService.java b/services/core/java/com/android/server/ConsumerIrService.java
index 2ed6c77..c4e84a4 100644
--- a/services/core/java/com/android/server/ConsumerIrService.java
+++ b/services/core/java/com/android/server/ConsumerIrService.java
@@ -19,17 +19,19 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.IConsumerIrService;
+import android.hardware.ir.ConsumerIrFreqRange;
+import android.hardware.ir.IConsumerIr;
import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Slog;
-import java.lang.RuntimeException;
-
public class ConsumerIrService extends IConsumerIrService.Stub {
private static final String TAG = "ConsumerIrService";
private static final int MAX_XMIT_TIME = 2000000; /* in microseconds */
- private static native boolean halOpen();
+ private static native boolean getHidlHalService();
private static native int halTransmit(int carrierFrequency, int[] pattern);
private static native int[] halGetCarrierFrequencies();
@@ -37,6 +39,7 @@
private final PowerManager.WakeLock mWakeLock;
private final boolean mHasNativeHal;
private final Object mHalLock = new Object();
+ private IConsumerIr mAidlService = null;
ConsumerIrService(Context context) {
mContext = context;
@@ -45,7 +48,8 @@
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mWakeLock.setReferenceCounted(true);
- mHasNativeHal = halOpen();
+ mHasNativeHal = getHalService();
+
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CONSUMER_IR)) {
if (!mHasNativeHal) {
throw new RuntimeException("FEATURE_CONSUMER_IR present, but no IR HAL loaded!");
@@ -60,6 +64,19 @@
return mHasNativeHal;
}
+ private boolean getHalService() {
+ // Attempt to get the AIDL HAL service first
+ final String fqName = IConsumerIr.DESCRIPTOR + "/default";
+ mAidlService = IConsumerIr.Stub.asInterface(
+ ServiceManager.waitForDeclaredService(fqName));
+ if (mAidlService != null) {
+ return true;
+ }
+
+ // Fall back to the HIDL HAL service
+ return getHidlHalService();
+ }
+
private void throwIfNoIrEmitter() {
if (!mHasNativeHal) {
throw new UnsupportedOperationException("IR emitter not available");
@@ -91,10 +108,18 @@
// Right now there is no mechanism to ensure fair queing of IR requests
synchronized (mHalLock) {
- int err = halTransmit(carrierFrequency, pattern);
+ if (mAidlService != null) {
+ try {
+ mAidlService.transmit(carrierFrequency, pattern);
+ } catch (RemoteException ignore) {
+ Slog.e(TAG, "Error transmitting frequency: " + carrierFrequency);
+ }
+ } else {
+ int err = halTransmit(carrierFrequency, pattern);
- if (err < 0) {
- Slog.e(TAG, "Error transmitting: " + err);
+ if (err < 0) {
+ Slog.e(TAG, "Error transmitting: " + err);
+ }
}
}
}
@@ -109,7 +134,24 @@
throwIfNoIrEmitter();
synchronized(mHalLock) {
- return halGetCarrierFrequencies();
+ if (mAidlService != null) {
+ try {
+ ConsumerIrFreqRange[] output = mAidlService.getCarrierFreqs();
+ if (output.length <= 0) {
+ Slog.e(TAG, "Error getting carrier frequencies.");
+ }
+ int[] result = new int[output.length * 2];
+ for (int i = 0; i < output.length; i++) {
+ result[i * 2] = output[i].minHz;
+ result[i * 2 + 1] = output[i].maxHz;
+ }
+ return result;
+ } catch (RemoteException ignore) {
+ return null;
+ }
+ } else {
+ return halGetCarrierFrequencies();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 91d6488..2ec4a02 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -632,6 +632,12 @@
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered, int index) {
boolean skip = false;
+ if (r.options != null && !r.options.testRequireCompatChange(filter.owningUid)) {
+ Slog.w(TAG, "Compat change filtered: broadcasting " + r.intent.toString()
+ + " to uid " + filter.owningUid + " due to compat change "
+ + r.options.getRequireCompatChangeId());
+ skip = true;
+ }
if (!mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
filter.packageName, filter.owningUid)) {
Slog.w(TAG, "Association not allowed: broadcasting "
@@ -1407,6 +1413,13 @@
+ "] broadcasting " + broadcastDescription(r, component));
skip = true;
}
+ if (brOptions != null &&
+ !brOptions.testRequireCompatChange(info.activityInfo.applicationInfo.uid)) {
+ Slog.w(TAG, "Compat change filtered: broadcasting " + broadcastDescription(r, component)
+ + " to uid " + info.activityInfo.applicationInfo.uid + " due to compat change "
+ + r.options.getRequireCompatChangeId());
+ skip = true;
+ }
if (!skip && !mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
component.getPackageName(), info.activityInfo.applicationInfo.uid)) {
Slog.w(TAG, "Association not allowed: broadcasting "
diff --git a/services/core/java/com/android/server/am/OomAdjuster.md b/services/core/java/com/android/server/am/OomAdjuster.md
index eda511a..febc37b 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.md
+++ b/services/core/java/com/android/server/am/OomAdjuster.md
@@ -59,6 +59,7 @@
* The next two factors are either it was the previous process with visible UI to the user, or it's a backup agent.
* And then it goes to the massive searches against the service connections and the content providers, each of the clients will be evaluated, and the Oom Adj score could get updated according to its clients' scores. However there are a bunch of service binding flags which could impact the result:
* Below table captures the results with given various service binding states:
+
| Conditon #1 | Condition #2 | Condition #3 | Condition #4 | Result |
|---------------------------------|------------------------------------------------------------|----------------------------------------------|---------------------------------------------------|--------------------------|
| `BIND_WAIVE_PRIORITY` not set | `BIND_ALLOW_OOM_MANAGEMENT` set | Shown UI && Not Home | | Use the app's own Adj |
@@ -83,6 +84,7 @@
| | | `BIND_NOT_FOREGROUND` not set | `BIND_IMPORTANT` is set | Sched = top app bound |
| | | | `BIND_IMPORTANT` is NOT set | Sched = default |
* Below table captures the results with given various content provider binding states:
+
| Conditon #1 | Condition #2 | Condition #3 | Result |
|---------------------------------|------------------------------------------------------------|----------------------------------------------|--------------------------|
| Client's process state >= cached| | | Client ProcState = empty |
@@ -95,6 +97,7 @@
| Still within retain time | Adj > previous app Adj | | adj = previuos app adj |
| | Process state > last activity | | ProcState = last activity|
* Some additional tweaks after the above ones:
+
| Conditon #1 | Condition #2 | Condition #3 | Result |
|---------------------------------|------------------------------------------------------------|----------------------------------------------|------------------------------------|
| Process state >= cached empty | Has client activities | | ProcState = cached activity client |
diff --git a/services/core/java/com/android/server/app/GameClassifier.java b/services/core/java/com/android/server/app/GameClassifier.java
new file mode 100644
index 0000000..e20bf46
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameClassifier.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+import android.annotation.NonNull;
+import android.os.UserHandle;
+
+/**
+ * Responsible for determining if a given application is a game.
+ */
+interface GameClassifier {
+
+ /**
+ * Returns {@code true} if the application associated with the given {@code packageName} is
+ * considered to be a game. The application is queried as the user associated with the given
+ * {@code userHandle}.
+ */
+ boolean isGame(@NonNull String packageName, @NonNull UserHandle userHandle);
+}
diff --git a/services/core/java/com/android/server/app/GameClassifierImpl.java b/services/core/java/com/android/server/app/GameClassifierImpl.java
new file mode 100644
index 0000000..8f5b0f0
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameClassifierImpl.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+import android.annotation.NonNull;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+
+final class GameClassifierImpl implements GameClassifier {
+
+ private final PackageManager mPackageManager;
+
+ GameClassifierImpl(@NonNull PackageManager packageManager) {
+ mPackageManager = packageManager;
+ }
+
+ @Override
+ public boolean isGame(@NonNull String packageName, @NonNull UserHandle userHandle) {
+ @ApplicationInfo.Category
+ int applicationCategory = ApplicationInfo.CATEGORY_UNDEFINED;
+
+ try {
+ applicationCategory =
+ mPackageManager.getApplicationInfoAsUser(
+ packageName,
+ 0,
+ userHandle.getIdentifier()).category;
+ } catch (PackageManager.NameNotFoundException ex) {
+ return false;
+ }
+
+ return applicationCategory == ApplicationInfo.CATEGORY_GAME;
+ }
+}
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index fc48cd5..0980f40 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -76,6 +76,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.compat.CompatibilityOverrideConfig;
import com.android.internal.compat.IPlatformCompat;
+import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
@@ -563,7 +564,12 @@
mService.registerPackageReceiver();
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_GAME_SERVICE)) {
- mGameServiceController = new GameServiceController(context);
+ mGameServiceController = new GameServiceController(
+ BackgroundThread.getExecutor(),
+ new GameServiceProviderSelectorImpl(
+ getContext().getResources(),
+ getContext().getPackageManager()),
+ new GameServiceProviderInstanceFactoryImpl(getContext()));
}
}
@@ -586,6 +592,14 @@
}
@Override
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ super.onUserUnlocking(user);
+ if (mGameServiceController != null) {
+ mGameServiceController.notifyUserUnlocking(user);
+ }
+ }
+
+ @Override
public void onUserStopping(@NonNull TargetUser user) {
mService.onUserStopping(user.getUserIdentifier());
if (mGameServiceController != null) {
diff --git a/services/core/java/com/android/server/app/GameServiceConnection.java b/services/core/java/com/android/server/app/GameServiceConnection.java
deleted file mode 100644
index b607789..0000000
--- a/services/core/java/com/android/server/app/GameServiceConnection.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.app;
-
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.service.games.GameService;
-import android.service.games.IGameService;
-import android.util.Slog;
-
-final class GameServiceConnection {
- private static final String TAG = "GameServiceConnection";
- private static final boolean DEBUG = false;
-
- private final Context mContext;
- private final ComponentName mGameServiceComponent;
- private final int mUser;
- private boolean mIsBound;
- @Nullable
- private IGameService mGameService;
- private final ServiceConnection mConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- if (DEBUG) {
- Slog.d(TAG, "onServiceConnected to " + name + " for user(" + mUser + ")");
- }
-
- mGameService = IGameService.Stub.asInterface(service);
- try {
- mGameService.connected();
- } catch (RemoteException e) {
- Slog.w(TAG, "RemoteException while calling ready", e);
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG) {
- Slog.d(TAG, "onServiceDisconnected to " + name);
- }
-
- mGameService = null;
- }
- };
-
- GameServiceConnection(Context context, ComponentName gameServiceComponent, int user) {
- mContext = context;
- mGameServiceComponent = gameServiceComponent;
- mUser = user;
- }
-
- public void connect() {
- if (mIsBound) {
- Slog.v(TAG, "Already bound, ignoring start.");
- return;
- }
-
- Intent intent = new Intent(GameService.SERVICE_INTERFACE);
- intent.setComponent(mGameServiceComponent);
- mIsBound = mContext.bindServiceAsUser(intent, mConnection,
- Context.BIND_AUTO_CREATE
- | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, new UserHandle(mUser));
- if (!mIsBound) {
- Slog.w(TAG, "Failed binding to game service " + mGameServiceComponent);
- }
- }
-
- public void disconnect() {
- try {
- if (mGameService != null) {
- mGameService.disconnected();
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "RemoteException in shutdown", e);
- }
-
- if (mIsBound) {
- mContext.unbindService(mConnection);
- mIsBound = false;
- }
- }
-}
diff --git a/services/core/java/com/android/server/app/GameServiceController.java b/services/core/java/com/android/server/app/GameServiceController.java
index d056ea9..ac720b9 100644
--- a/services/core/java/com/android/server/app/GameServiceController.java
+++ b/services/core/java/com/android/server/app/GameServiceController.java
@@ -18,40 +18,56 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.service.games.GameService;
-import android.text.TextUtils;
+import android.annotation.WorkerThread;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.server.SystemService;
-import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+/**
+ * Responsible for managing the Game Service API.
+ *
+ * Key responsibilities selecting the active Game Service provider, binding to the Game Service
+ * provider services, and driving the GameService/GameSession lifecycles.
+ */
final class GameServiceController {
private static final String TAG = "GameServiceController";
- private static final boolean DEBUG = false;
- private final Context mContext;
+
+ private final Object mLock = new Object();
+ private final Executor mBackgroundExecutor;
+ private final GameServiceProviderSelector mGameServiceProviderSelector;
+ private final GameServiceProviderInstanceFactory mGameServiceProviderInstanceFactory;
+
+ private volatile boolean mHasBootCompleted;
@Nullable
- private SystemService.TargetUser mCurrentForegroundUser;
- private boolean mHasBootCompleted;
-
+ private volatile SystemService.TargetUser mCurrentForegroundUser;
+ @GuardedBy("mLock")
@Nullable
- private GameServiceConnection mGameServiceConnection;
+ private volatile GameServiceProviderConfiguration mActiveGameServiceProviderConfiguration;
+ @GuardedBy("mLock")
+ @Nullable
+ private volatile GameServiceProviderInstance mGameServiceProviderInstance;
- GameServiceController(Context context) {
- mContext = context;
+ GameServiceController(
+ @NonNull Executor backgroundExecutor,
+ @NonNull GameServiceProviderSelector gameServiceProviderSelector,
+ @NonNull GameServiceProviderInstanceFactory gameServiceProviderInstanceFactory) {
+ mGameServiceProviderInstanceFactory = gameServiceProviderInstanceFactory;
+ mBackgroundExecutor = backgroundExecutor;
+ mGameServiceProviderSelector = gameServiceProviderSelector;
}
void onBootComplete() {
+ if (mHasBootCompleted) {
+ return;
+ }
mHasBootCompleted = true;
- evaluateGameServiceConnection();
+ mBackgroundExecutor.execute(this::evaluateActiveGameServiceProvider);
}
void notifyUserStarted(@NonNull SystemService.TargetUser user) {
@@ -59,96 +75,86 @@
return;
}
- mCurrentForegroundUser = user;
- evaluateGameServiceConnection();
+ setCurrentForegroundUserAndEvaluateProvider(user);
}
void notifyNewForegroundUser(@NonNull SystemService.TargetUser user) {
- mCurrentForegroundUser = user;
- evaluateGameServiceConnection();
+ setCurrentForegroundUserAndEvaluateProvider(user);
}
- void notifyUserStopped(@NonNull SystemService.TargetUser user) {
- if (mCurrentForegroundUser == null
- || mCurrentForegroundUser.getUserIdentifier() != user.getUserIdentifier()) {
+ void notifyUserUnlocking(@NonNull SystemService.TargetUser user) {
+ boolean isSameAsForegroundUser =
+ mCurrentForegroundUser != null
+ && mCurrentForegroundUser.getUserIdentifier() == user.getUserIdentifier();
+ if (!isSameAsForegroundUser) {
return;
}
- mCurrentForegroundUser = null;
- evaluateGameServiceConnection();
+ // It is likely that the Game Service provider's components are not Direct Boot mode aware
+ // and will not be capable of running until the user has unlocked the device. To allow for
+ // this we re-evaluate the active game service provider once these components are available.
+
+ mBackgroundExecutor.execute(this::evaluateActiveGameServiceProvider);
}
- private void evaluateGameServiceConnection() {
+ void notifyUserStopped(@NonNull SystemService.TargetUser user) {
+ boolean isSameAsForegroundUser =
+ mCurrentForegroundUser != null
+ && mCurrentForegroundUser.getUserIdentifier() == user.getUserIdentifier();
+ if (!isSameAsForegroundUser) {
+ return;
+ }
+
+ setCurrentForegroundUserAndEvaluateProvider(null);
+ }
+
+ private void setCurrentForegroundUserAndEvaluateProvider(
+ @Nullable SystemService.TargetUser user) {
+ boolean hasUserChanged =
+ !Objects.equals(mCurrentForegroundUser, user);
+ if (!hasUserChanged) {
+ return;
+ }
+ mCurrentForegroundUser = user;
+
+ mBackgroundExecutor.execute(this::evaluateActiveGameServiceProvider);
+ }
+
+ @WorkerThread
+ private void evaluateActiveGameServiceProvider() {
if (!mHasBootCompleted) {
return;
}
- // TODO(b/204565942): Only shutdown the existing service connection if the game service
- // provider or user has changed.
- if (mGameServiceConnection != null) {
- mGameServiceConnection.disconnect();
- mGameServiceConnection = null;
- }
+ synchronized (mLock) {
+ GameServiceProviderConfiguration selectedGameServiceProviderConfiguration =
+ mGameServiceProviderSelector.get(mCurrentForegroundUser);
- boolean isUserSupported =
- mCurrentForegroundUser != null
- && mCurrentForegroundUser.isFull()
- && !mCurrentForegroundUser.isManagedProfile();
- if (!isUserSupported) {
- if (DEBUG && mCurrentForegroundUser != null) {
- Slog.d(TAG, "User not supported: " + mCurrentForegroundUser);
+ boolean didActiveGameServiceProviderChanged =
+ !Objects.equals(selectedGameServiceProviderConfiguration,
+ mActiveGameServiceProviderConfiguration);
+ if (!didActiveGameServiceProviderChanged) {
+ return;
}
- return;
- }
- ComponentName gameServiceComponentName =
- determineGameServiceComponentName(mCurrentForegroundUser.getUserIdentifier());
- if (gameServiceComponentName == null) {
- return;
- }
-
- mGameServiceConnection = new GameServiceConnection(
- mContext,
- gameServiceComponentName,
- mCurrentForegroundUser.getUserIdentifier());
- mGameServiceConnection.connect();
- }
-
- @Nullable
- private ComponentName determineGameServiceComponentName(int userId) {
- String gameServicePackage =
- mContext.getResources().getString(
- com.android.internal.R.string.config_systemGameService);
- if (TextUtils.isEmpty(gameServicePackage)) {
- if (DEBUG) {
- Slog.d(TAG, "No game service package defined");
+ if (mGameServiceProviderInstance != null) {
+ Slog.i(TAG, "Stopping Game Service provider: "
+ + mActiveGameServiceProviderConfiguration);
+ mGameServiceProviderInstance.stop();
}
- return null;
- }
- List<ResolveInfo> gameServiceResolveInfos =
- mContext.getPackageManager().queryIntentServicesAsUser(
- new Intent(GameService.SERVICE_INTERFACE).setPackage(gameServicePackage),
- PackageManager.MATCH_SYSTEM_ONLY,
- userId);
+ mActiveGameServiceProviderConfiguration = selectedGameServiceProviderConfiguration;
- if (gameServiceResolveInfos.isEmpty()) {
- Slog.v(TAG, "No available game service found for user id: " + userId);
- return null;
- }
-
- for (ResolveInfo resolveInfo : gameServiceResolveInfos) {
- if (resolveInfo.serviceInfo == null) {
- continue;
+ if (mActiveGameServiceProviderConfiguration == null) {
+ return;
}
- final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
- if (!serviceInfo.isEnabled()) {
- continue;
- }
- return serviceInfo.getComponentName();
- }
- Slog.v(TAG, "No game service found for user id: " + userId);
- return null;
+ Slog.i(TAG,
+ "Starting Game Service provider: " + mActiveGameServiceProviderConfiguration);
+ mGameServiceProviderInstance =
+ mGameServiceProviderInstanceFactory.create(
+ mActiveGameServiceProviderConfiguration);
+ mGameServiceProviderInstance.start();
+ }
}
}
diff --git a/services/core/java/com/android/server/app/GameServiceProviderConfiguration.java b/services/core/java/com/android/server/app/GameServiceProviderConfiguration.java
new file mode 100644
index 0000000..7c8f251
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameServiceProviderConfiguration.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.os.UserHandle;
+
+import java.util.Objects;
+
+/**
+ * Representation of a {@link android.service.games.GameService} provider configuration.
+ */
+final class GameServiceProviderConfiguration {
+ private final UserHandle mUserHandle;
+ private final ComponentName mGameServiceComponentName;
+ private final ComponentName mGameSessionServiceComponentName;
+
+ GameServiceProviderConfiguration(
+ @NonNull UserHandle userHandle,
+ @NonNull ComponentName gameServiceComponentName,
+ @NonNull ComponentName gameSessionServiceComponentName) {
+ Objects.requireNonNull(userHandle);
+ Objects.requireNonNull(gameServiceComponentName);
+ Objects.requireNonNull(gameSessionServiceComponentName);
+
+ this.mUserHandle = userHandle;
+ this.mGameServiceComponentName = gameServiceComponentName;
+ this.mGameSessionServiceComponentName = gameSessionServiceComponentName;
+ }
+
+ @NonNull
+ public UserHandle getUserHandle() {
+ return mUserHandle;
+ }
+
+ @NonNull
+ public ComponentName getGameServiceComponentName() {
+ return mGameServiceComponentName;
+ }
+
+ @NonNull
+ public ComponentName getGameSessionServiceComponentName() {
+ return mGameSessionServiceComponentName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof GameServiceProviderConfiguration)) {
+ return false;
+ }
+
+ GameServiceProviderConfiguration that = (GameServiceProviderConfiguration) o;
+ return mUserHandle.equals(that.mUserHandle)
+ && mGameServiceComponentName.equals(that.mGameServiceComponentName)
+ && mGameSessionServiceComponentName.equals(that.mGameSessionServiceComponentName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUserHandle, mGameServiceComponentName,
+ mGameSessionServiceComponentName);
+ }
+
+ @Override
+ public String toString() {
+ return "GameServiceProviderConfiguration{"
+ + "mUserHandle="
+ + mUserHandle
+ + ", gameServiceComponentName="
+ + mGameServiceComponentName
+ + ", gameSessionServiceComponentName="
+ + mGameSessionServiceComponentName
+ + '}';
+ }
+}
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstance.java b/services/core/java/com/android/server/app/GameServiceProviderInstance.java
new file mode 100644
index 0000000..e83f9ac
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstance.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+/**
+ * Representation of an instance of a Game Service provider.
+ *
+ * This includes maintaining the bindings and driving the interactions with the provider's
+ * implementations of {@link android.service.games.GameService} and
+ * {@link android.service.games.GameSessionService}.
+ */
+interface GameServiceProviderInstance {
+ /**
+ * Begins running the Game Service provider instance.
+ */
+ void start();
+
+ /**
+ * Stops running the Game Service provider instance.
+ */
+ void stop();
+}
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactory.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactory.java
new file mode 100644
index 0000000..7640cc5
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactory.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+import android.annotation.NonNull;
+
+/**
+ * Factory for creating {@link GameServiceProviderInstance}.
+ */
+interface GameServiceProviderInstanceFactory {
+
+ @NonNull
+ GameServiceProviderInstance create(@NonNull
+ GameServiceProviderConfiguration gameServiceProviderConfiguration);
+}
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
new file mode 100644
index 0000000..d5ac03a
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+import android.annotation.NonNull;
+import android.app.ActivityTaskManager;
+import android.content.Context;
+import android.content.Intent;
+import android.service.games.GameService;
+import android.service.games.GameSessionService;
+import android.service.games.IGameService;
+import android.service.games.IGameSessionService;
+
+import com.android.internal.infra.ServiceConnector;
+import com.android.internal.os.BackgroundThread;
+
+final class GameServiceProviderInstanceFactoryImpl implements GameServiceProviderInstanceFactory {
+ private final Context mContext;
+
+ GameServiceProviderInstanceFactoryImpl(@NonNull Context context) {
+ this.mContext = context;
+ }
+
+ @NonNull
+ @Override
+ public GameServiceProviderInstance create(@NonNull
+ GameServiceProviderConfiguration gameServiceProviderConfiguration) {
+ return new GameServiceProviderInstanceImpl(
+ gameServiceProviderConfiguration.getUserHandle(),
+ BackgroundThread.getExecutor(),
+ new GameClassifierImpl(mContext.getPackageManager()),
+ ActivityTaskManager.getService(),
+ new GameServiceConnector(mContext, gameServiceProviderConfiguration),
+ new GameSessionServiceConnector(mContext, gameServiceProviderConfiguration));
+ }
+
+ private static final class GameServiceConnector extends ServiceConnector.Impl<IGameService> {
+ private static final int DISABLE_AUTOMATIC_DISCONNECT_TIMEOUT = 0;
+ private static final int BINDING_FLAGS = Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS;
+
+ GameServiceConnector(
+ @NonNull Context context,
+ @NonNull GameServiceProviderConfiguration configuration) {
+ super(context, new Intent(GameService.ACTION_GAME_SERVICE)
+ .setComponent(configuration.getGameServiceComponentName()),
+ BINDING_FLAGS, configuration.getUserHandle().getIdentifier(),
+ IGameService.Stub::asInterface);
+ }
+
+ @Override
+ protected long getAutoDisconnectTimeoutMs() {
+ return DISABLE_AUTOMATIC_DISCONNECT_TIMEOUT;
+ }
+ }
+
+ private static final class GameSessionServiceConnector extends
+ ServiceConnector.Impl<IGameSessionService> {
+ private static final int DISABLE_AUTOMATIC_DISCONNECT_TIMEOUT = 0;
+ private static final int BINDING_FLAGS =
+ Context.BIND_TREAT_LIKE_ACTIVITY
+ | Context.BIND_SCHEDULE_LIKE_TOP_APP
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS;
+
+ GameSessionServiceConnector(
+ @NonNull Context context,
+ @NonNull GameServiceProviderConfiguration configuration) {
+ super(context, new Intent(GameSessionService.ACTION_GAME_SESSION_SERVICE)
+ .setComponent(configuration.getGameSessionServiceComponentName()),
+ BINDING_FLAGS, configuration.getUserHandle().getIdentifier(),
+ IGameSessionService.Stub::asInterface);
+ }
+
+ @Override
+ protected long getAutoDisconnectTimeoutMs() {
+ return DISABLE_AUTOMATIC_DISCONNECT_TIMEOUT;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
new file mode 100644
index 0000000..3f3f257
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+import android.annotation.NonNull;
+import android.app.IActivityTaskManager;
+import android.app.TaskStackListener;
+import android.content.ComponentName;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.games.CreateGameSessionRequest;
+import android.service.games.IGameService;
+import android.service.games.IGameSession;
+import android.service.games.IGameSessionService;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.infra.ServiceConnector;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
+final class GameServiceProviderInstanceImpl implements GameServiceProviderInstance {
+ private static final String TAG = "GameServiceProviderInstance";
+ private static final int CREATE_GAME_SESSION_TIMEOUT_MS = 10_000;
+ private static final boolean DEBUG = false;
+
+ private final TaskStackListener mTaskStackListener = new TaskStackListener() {
+ @Override
+ public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
+ if (componentName == null) {
+ return;
+ }
+
+ mBackgroundExecutor.execute(() -> {
+ GameServiceProviderInstanceImpl.this.onTaskCreated(taskId, componentName);
+ });
+ }
+
+ @Override
+ public void onTaskRemoved(int taskId) throws RemoteException {
+ mBackgroundExecutor.execute(() -> {
+ GameServiceProviderInstanceImpl.this.onTaskRemoved(taskId);
+ });
+ }
+ };
+ private final Object mLock = new Object();
+ private final UserHandle mUserHandle;
+ private final Executor mBackgroundExecutor;
+ private final GameClassifier mGameClassifier;
+ private final IActivityTaskManager mActivityTaskManager;
+ private final ServiceConnector<IGameService> mGameServiceConnector;
+ private final ServiceConnector<IGameSessionService> mGameSessionServiceConnector;
+
+ @GuardedBy("mLock")
+ private final ConcurrentHashMap<Integer, GameSessionRecord> mGameSessions =
+ new ConcurrentHashMap<>();
+ @GuardedBy("mLock")
+ private volatile boolean mIsRunning;
+
+ GameServiceProviderInstanceImpl(
+ UserHandle userHandle,
+ @NonNull Executor backgroundExecutor,
+ @NonNull GameClassifier gameClassifier,
+ @NonNull IActivityTaskManager activityTaskManager,
+ @NonNull ServiceConnector<IGameService> gameServiceConnector,
+ @NonNull ServiceConnector<IGameSessionService> gameSessionServiceConnector) {
+ mUserHandle = userHandle;
+ mBackgroundExecutor = backgroundExecutor;
+ mGameClassifier = gameClassifier;
+ mActivityTaskManager = activityTaskManager;
+ mGameServiceConnector = gameServiceConnector;
+ mGameSessionServiceConnector = gameSessionServiceConnector;
+ }
+
+ @Override
+ public void start() {
+ synchronized (mLock) {
+ startLocked();
+ }
+ }
+
+ @Override
+ public void stop() {
+ synchronized (mLock) {
+ stopLocked();
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void startLocked() {
+ if (mIsRunning) {
+ return;
+ }
+ mIsRunning = true;
+
+ // TODO(b/204503192): In cases where the connection to the game service fails retry with
+ // back off mechanism.
+ AndroidFuture<Void> unusedPostConnectedFuture = mGameServiceConnector.post(gameService -> {
+ gameService.connected();
+ });
+
+ try {
+ mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to register task stack listener", e);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void stopLocked() {
+ if (!mIsRunning) {
+ return;
+ }
+ mIsRunning = false;
+
+ try {
+ mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to unregister task stack listener", e);
+ }
+
+ for (GameSessionRecord gameSessionRecord : mGameSessions.values()) {
+ IGameSession gameSession = gameSessionRecord.getGameSession();
+ if (gameSession == null) {
+ continue;
+ }
+
+ try {
+ gameSession.destroy();
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to destroy session: " + gameSessionRecord, ex);
+ }
+ }
+ mGameSessions.clear();
+
+ // TODO(b/204503192): It is possible that the game service is disconnected. In this
+ // case we should avoid rebinding just to shut it down again.
+ AndroidFuture<Void> unusedPostDisconnectedFuture =
+ mGameServiceConnector.post(gameService -> {
+ gameService.disconnected();
+ });
+ mGameServiceConnector.unbind();
+ mGameSessionServiceConnector.unbind();
+ }
+
+ private void onTaskCreated(int taskId, @NonNull ComponentName componentName) {
+ String packageName = componentName.getPackageName();
+ if (!mGameClassifier.isGame(packageName, mUserHandle)) {
+ return;
+ }
+
+ synchronized (mLock) {
+ createGameSessionLocked(taskId, componentName);
+ }
+ }
+
+ private void onTaskRemoved(int taskId) {
+ synchronized (mLock) {
+ boolean isTaskAssociatedWithGameSession = mGameSessions.containsKey(taskId);
+ if (!isTaskAssociatedWithGameSession) {
+ return;
+ }
+
+ destroyGameSessionLocked(taskId);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void createGameSessionLocked(int sessionId, @NonNull ComponentName componentName) {
+ if (DEBUG) {
+ Slog.i(TAG, "createGameSession() id: " + sessionId + " component: " + componentName);
+ }
+
+ if (!mIsRunning) {
+ return;
+ }
+
+ GameSessionRecord existingGameSessionRecord = mGameSessions.get(sessionId);
+ if (existingGameSessionRecord != null) {
+ Slog.w(TAG, "Existing game session found for task (id: " + sessionId
+ + ") creation. Ignoring.");
+ return;
+ }
+
+ GameSessionRecord gameSessionRecord = GameSessionRecord.pendingGameSession(sessionId,
+ componentName);
+ mGameSessions.put(sessionId, gameSessionRecord);
+
+ // TODO(b/207035150): Allow the game service provider to determine if a game session
+ // should be created. For now we will assume all games should have a session.
+ AndroidFuture<IBinder> gameSessionFuture = new AndroidFuture<IBinder>()
+ .orTimeout(CREATE_GAME_SESSION_TIMEOUT_MS, TimeUnit.MILLISECONDS)
+ .whenCompleteAsync((gameSessionIBinder, exception) -> {
+ IGameSession gameSession = IGameSession.Stub.asInterface(gameSessionIBinder);
+ if (exception != null || gameSession == null) {
+ Slog.w(TAG, "Failed to create GameSession: " + gameSessionRecord,
+ exception);
+ synchronized (mLock) {
+ destroyGameSessionLocked(sessionId);
+ }
+ return;
+ }
+
+ synchronized (mLock) {
+ attachGameSessionLocked(sessionId, gameSession);
+ }
+ }, mBackgroundExecutor);
+
+ AndroidFuture<Void> unusedPostCreateGameSessionFuture =
+ mGameSessionServiceConnector.post(gameService -> {
+ CreateGameSessionRequest createGameSessionRequest =
+ new CreateGameSessionRequest(sessionId, componentName.getPackageName());
+ gameService.create(createGameSessionRequest, gameSessionFuture);
+ });
+ }
+
+ @GuardedBy("mLock")
+ private void attachGameSessionLocked(int sessionId, @NonNull IGameSession gameSession) {
+ if (DEBUG) {
+ Slog.i(TAG, "attachGameSession() id: " + sessionId);
+ }
+
+ GameSessionRecord gameSessionRecord = mGameSessions.get(sessionId);
+ if (gameSessionRecord == null) {
+ Slog.w(TAG, "No associated game session record. Destroying id: " + sessionId);
+
+ try {
+ gameSession.destroy();
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to destroy session: " + gameSessionRecord, ex);
+ }
+ return;
+ }
+
+ mGameSessions.put(sessionId, gameSessionRecord.withGameSession(gameSession));
+ }
+
+ @GuardedBy("mLock")
+ private void destroyGameSessionLocked(int sessionId) {
+ // TODO(b/204503192): Limit the lifespan of the game session in the Game Service provider
+ // to only when the associated task is running. Right now it is possible for a task to
+ // move into the background and for all associated processes to die and for the Game Session
+ // provider's GameSessionService to continue to be running. Ideally we could unbind the
+ // service when this happens.
+ if (DEBUG) {
+ Slog.i(TAG, "destroyGameSession() id: " + sessionId);
+ }
+
+ GameSessionRecord gameSessionRecord = mGameSessions.remove(sessionId);
+ if (gameSessionRecord == null) {
+ if (DEBUG) {
+ Slog.w(TAG, "No game session found for id: " + sessionId);
+ }
+ return;
+ }
+
+ IGameSession gameSession = gameSessionRecord.getGameSession();
+ if (gameSession != null) {
+ try {
+ gameSession.destroy();
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to destroy session: " + gameSessionRecord, ex);
+ }
+ }
+
+ if (mGameSessions.isEmpty()) {
+ if (DEBUG) {
+ Slog.i(TAG, "No active game sessions. Disconnecting GameSessionService");
+ }
+
+ if (mGameSessionServiceConnector != null) {
+ mGameSessionServiceConnector.unbind();
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/app/GameServiceProviderSelector.java b/services/core/java/com/android/server/app/GameServiceProviderSelector.java
new file mode 100644
index 0000000..51d3515
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameServiceProviderSelector.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+import android.annotation.Nullable;
+
+import com.android.server.SystemService;
+
+/**
+ * Responsible for determining what the active Game Service provider should be.
+ */
+interface GameServiceProviderSelector {
+
+ /**
+ * Returns the {@link GameServiceProviderConfiguration} associated with the selected Game
+ * Service provider for the given user or {@code null} if none should be used.
+ */
+ @Nullable
+ GameServiceProviderConfiguration get(@Nullable SystemService.TargetUser user);
+}
diff --git a/services/core/java/com/android/server/app/GameServiceProviderSelectorImpl.java b/services/core/java/com/android/server/app/GameServiceProviderSelectorImpl.java
new file mode 100644
index 0000000..54ef707
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameServiceProviderSelectorImpl.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.UserHandle;
+import android.service.games.GameService;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.server.SystemService;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.List;
+
+final class GameServiceProviderSelectorImpl implements GameServiceProviderSelector {
+ private static final String TAG = "GameServiceProviderSelector";
+ private static final String GAME_SERVICE_NODE_NAME = "game-service";
+ private static final boolean DEBUG = false;
+
+ private final Resources mResources;
+ private final PackageManager mPackageManager;
+
+ GameServiceProviderSelectorImpl(@NonNull Resources resources,
+ @NonNull PackageManager packageManager) {
+ mResources = resources;
+ mPackageManager = packageManager;
+ }
+
+ @Override
+ @Nullable
+ public GameServiceProviderConfiguration get(@Nullable SystemService.TargetUser user) {
+ if (user == null) {
+ return null;
+ }
+
+ boolean isUserSupported = user.isFull() && !user.isManagedProfile();
+ if (!isUserSupported) {
+ Slog.i(TAG, "Game Service not supported for user: " + user.getUserIdentifier());
+ return null;
+ }
+
+ String gameServicePackage =
+ mResources.getString(
+ com.android.internal.R.string.config_systemGameService);
+
+ if (TextUtils.isEmpty(gameServicePackage)) {
+ Slog.w(TAG, "No game service package defined");
+ return null;
+ }
+
+ int userId = user.getUserIdentifier();
+ List<ResolveInfo> gameServiceResolveInfos =
+ mPackageManager.queryIntentServicesAsUser(
+ new Intent(GameService.ACTION_GAME_SERVICE).setPackage(gameServicePackage),
+ PackageManager.GET_META_DATA | PackageManager.MATCH_SYSTEM_ONLY,
+ userId);
+ if (DEBUG) {
+ Slog.i(TAG, "Querying package: " + gameServicePackage + " and user id: " + userId);
+ Slog.i(TAG, "Found resolve infos: " + gameServiceResolveInfos);
+ }
+
+ if (gameServiceResolveInfos == null || gameServiceResolveInfos.isEmpty()) {
+ Slog.w(TAG, "No available game service found for user id: " + userId);
+ return null;
+ }
+
+ GameServiceProviderConfiguration selectedProvider = null;
+ for (ResolveInfo resolveInfo : gameServiceResolveInfos) {
+ if (resolveInfo.serviceInfo == null) {
+ continue;
+ }
+ ServiceInfo gameServiceServiceInfo = resolveInfo.serviceInfo;
+
+ ComponentName gameSessionServiceComponentName =
+ determineGameSessionServiceFromGameService(gameServiceServiceInfo);
+ if (gameSessionServiceComponentName == null) {
+ continue;
+ }
+
+ selectedProvider =
+ new GameServiceProviderConfiguration(
+ new UserHandle(userId),
+ gameServiceServiceInfo.getComponentName(),
+ gameSessionServiceComponentName);
+ break;
+ }
+
+ if (selectedProvider == null) {
+ Slog.w(TAG, "No valid game service found for user id: " + userId);
+ return null;
+ }
+
+ return selectedProvider;
+ }
+
+ @Nullable
+ private ComponentName determineGameSessionServiceFromGameService(
+ @NonNull ServiceInfo gameServiceServiceInfo) {
+ String gameSessionService;
+ try (XmlResourceParser parser = gameServiceServiceInfo.loadXmlMetaData(mPackageManager,
+ GameService.SERVICE_META_DATA)) {
+ if (parser == null) {
+ Slog.w(TAG, "No " + GameService.SERVICE_META_DATA + " meta-data found for "
+ + gameServiceServiceInfo.getComponentName());
+ return null;
+ }
+
+ Resources resources = mPackageManager.getResourcesForApplication(
+ gameServiceServiceInfo.packageName);
+
+ AttributeSet attributeSet = Xml.asAttributeSet(parser);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ // Do nothing
+ }
+
+ boolean isStartingTagGameService = GAME_SERVICE_NODE_NAME.equals(parser.getName());
+ if (!isStartingTagGameService) {
+ Slog.w(TAG, "Meta-data does not start with " + GAME_SERVICE_NODE_NAME + " tag");
+ return null;
+ }
+
+ TypedArray array = resources.obtainAttributes(attributeSet,
+ com.android.internal.R.styleable.GameService);
+ gameSessionService = array.getString(
+ com.android.internal.R.styleable.GameService_gameSessionService);
+ array.recycle();
+ } catch (PackageManager.NameNotFoundException | XmlPullParserException | IOException ex) {
+ Slog.w("Error while parsing meta-data for " + gameServiceServiceInfo.getComponentName(),
+ ex);
+ return null;
+ }
+
+ if (TextUtils.isEmpty(gameSessionService)) {
+ Slog.w(TAG, "No gameSessionService specified");
+ return null;
+ }
+ ComponentName componentName =
+ new ComponentName(gameServiceServiceInfo.packageName, gameSessionService);
+
+ try {
+ mPackageManager.getServiceInfo(componentName, /* flags= */ 0);
+ } catch (PackageManager.NameNotFoundException ex) {
+ Slog.w(TAG, "GameSessionService does not exist: " + componentName);
+ return null;
+ }
+
+ return componentName;
+ }
+}
diff --git a/services/core/java/com/android/server/app/GameSessionRecord.java b/services/core/java/com/android/server/app/GameSessionRecord.java
new file mode 100644
index 0000000..329e9e8
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameSessionRecord.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.service.games.IGameSession;
+
+import java.util.Objects;
+
+final class GameSessionRecord {
+
+ private final int mTaskId;
+ private final ComponentName mRootComponentName;
+ @Nullable
+ private final IGameSession mIGameSession;
+
+ static GameSessionRecord pendingGameSession(int taskId, ComponentName rootComponentName) {
+ return new GameSessionRecord(taskId, rootComponentName, /* gameSession= */ null);
+ }
+
+ private GameSessionRecord(
+ int taskId,
+ @NonNull ComponentName rootComponentName,
+ @Nullable IGameSession gameSession) {
+ this.mTaskId = taskId;
+ this.mRootComponentName = rootComponentName;
+ this.mIGameSession = gameSession;
+ }
+
+ @NonNull
+ public GameSessionRecord withGameSession(@NonNull IGameSession gameSession) {
+ Objects.requireNonNull(gameSession);
+ return new GameSessionRecord(mTaskId, mRootComponentName, gameSession);
+ }
+
+ @Nullable
+ public IGameSession getGameSession() {
+ return mIGameSession;
+ }
+
+ @Override
+ public String toString() {
+ return "GameSessionRecord{"
+ + "mTaskId="
+ + mTaskId
+ + ", mRootComponentName="
+ + mRootComponentName
+ + ", mIGameSession="
+ + mIGameSession
+ + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof GameSessionRecord)) {
+ return false;
+ }
+
+ GameSessionRecord that = (GameSessionRecord) o;
+ return mTaskId == that.mTaskId && mRootComponentName.equals(that.mRootComponentName)
+ && Objects.equals(mIGameSession, that.mIGameSession);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTaskId, mRootComponentName, mIGameSession);
+ }
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 8615393..902cdb9 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -9771,7 +9771,7 @@
projection)) {
Slog.w(TAG, "Permission denied to register audio policy for pid "
+ Binder.getCallingPid() + " / uid " + Binder.getCallingUid()
- + ", need MODIFY_AUDIO_ROUTING or MediaProjection that can project audio");
+ + ", need system permission or a MediaProjection that can project audio");
return null;
}
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index b333ed2..406b2dd2 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -817,7 +817,7 @@
// the same time if we still have a public client.
while (clientIterator.hasNext()) {
PlayMonitorClient pmc = clientIterator.next();
- if (pcdb.equals(pmc.mDispatcherCb)) {
+ if (pcdb.asBinder().equals(pmc.mDispatcherCb.asBinder())) {
pmc.release();
clientIterator.remove();
} else {
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index 2465ec5..6f71768 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -38,8 +38,8 @@
private static final String TAG = "Biometrics/AcquisitionClient";
- private static final VibrationAttributes TOUCH_VIBRATION_ATTRIBUTES =
- VibrationAttributes.createForUsage(VibrationAttributes.USAGE_TOUCH);
+ private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES =
+ VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);
private static final VibrationEffect SUCCESS_VIBRATION_EFFECT =
VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
@@ -196,7 +196,7 @@
getContext().getOpPackageName(),
SUCCESS_VIBRATION_EFFECT,
getClass().getSimpleName() + "::success",
- TOUCH_VIBRATION_ATTRIBUTES);
+ HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES);
}
}
@@ -207,7 +207,7 @@
getContext().getOpPackageName(),
ERROR_VIBRATION_EFFECT,
getClass().getSimpleName() + "::error",
- TOUCH_VIBRATION_ATTRIBUTES);
+ HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES);
}
}
}
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index e2e56ae..9dd7daf 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -36,6 +36,8 @@
import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.internal.compat.CompatibilityChangeInfo;
import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesByPackageConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveByPackageConfig;
import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
import com.android.internal.compat.IOverrideValidator;
import com.android.internal.compat.OverrideAllowedState;
@@ -220,15 +222,47 @@
}
/**
- * Overrides the enabled state for a given change and app.
+ * Adds compat config overrides for multiple packages.
*
+ * <p>Equivalent to calling
+ * {@link #addPackageOverrides(CompatibilityOverrideConfig, String, boolean)} on each entry
+ * in {@code overridesByPackage}, but the state of the compat config will be updated only
+ * once instead of for each package.
*
- * @param overrides list of overrides to default changes config.
- * @param packageName app for which the overrides will be applied.
+ * @param overridesByPackage map from package name to compat config overrides to add for that
+ * package.
+ * @param skipUnknownChangeIds whether to skip unknown change IDs in {@code overridesByPackage}.
+ */
+ synchronized void addAllPackageOverrides(
+ CompatibilityOverridesByPackageConfig overridesByPackage,
+ boolean skipUnknownChangeIds) {
+ for (String packageName : overridesByPackage.packageNameToOverrides.keySet()) {
+ addPackageOverridesWithoutSaving(
+ overridesByPackage.packageNameToOverrides.get(packageName), packageName,
+ skipUnknownChangeIds);
+ }
+ saveOverrides();
+ invalidateCache();
+ }
+
+ /**
+ * Adds compat config overrides for a given package.
+ *
+ * <p>Note, package overrides are not persistent and will be lost on system or runtime restart.
+ *
+ * @param overrides list of compat config overrides to add for the given package.
+ * @param packageName app for which the overrides will be applied.
* @param skipUnknownChangeIds whether to skip unknown change IDs in {@code overrides}.
*/
synchronized void addPackageOverrides(CompatibilityOverrideConfig overrides,
String packageName, boolean skipUnknownChangeIds) {
+ addPackageOverridesWithoutSaving(overrides, packageName, skipUnknownChangeIds);
+ saveOverrides();
+ invalidateCache();
+ }
+
+ private void addPackageOverridesWithoutSaving(CompatibilityOverrideConfig overrides,
+ String packageName, boolean skipUnknownChangeIds) {
for (Long changeId : overrides.overrides.keySet()) {
if (skipUnknownChangeIds && !isKnownChangeId(changeId)) {
Slog.w(TAG, "Trying to add overrides for unknown Change ID " + changeId + ". "
@@ -237,8 +271,6 @@
}
addOverrideUnsafe(changeId, packageName, overrides.overrides.get(changeId));
}
- saveOverrides();
- invalidateCache();
}
private boolean addOverrideUnsafe(long changeId, String packageName,
@@ -344,6 +376,36 @@
}
/**
+ * Removes overrides with a specified change ID that were previously added via
+ * {@link #addOverride(long, String, boolean)} or
+ * {@link #addPackageOverrides(CompatibilityOverrideConfig, String, boolean)} for multiple
+ * packages.
+ *
+ * <p>Equivalent to calling
+ * {@link #removePackageOverrides(CompatibilityOverridesToRemoveConfig, String)} on each entry
+ * in {@code overridesToRemoveByPackage}, but the state of the compat config will be updated
+ * only once instead of for each package.
+ *
+ * @param overridesToRemoveByPackage map from package name to a list of change IDs for
+ * which to restore the default behaviour for that
+ * package.
+ */
+ synchronized void removeAllPackageOverrides(
+ CompatibilityOverridesToRemoveByPackageConfig overridesToRemoveByPackage) {
+ boolean shouldInvalidateCache = false;
+ for (String packageName :
+ overridesToRemoveByPackage.packageNameToOverridesToRemove.keySet()) {
+ shouldInvalidateCache |= removePackageOverridesWithoutSaving(
+ overridesToRemoveByPackage.packageNameToOverridesToRemove.get(packageName),
+ packageName);
+ }
+ if (shouldInvalidateCache) {
+ saveOverrides();
+ invalidateCache();
+ }
+ }
+
+ /**
* Removes all overrides previously added via {@link #addOverride(long, String, boolean)} or
* {@link #addPackageOverrides(CompatibilityOverrideConfig, String, boolean)} for a certain
* package.
@@ -377,6 +439,16 @@
*/
synchronized void removePackageOverrides(CompatibilityOverridesToRemoveConfig overridesToRemove,
String packageName) {
+ boolean shouldInvalidateCache = removePackageOverridesWithoutSaving(overridesToRemove,
+ packageName);
+ if (shouldInvalidateCache) {
+ saveOverrides();
+ invalidateCache();
+ }
+ }
+
+ private boolean removePackageOverridesWithoutSaving(
+ CompatibilityOverridesToRemoveConfig overridesToRemove, String packageName) {
boolean shouldInvalidateCache = false;
for (Long changeId : overridesToRemove.changeIds) {
if (!isKnownChangeId(changeId)) {
@@ -386,10 +458,7 @@
}
shouldInvalidateCache |= removeOverrideUnsafe(changeId, packageName);
}
- if (shouldInvalidateCache) {
- saveOverrides();
- invalidateCache();
- }
+ return shouldInvalidateCache;
}
private long[] getAllowedChangesSinceTargetSdkForPackage(String packageName,
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 6ea89d4..aab6281 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -47,6 +47,8 @@
import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.internal.compat.CompatibilityChangeInfo;
import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesByPackageConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveByPackageConfig;
import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
import com.android.internal.compat.IOverrideValidator;
import com.android.internal.compat.IPlatformCompat;
@@ -226,9 +228,19 @@
}
@Override
+ public void putAllOverridesOnReleaseBuilds(
+ CompatibilityOverridesByPackageConfig overridesByPackage) {
+ checkCompatChangeOverrideOverridablePermission();
+ for (CompatibilityOverrideConfig overrides :
+ overridesByPackage.packageNameToOverrides.values()) {
+ checkAllCompatOverridesAreOverridable(overrides.overrides.keySet());
+ }
+ mCompatConfig.addAllPackageOverrides(overridesByPackage, /* skipUnknownChangeIds= */ true);
+ }
+
+ @Override
public void putOverridesOnReleaseBuilds(CompatibilityOverrideConfig overrides,
String packageName) {
- // TODO(b/183630314): Unify the permission enforcement with the other setOverrides* methods.
checkCompatChangeOverrideOverridablePermission();
checkAllCompatOverridesAreOverridable(overrides.overrides.keySet());
mCompatConfig.addPackageOverrides(overrides, packageName, /* skipUnknownChangeIds= */ true);
@@ -280,10 +292,20 @@
}
@Override
+ public void removeAllOverridesOnReleaseBuilds(
+ CompatibilityOverridesToRemoveByPackageConfig overridesToRemoveByPackage) {
+ checkCompatChangeOverrideOverridablePermission();
+ for (CompatibilityOverridesToRemoveConfig overridesToRemove :
+ overridesToRemoveByPackage.packageNameToOverridesToRemove.values()) {
+ checkAllCompatOverridesAreOverridable(overridesToRemove.changeIds);
+ }
+ mCompatConfig.removeAllPackageOverrides(overridesToRemoveByPackage);
+ }
+
+ @Override
public void removeOverridesOnReleaseBuilds(
CompatibilityOverridesToRemoveConfig overridesToRemove,
String packageName) {
- // TODO(b/183630314): Unify the permission enforcement with the other setOverrides* methods.
checkCompatChangeOverrideOverridablePermission();
checkAllCompatOverridesAreOverridable(overridesToRemove.changeIds);
mCompatConfig.removePackageOverrides(overridesToRemove, packageName);
diff --git a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
index 7e58b6c..880dbf6 100644
--- a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
+++ b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
@@ -41,11 +41,14 @@
import android.os.ServiceManager;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesByPackageConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveByPackageConfig;
import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
import com.android.internal.compat.IPlatformCompat;
import com.android.server.SystemService;
@@ -150,6 +153,9 @@
Set<String> packageNames = new ArraySet<>(properties.getKeyset());
packageNames.remove(FLAG_OWNED_CHANGE_IDS);
packageNames.remove(FLAG_REMOVE_OVERRIDES);
+ Map<String, CompatibilityOverrideConfig> packageNameToOverridesToAdd = new ArrayMap<>();
+ Map<String, CompatibilityOverridesToRemoveConfig> packageNameToOverridesToRemove =
+ new ArrayMap<>();
for (String packageName : packageNames) {
Long versionCode = getVersionCodeOrNull(packageName);
if (versionCode == null) {
@@ -157,11 +163,30 @@
continue;
}
- applyPackageOverrides(properties.getString(packageName, /* defaultValue= */ ""),
- packageName, versionCode, ownedChangeIds,
- packageToChangeIdsToSkip.getOrDefault(packageName, emptySet()),
- /* removeOtherOwnedOverrides= */ true);
+ Set<Long> changeIdsToSkip = packageToChangeIdsToSkip.getOrDefault(packageName,
+ emptySet());
+ Map<Long, PackageOverride> overridesToAdd = mOverridesParser.parsePackageOverrides(
+ properties.getString(packageName, /* defaultValue= */ ""), packageName,
+ versionCode, changeIdsToSkip);
+ if (!overridesToAdd.isEmpty()) {
+ packageNameToOverridesToAdd.put(packageName,
+ new CompatibilityOverrideConfig(overridesToAdd));
+ }
+
+ Set<Long> overridesToRemove = new ArraySet<>();
+ for (Long changeId : ownedChangeIds) {
+ if (!overridesToAdd.containsKey(changeId) && !changeIdsToSkip.contains(changeId)) {
+ overridesToRemove.add(changeId);
+ }
+ }
+ if (!overridesToRemove.isEmpty()) {
+ packageNameToOverridesToRemove.put(packageName,
+ new CompatibilityOverridesToRemoveConfig(overridesToRemove));
+ }
}
+
+ putAllPackageOverrides(packageNameToOverridesToAdd);
+ removeAllPackageOverrides(packageNameToOverridesToRemove);
}
/**
@@ -177,42 +202,15 @@
// We apply overrides for each namespace separately so that if there is a failure for
// one namespace, the other namespaces won't be affected.
Set<Long> ownedChangeIds = getOwnedChangeIds(namespace);
- applyPackageOverrides(
- DeviceConfig.getString(namespace, packageName, /* defaultValue= */ ""),
- packageName, versionCode, ownedChangeIds,
+ putPackageOverrides(packageName, mOverridesParser.parsePackageOverrides(
+ DeviceConfig.getString(namespace, packageName, /* defaultValue= */""),
+ packageName, versionCode,
getOverridesToRemove(namespace, ownedChangeIds).getOrDefault(packageName,
- emptySet()), /* removeOtherOwnedOverrides */ false);
+ emptySet())));
}
}
/**
- * Calls {@link AppCompatOverridesParser#parsePackageOverrides} on the given arguments and adds
- * the resulting overrides via {@link IPlatformCompat#putOverridesOnReleaseBuilds}.
- *
- * <p>In addition, if {@code removeOtherOwnedOverrides} is true, removes any override that
- * wasn't just added, whose change ID is in {@code ownedChangeIds} but not in {@code
- * changeIdsToSkip}, via {@link IPlatformCompat#removeOverridesOnReleaseBuilds}.
- */
- private void applyPackageOverrides(String configStr, String packageName, long versionCode,
- Set<Long> ownedChangeIds, Set<Long> changeIdsToSkip,
- boolean removeOtherOwnedOverrides) {
- Map<Long, PackageOverride> overridesToAdd = mOverridesParser.parsePackageOverrides(
- configStr, packageName, versionCode, changeIdsToSkip);
- putPackageOverrides(packageName, overridesToAdd);
-
- if (!removeOtherOwnedOverrides) {
- return;
- }
- Set<Long> overridesToRemove = new ArraySet<>();
- for (Long changeId : ownedChangeIds) {
- if (!overridesToAdd.containsKey(changeId) && !changeIdsToSkip.contains(changeId)) {
- overridesToRemove.add(changeId);
- }
- }
- removePackageOverrides(packageName, overridesToRemove);
- }
-
- /**
* Removes all owned overrides in all supported namespaces for the given {@code packageName}.
*
* <p>If a certain namespace doesn't have a package override flag for the given {@code
@@ -231,14 +229,18 @@
}
/**
- * Calls {@link IPlatformCompat#removeOverridesOnReleaseBuilds} on each package name and
- * respective change IDs in {@code overridesToRemove}.
+ * Calls {@link IPlatformCompat#removeAllOverridesOnReleaseBuilds} on {@code
+ * packageNameToOverridesToRemove}.
*/
- private void removeOverrides(Map<String, Set<Long>> overridesToRemove) {
- for (Map.Entry<String, Set<Long>> packageNameAndOverrides : overridesToRemove.entrySet()) {
- removePackageOverrides(packageNameAndOverrides.getKey(),
- packageNameAndOverrides.getValue());
+ private void removeOverrides(Map<String, Set<Long>> packageNameToOverridesToRemove) {
+ Map<String, CompatibilityOverridesToRemoveConfig> packageNameToConfig =
+ new ArrayMap<>();
+ for (Map.Entry<String, Set<Long>> packageNameAndChangeIds :
+ packageNameToOverridesToRemove.entrySet()) {
+ packageNameToConfig.put(packageNameAndChangeIds.getKey(),
+ new CompatibilityOverridesToRemoveConfig(packageNameAndChangeIds.getValue()));
}
+ removeAllPackageOverrides(packageNameToConfig);
}
/**
@@ -262,6 +264,20 @@
DeviceConfig.getString(namespace, FLAG_OWNED_CHANGE_IDS, /* defaultValue= */ ""));
}
+ private void putAllPackageOverrides(
+ Map<String, CompatibilityOverrideConfig> packageNameToOverrides) {
+ if (packageNameToOverrides.isEmpty()) {
+ return;
+ }
+ CompatibilityOverridesByPackageConfig config = new CompatibilityOverridesByPackageConfig(
+ packageNameToOverrides);
+ try {
+ mPlatformCompat.putAllOverridesOnReleaseBuilds(config);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to call IPlatformCompat#putAllOverridesOnReleaseBuilds", e);
+ }
+ }
+
private void putPackageOverrides(String packageName,
Map<Long, PackageOverride> overridesToAdd) {
if (overridesToAdd.isEmpty()) {
@@ -271,7 +287,21 @@
try {
mPlatformCompat.putOverridesOnReleaseBuilds(config, packageName);
} catch (RemoteException e) {
- Slog.w(TAG, "Failed to call IPlatformCompat#putOverridesOnReleaseBuilds", e);
+ Slog.e(TAG, "Failed to call IPlatformCompat#putOverridesOnReleaseBuilds", e);
+ }
+ }
+
+ private void removeAllPackageOverrides(
+ Map<String, CompatibilityOverridesToRemoveConfig> packageNameToOverridesToRemove) {
+ if (packageNameToOverridesToRemove.isEmpty()) {
+ return;
+ }
+ CompatibilityOverridesToRemoveByPackageConfig config =
+ new CompatibilityOverridesToRemoveByPackageConfig(packageNameToOverridesToRemove);
+ try {
+ mPlatformCompat.removeAllOverridesOnReleaseBuilds(config);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to call IPlatformCompat#removeAllOverridesOnReleaseBuilds", e);
}
}
@@ -284,7 +314,7 @@
try {
mPlatformCompat.removeOverridesOnReleaseBuilds(config, packageName);
} catch (RemoteException e) {
- Slog.w(TAG, "Failed to call IPlatformCompat#removeOverridesOnReleaseBuilds", e);
+ Slog.e(TAG, "Failed to call IPlatformCompat#removeOverridesOnReleaseBuilds", e);
}
}
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index a56a8ea..72e900b 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -25,9 +25,7 @@
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.WARNING_DISABLED;
-import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
import static android.net.NetworkTemplate.OEM_MANAGED_ALL;
-import static android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT;
import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -77,6 +75,8 @@
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
+import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@@ -224,12 +224,13 @@
"Can't get TelephonyManager for subId %d", subId));
}
- subscriberId = tele.getSubscriberId();
- mNetworkTemplate = new NetworkTemplate(
- NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId },
- null, NetworkStats.METERED_YES, NetworkStats.ROAMING_ALL,
- NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ subscriberId = Objects.requireNonNull(tele.getSubscriberId(),
+ "Null subscriber Id for subId " + subId);
+ mNetworkTemplate = new NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE)
+ .setSubscriberIds(Set.of(subscriberId))
+ .setMeteredness(NetworkStats.METERED_YES)
+ .setDefaultNetworkStatus(NetworkStats.DEFAULT_NETWORK_NO)
+ .build();
mUsageCallback = new UsageCallback() {
@Override
public void onThresholdReached(int networkType, String subscriberId) {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index bf4ef48..a2fed291 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -17,6 +17,8 @@
package com.android.server.connectivity;
import static android.Manifest.permission.BIND_VPN_SERVICE;
+import static android.Manifest.permission.CONTROL_VPN;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
@@ -932,6 +934,7 @@
* - oldPackage null, newPackage non-null: ConfirmDialog calling prepareVpn().
* - oldPackage null, newPackage=LEGACY_VPN: Used internally to disconnect
* and revoke any current app VPN and re-prepare legacy vpn.
+ * - oldPackage null, newPackage null: always returns true for backward compatibility.
*
* TODO: Rename the variables - or split this method into two - and end this confusion.
* TODO: b/29032008 Migrate code from prepare(oldPackage=non-null, newPackage=LEGACY_VPN)
@@ -945,6 +948,18 @@
*/
public synchronized boolean prepare(
String oldPackage, String newPackage, @VpnManager.VpnType int vpnType) {
+ // Except for Settings and VpnDialogs, the caller should be matched one of oldPackage or
+ // newPackage. Otherwise, non VPN owner might get the VPN always-on status of the VPN owner.
+ // See b/191382886.
+ if (mContext.checkCallingOrSelfPermission(CONTROL_VPN) != PERMISSION_GRANTED) {
+ if (oldPackage != null) {
+ verifyCallingUidAndPackage(oldPackage);
+ }
+ if (newPackage != null) {
+ verifyCallingUidAndPackage(newPackage);
+ }
+ }
+
if (oldPackage != null) {
// Stop an existing always-on VPN from being dethroned by other apps.
if (mAlwaysOn && !isCurrentPreparedPackage(oldPackage)) {
@@ -1859,14 +1874,13 @@
}
private void enforceControlPermission() {
- mContext.enforceCallingPermission(Manifest.permission.CONTROL_VPN, "Unauthorized Caller");
+ mContext.enforceCallingPermission(CONTROL_VPN, "Unauthorized Caller");
}
private void enforceControlPermissionOrInternalCaller() {
// Require the caller to be either an application with CONTROL_VPN permission or a process
// in the system server.
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CONTROL_VPN,
- "Unauthorized Caller");
+ mContext.enforceCallingOrSelfPermission(CONTROL_VPN, "Unauthorized Caller");
}
private void enforceSettingsPermission() {
@@ -3176,8 +3190,9 @@
}
private void verifyCallingUidAndPackage(String packageName) {
- if (getAppUid(packageName, mUserId) != Binder.getCallingUid()) {
- throw new SecurityException("Mismatched package and UID");
+ final int callingUid = Binder.getCallingUid();
+ if (getAppUid(packageName, mUserId) != callingUid) {
+ throw new SecurityException(packageName + " does not belong to uid " + callingUid);
}
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index c0a6abf..c4f2b14 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -714,7 +714,6 @@
display.getDisplayInfoLocked().shouldConstrainMetricsForLauncher;
if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
handleLogicalDisplayChangedLocked(display);
- scheduleTraversalLocked(false);
}
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index c5dc23e..47e0e69 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -72,16 +72,16 @@
@NonNull private final WindowManagerInternal mWindowManagerInternal;
@NonNull private final Resources mRes;
- private long mLastBindTime;
- private boolean mHasConnection;
- @Nullable private String mCurId;
- @Nullable private String mSelectedMethodId;
- @Nullable private Intent mCurIntent;
- @Nullable private IInputMethod mCurMethod;
- private int mCurMethodUid = Process.INVALID_UID;
- private IBinder mCurToken;
- private int mCurSeq;
- private boolean mVisibleBound;
+ @GuardedBy("mMethodMap") private long mLastBindTime;
+ @GuardedBy("mMethodMap") private boolean mHasConnection;
+ @GuardedBy("mMethodMap") @Nullable private String mCurId;
+ @GuardedBy("mMethodMap") @Nullable private String mSelectedMethodId;
+ @GuardedBy("mMethodMap") @Nullable private Intent mCurIntent;
+ @GuardedBy("mMethodMap") @Nullable private IInputMethod mCurMethod;
+ @GuardedBy("mMethodMap") private int mCurMethodUid = Process.INVALID_UID;
+ @GuardedBy("mMethodMap") private IBinder mCurToken;
+ @GuardedBy("mMethodMap") private int mCurSeq;
+ @GuardedBy("mMethodMap") private boolean mVisibleBound;
private boolean mSupportsStylusHw;
/**
@@ -146,6 +146,7 @@
* Time that we last initiated a bind to the input method, to determine
* if we should try to disconnect and reconnect to it.
*/
+ @GuardedBy("mMethodMap")
long getLastBindTime() {
return mLastBindTime;
}
@@ -154,6 +155,7 @@
* Set to true if our ServiceConnection is currently actively bound to
* a service (whether or not we have gotten its IBinder back yet).
*/
+ @GuardedBy("mMethodMap")
boolean hasConnection() {
return mHasConnection;
}
@@ -166,6 +168,7 @@
*
* @see #getSelectedMethodId()
*/
+ @GuardedBy("mMethodMap")
@Nullable
String getCurId() {
return mCurId;
@@ -184,11 +187,13 @@
*
* @see #getCurId()
*/
+ @GuardedBy("mMethodMap")
@Nullable
String getSelectedMethodId() {
return mSelectedMethodId;
}
+ @GuardedBy("mMethodMap")
void setSelectedMethodId(@Nullable String selectedMethodId) {
mSelectedMethodId = selectedMethodId;
}
@@ -197,6 +202,7 @@
* The token we have made for the currently active input method, to
* identify it in the future.
*/
+ @GuardedBy("mMethodMap")
IBinder getCurToken() {
return mCurToken;
}
@@ -204,6 +210,7 @@
/**
* The Intent used to connect to the current input method.
*/
+ @GuardedBy("mMethodMap")
@Nullable
Intent getCurIntent() {
return mCurIntent;
@@ -213,6 +220,7 @@
* The current binding sequence number, incremented every time there is
* a new bind performed.
*/
+ @GuardedBy("mMethodMap")
int getSequenceNumber() {
return mCurSeq;
}
@@ -221,6 +229,7 @@
* Increase the current binding sequence number by one.
* Reset to 1 on overflow.
*/
+ @GuardedBy("mMethodMap")
void advanceSequenceNumber() {
mCurSeq += 1;
if (mCurSeq <= 0) {
@@ -232,6 +241,7 @@
* If non-null, this is the input method service we are currently connected
* to.
*/
+ @GuardedBy("mMethodMap")
@Nullable
IInputMethod getCurMethod() {
return mCurMethod;
@@ -240,6 +250,7 @@
/**
* If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntent()}.
*/
+ @GuardedBy("mMethodMap")
int getCurMethodUid() {
return mCurMethodUid;
}
@@ -247,6 +258,7 @@
/**
* Indicates whether {@link #mVisibleConnection} is currently in use.
*/
+ @GuardedBy("mMethodMap")
boolean isVisibleBound() {
return mVisibleBound;
}
@@ -254,11 +266,12 @@
/**
* Used to bring IME service up to visible adjustment while it is being shown.
*/
+ @GuardedBy("mMethodMap")
private final ServiceConnection mVisibleConnection = new ServiceConnection() {
@Override public void onBindingDied(ComponentName name) {
synchronized (mMethodMap) {
if (mVisibleBound) {
- unbindVisibleConnectionLocked();
+ unbindVisibleConnection();
}
}
}
@@ -273,6 +286,7 @@
/**
* Used to bind the IME while it is not currently being shown.
*/
+ @GuardedBy("mMethodMap")
private final ServiceConnection mMainConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
@@ -280,10 +294,10 @@
synchronized (mMethodMap) {
if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
mCurMethod = IInputMethod.Stub.asInterface(service);
- updateCurrentMethodUidLocked();
+ updateCurrentMethodUid();
if (mCurToken == null) {
Slog.w(TAG, "Service connected without a token!");
- unbindCurrentMethodLocked();
+ unbindCurrentMethod();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return;
}
@@ -305,7 +319,7 @@
}
@GuardedBy("mMethodMap")
- private void updateCurrentMethodUidLocked() {
+ private void updateCurrentMethodUid() {
final String curMethodPackage = mCurIntent.getComponent().getPackageName();
final int curMethodUid = mPackageManagerInternal.getPackageUid(
curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId());
@@ -339,7 +353,7 @@
// We consider this to be a new bind attempt, since the system
// should now try to restart the service for us.
mLastBindTime = SystemClock.uptimeMillis();
- clearCurMethodAndSessionsLocked();
+ clearCurMethodAndSessions();
mService.clearInputShowRequestLocked();
mService.unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME);
}
@@ -348,34 +362,34 @@
};
@GuardedBy("mMethodMap")
- void unbindCurrentMethodLocked() {
+ void unbindCurrentMethod() {
if (mVisibleBound) {
- unbindVisibleConnectionLocked();
+ unbindVisibleConnection();
}
if (mHasConnection) {
- unbindMainConnectionLocked();
+ unbindMainConnection();
}
if (mCurToken != null) {
- removeCurrentTokenLocked();
+ removeCurrentToken();
mService.resetSystemUiLocked();
}
mCurId = null;
- clearCurMethodAndSessionsLocked();
+ clearCurMethodAndSessions();
}
@GuardedBy("mMethodMap")
- private void clearCurMethodAndSessionsLocked() {
+ private void clearCurMethodAndSessions() {
mService.clearClientSessionsLocked();
mCurMethod = null;
mCurMethodUid = Process.INVALID_UID;
}
@GuardedBy("mMethodMap")
- private void removeCurrentTokenLocked() {
- int curTokenDisplayId = mService.getCurTokenDisplayId();
+ private void removeCurrentToken() {
+ int curTokenDisplayId = mService.getCurTokenDisplayIdLocked();
if (DEBUG) {
Slog.v(TAG,
@@ -388,7 +402,7 @@
@GuardedBy("mMethodMap")
@NonNull
- InputBindResult bindCurrentMethodLocked() {
+ InputBindResult bindCurrentMethod() {
InputMethodInfo info = mMethodMap.get(mSelectedMethodId);
if (info == null) {
throw new IllegalArgumentException("Unknown id: " + mSelectedMethodId);
@@ -396,11 +410,11 @@
mCurIntent = createImeBindingIntent(info.getComponent());
- if (bindCurrentInputMethodServiceMainConnectionLocked()) {
+ if (bindCurrentInputMethodServiceMainConnection()) {
mCurId = info.getId();
mLastBindTime = SystemClock.uptimeMillis();
- addFreshWindowTokenLocked();
+ addFreshWindowToken();
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
null, null, mCurId, mCurSeq, false);
@@ -425,11 +439,11 @@
}
@GuardedBy("mMethodMap")
- private void addFreshWindowTokenLocked() {
- int displayIdToShowIme = mService.getDisplayIdToShowIme();
+ private void addFreshWindowToken() {
+ int displayIdToShowIme = mService.getDisplayIdToShowImeLocked();
mCurToken = new Binder();
- mService.setCurTokenDisplayId(displayIdToShowIme);
+ mService.setCurTokenDisplayIdLocked(displayIdToShowIme);
try {
if (DEBUG) {
@@ -445,19 +459,19 @@
}
@GuardedBy("mMethodMap")
- private void unbindMainConnectionLocked() {
+ private void unbindMainConnection() {
mContext.unbindService(mMainConnection);
mHasConnection = false;
}
@GuardedBy("mMethodMap")
- void unbindVisibleConnectionLocked() {
+ void unbindVisibleConnection() {
mContext.unbindService(mVisibleConnection);
mVisibleBound = false;
}
@GuardedBy("mMethodMap")
- private boolean bindCurrentInputMethodServiceLocked(ServiceConnection conn, int flags) {
+ private boolean bindCurrentInputMethodService(ServiceConnection conn, int flags) {
if (mCurIntent == null || conn == null) {
Slog.e(TAG, "--- bind failed: service = " + mCurIntent + ", conn = " + conn);
return false;
@@ -467,15 +481,15 @@
}
@GuardedBy("mMethodMap")
- private boolean bindCurrentInputMethodServiceVisibleConnectionLocked() {
- mVisibleBound = bindCurrentInputMethodServiceLocked(mVisibleConnection,
+ private boolean bindCurrentInputMethodServiceVisibleConnection() {
+ mVisibleBound = bindCurrentInputMethodService(mVisibleConnection,
IME_VISIBLE_BIND_FLAGS);
return mVisibleBound;
}
@GuardedBy("mMethodMap")
- private boolean bindCurrentInputMethodServiceMainConnectionLocked() {
- mHasConnection = bindCurrentInputMethodServiceLocked(mMainConnection,
+ private boolean bindCurrentInputMethodServiceMainConnection() {
+ mHasConnection = bindCurrentInputMethodService(mMainConnection,
mImeConnectionBindFlags);
return mHasConnection;
}
@@ -487,26 +501,35 @@
* Performs a rebind if no binding is achieved in {@link #TIME_TO_RECONNECT} milliseconds.
*/
@GuardedBy("mMethodMap")
- void setCurrentMethodVisibleLocked() {
+ void setCurrentMethodVisible() {
if (mCurMethod != null) {
- if (DEBUG) Slog.d(TAG, "setCurrentMethodVisibleLocked: mCurToken=" + mCurToken);
+ if (DEBUG) Slog.d(TAG, "setCurrentMethodVisible: mCurToken=" + mCurToken);
if (mHasConnection && !mVisibleBound) {
- bindCurrentInputMethodServiceVisibleConnectionLocked();
+ bindCurrentInputMethodServiceVisibleConnection();
}
return;
}
+ // No IME is currently connected. Reestablish the main connection.
+ if (!mHasConnection) {
+ if (DEBUG) {
+ Slog.d(TAG, "Cannot show input: no IME bound. Rebinding.");
+ }
+ bindCurrentMethod();
+ return;
+ }
+
long bindingDuration = SystemClock.uptimeMillis() - mLastBindTime;
- if (mHasConnection && bindingDuration >= TIME_TO_RECONNECT) {
+ if (bindingDuration >= TIME_TO_RECONNECT) {
// The client has asked to have the input method shown, but
// we have been sitting here too long with a connection to the
// service and no interface received, so let's disconnect/connect
// to try to prod things along.
EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, getSelectedMethodId(),
bindingDuration, 1);
- Slog.w(TAG, "Force disconnect/connect to the IME in setCurrentMethodVisibleLocked()");
- unbindMainConnectionLocked();
- bindCurrentInputMethodServiceMainConnectionLocked();
+ Slog.w(TAG, "Force disconnect/connect to the IME in setCurrentMethodVisible()");
+ unbindMainConnection();
+ bindCurrentInputMethodServiceMainConnection();
} else {
if (DEBUG) {
Slog.d(TAG, "Can't show input: connection = " + mHasConnection + ", time = "
@@ -519,9 +542,9 @@
* Remove the binding needed for the IME to be shown.
*/
@GuardedBy("mMethodMap")
- void setCurrentMethodNotVisibleLocked() {
+ void setCurrentMethodNotVisible() {
if (mVisibleBound) {
- unbindVisibleConnectionLocked();
+ unbindVisibleConnection();
}
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index da3729d..41d8332 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -149,6 +149,7 @@
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.content.PackageMonitor;
import com.android.internal.infra.AndroidFuture;
+import com.android.internal.inputmethod.DirectBootAwareness;
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
import com.android.internal.inputmethod.ImeTracing;
@@ -261,6 +262,16 @@
private static final String ACTION_SHOW_INPUT_METHOD_PICKER =
"com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER";
+ /**
+ * When set, {@link #startInputUncheckedLocked} will return
+ * {@link InputBindResult#NO_EDITOR} instead of starting an IME connection
+ * unless {@link StartInputFlags#IS_TEXT_EDITOR} is set. This behavior overrides
+ * {@link LayoutParams#SOFT_INPUT_STATE_VISIBLE SOFT_INPUT_STATE_VISIBLE} and
+ * {@link LayoutParams#SOFT_INPUT_STATE_ALWAYS_VISIBLE SOFT_INPUT_STATE_ALWAYS_VISIBLE}
+ * starting from {@link android.os.Build.VERSION_CODES#P}.
+ */
+ private final boolean mPreventImeStartupUnlessTextEditor;
+
@UserIdInt
private int mLastSwitchUserId;
@@ -309,7 +320,7 @@
* The display id for which the latest startInput was called.
*/
@GuardedBy("mMethodMap")
- int getDisplayIdToShowIme() {
+ int getDisplayIdToShowImeLocked() {
return mDisplayIdToShowIme;
}
@@ -415,17 +426,19 @@
* <p>This can be transiently {@code null} when the system is re-initializing input method
* settings, e.g., the system locale is just changed.</p>
*
- * <p>Note that {@link InputMethodBindingController#getCurId()} is used to track which IME is
- * being connected to {@link InputMethodManagerService}.</p>
+ * <p>Note that {@link InputMethodBindingController#getCurId()} is used to track which IME
+ * is being connected to {@link InputMethodManagerService}.</p>
*
* @see InputMethodBindingController#getCurId()
*/
+ @GuardedBy("mMethodMap")
@Nullable
- private String getSelectedMethodId() {
+ private String getSelectedMethodIdLocked() {
return mBindingController.getSelectedMethodId();
}
- private void setSelectedMethodId(@Nullable String selectedMethodId) {
+ @GuardedBy("mMethodMap")
+ private void setSelectedMethodIdLocked(@Nullable String selectedMethodId) {
mBindingController.setSelectedMethodId(selectedMethodId);
}
@@ -433,7 +446,8 @@
* The current binding sequence number, incremented every time there is
* a new bind performed.
*/
- private int getSequenceNumber() {
+ @GuardedBy("mMethodMap")
+ private int getSequenceNumberLocked() {
return mBindingController.getSequenceNumber();
}
@@ -441,7 +455,8 @@
* Increase the current binding sequence number by one.
* Reset to 1 on overflow.
*/
- private void advanceSequenceNumber() {
+ @GuardedBy("mMethodMap")
+ private void advanceSequenceNumberLocked() {
mBindingController.advanceSequenceNumber();
}
@@ -500,10 +515,11 @@
*
* <p>This can be {@code null} when no input method is connected.</p>
*
- * @see #getSelectedMethodId()
+ * @see #getSelectedMethodIdLocked()
*/
+ @GuardedBy("mMethodMap")
@Nullable
- private String getCurId() {
+ private String getCurIdLocked() {
return mBindingController.getCurId();
}
@@ -521,7 +537,8 @@
* Set to true if our ServiceConnection is currently actively bound to
* a service (whether or not we have gotten its IBinder back yet).
*/
- private boolean hasConnection() {
+ @GuardedBy("mMethodMap")
+ private boolean hasConnectionLocked() {
return mBindingController.hasConnection();
}
@@ -553,8 +570,9 @@
/**
* The Intent used to connect to the current input method.
*/
+ @GuardedBy("mMethodMap")
@Nullable
- private Intent getCurIntent() {
+ private Intent getCurIntentLocked() {
return mBindingController.getCurIntent();
}
@@ -562,22 +580,26 @@
* The token we have made for the currently active input method, to
* identify it in the future.
*/
- private IBinder getCurToken() {
+ @GuardedBy("mMethodMap")
+ private IBinder getCurTokenLocked() {
return mBindingController.getCurToken();
}
/**
* The displayId of current active input method.
*/
- int getCurTokenDisplayId() {
+ @GuardedBy("mMethodMap")
+ int getCurTokenDisplayIdLocked() {
return mCurTokenDisplayId;
}
- void setCurTokenDisplayId(int curTokenDisplayId) {
+ @GuardedBy("mMethodMap")
+ void setCurTokenDisplayIdLocked(int curTokenDisplayId) {
mCurTokenDisplayId = curTokenDisplayId;
}
- int mCurTokenDisplayId = INVALID_DISPLAY;
+ @GuardedBy("mMethodMap")
+ private int mCurTokenDisplayId = INVALID_DISPLAY;
/**
* The host input token of the current active input method.
@@ -598,15 +620,17 @@
* If non-null, this is the input method service we are currently connected
* to.
*/
+ @GuardedBy("mMethodMap")
@Nullable
- private IInputMethod getCurMethod() {
+ private IInputMethod getCurMethodLocked() {
return mBindingController.getCurMethod();
}
/**
- * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntent()}.
+ * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntentLocked()}.
*/
- private int getCurMethodUid() {
+ @GuardedBy("mMethodMap")
+ private int getCurMethodUidLocked() {
return mBindingController.getCurMethodUid();
}
@@ -614,7 +638,8 @@
* Time that we last initiated a bind to the input method, to determine
* if we should try to disconnect and reconnect to it.
*/
- private long getLastBindTime() {
+ @GuardedBy("mMethodMap")
+ private long getLastBindTimeLocked() {
return mBindingController.getLastBindTime();
}
@@ -657,7 +682,7 @@
* </dd>
* </dl>
* <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
- * {@link InputMethodBindingController#unbindCurrentMethodLocked()}.</em>
+ * {@link InputMethodBindingController#unbindCurrentMethod()}.</em>
*/
int mImeWindowVis;
@@ -1648,12 +1673,14 @@
mSettings, context);
mMenuController = new InputMethodMenuController(this);
mBindingController = new InputMethodBindingController(this);
+ mPreventImeStartupUnlessTextEditor = mRes.getBoolean(
+ com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor);
}
@GuardedBy("mMethodMap")
private void resetDefaultImeLocked(Context context) {
// Do not reset the default (current) IME when it is a 3rd-party IME
- String selectedMethodId = getSelectedMethodId();
+ String selectedMethodId = getSelectedMethodIdLocked();
if (selectedMethodId != null && !mMethodMap.get(selectedMethodId).isSystem()) {
return;
}
@@ -1861,7 +1888,7 @@
if (token == null) {
throw new InvalidParameterException("token must not be null.");
}
- if (token != getCurToken()) {
+ if (token != getCurTokenLocked()) {
Slog.e(TAG, "Ignoring " + Debug.getCaller() + " due to an invalid token."
+ " uid:" + Binder.getCallingUid() + " token:" + token);
return false;
@@ -1869,8 +1896,8 @@
return true;
}
- @Override
- public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
+ private List<InputMethodInfo> getInputMethodListInternal(@UserIdInt int userId,
+ @DirectBootAwareness int directBootAwareness) {
if (UserHandle.getCallingUserId() != userId) {
mContext.enforceCallingPermission(
Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
@@ -1883,7 +1910,7 @@
}
final long ident = Binder.clearCallingIdentity();
try {
- return getInputMethodListLocked(resolvedUserIds[0]);
+ return getInputMethodListLocked(resolvedUserIds[0], directBootAwareness);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -1891,6 +1918,17 @@
}
@Override
+ public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
+ return getInputMethodListInternal(userId, DirectBootAwareness.AUTO);
+ }
+
+ @Override
+ public List<InputMethodInfo> getAwareLockedInputMethodList(@UserIdInt int userId,
+ @DirectBootAwareness int directBootAwareness) {
+ return getInputMethodListInternal(userId, directBootAwareness);
+ }
+
+ @Override
public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
if (UserHandle.getCallingUserId() != userId) {
mContext.enforceCallingPermission(
@@ -1912,9 +1950,11 @@
}
@GuardedBy("mMethodMap")
- private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId) {
+ private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId,
+ @DirectBootAwareness int directBootAwareness) {
final ArrayList<InputMethodInfo> methodList;
- if (userId == mSettings.getCurrentUserId()) {
+ if (userId == mSettings.getCurrentUserId()
+ && directBootAwareness == DirectBootAwareness.AUTO) {
// Create a copy.
methodList = new ArrayList<>(mMethodList);
} else {
@@ -1924,7 +1964,7 @@
new ArrayMap<>();
AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
- methodList);
+ methodList, directBootAwareness);
}
return methodList;
}
@@ -1943,15 +1983,16 @@
@GuardedBy("mMethodMap")
private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId,
InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback) {
- final InputMethodInfo imi = mMethodMap.get(getSelectedMethodId());
+ final InputMethodInfo imi = mMethodMap.get(getSelectedMethodIdLocked());
try {
- IInputMethod curMethod = getCurMethod();
+ IInputMethod curMethod = getCurMethodLocked();
if (userId == mSettings.getCurrentUserId() && imi != null
&& imi.isInlineSuggestionsEnabled() && curMethod != null) {
executeOrSendMessage(curMethod,
mCaller.obtainMessageOOO(MSG_INLINE_SUGGESTIONS_REQUEST, curMethod,
requestInfo, new InlineSuggestionsRequestCallbackDecorator(callback,
- imi.getPackageName(), mCurTokenDisplayId, getCurToken(),
+ imi.getPackageName(), mCurTokenDisplayId,
+ getCurTokenLocked(),
this)));
} else {
callback.onInlineSuggestionsUnsupported();
@@ -2087,7 +2128,7 @@
boolean allowsImplicitlySelectedSubtypes, @UserIdInt int userId) {
if (userId == mSettings.getCurrentUserId()) {
final InputMethodInfo imi;
- String selectedMethodId = getSelectedMethodId();
+ String selectedMethodId = getSelectedMethodIdLocked();
if (imiId == null && selectedMethodId != null) {
imi = mMethodMap.get(selectedMethodId);
} else {
@@ -2180,7 +2221,7 @@
mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
if (mBoundToMethod) {
mBoundToMethod = false;
- IInputMethod curMethod = getCurMethod();
+ IInputMethod curMethod = getCurMethodLocked();
if (curMethod != null) {
executeOrSendMessage(curMethod, mCaller.obtainMessageO(
MSG_UNBIND_INPUT, curMethod));
@@ -2211,7 +2252,7 @@
+ mCurClient.client.asBinder());
if (mBoundToMethod) {
mBoundToMethod = false;
- IInputMethod curMethod = getCurMethod();
+ IInputMethod curMethod = getCurMethodLocked();
if (curMethod != null) {
executeOrSendMessage(curMethod, mCaller.obtainMessageO(
MSG_UNBIND_INPUT, curMethod));
@@ -2221,7 +2262,8 @@
scheduleSetActiveToClient(mCurClient, false /* active */, false /* fullscreen */,
false /* reportToImeController */);
executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO(
- MSG_UNBIND_CLIENT, getSequenceNumber(), unbindClientReason, mCurClient.client));
+ MSG_UNBIND_CLIENT, getSequenceNumberLocked(), unbindClientReason,
+ mCurClient.client));
mCurClient.sessionRequested = false;
mCurClient = null;
@@ -2262,18 +2304,19 @@
@NonNull
InputBindResult attachNewInputLocked(@StartInputReason int startInputReason, boolean initial) {
if (!mBoundToMethod) {
- IInputMethod curMethod = getCurMethod();
+ IInputMethod curMethod = getCurMethodLocked();
executeOrSendMessage(curMethod, mCaller.obtainMessageOO(
MSG_BIND_INPUT, curMethod, mCurClient.binding));
mBoundToMethod = true;
}
final Binder startInputToken = new Binder();
- final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), getCurToken(),
- mCurTokenDisplayId, getCurId(), startInputReason, !initial,
+ final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(),
+ getCurTokenLocked(),
+ mCurTokenDisplayId, getCurIdLocked(), startInputReason, !initial,
UserHandle.getUserId(mCurClient.uid), mCurClient.selfReportedDisplayId,
mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode,
- getSequenceNumber());
+ getSequenceNumberLocked());
mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
mStartInputHistory.addEntry(info);
@@ -2284,7 +2327,7 @@
// INTERACT_ACROSS_USERS(_FULL) permissions, which is actually almost always the case.
if (mSettings.getCurrentUserId() == UserHandle.getUserId(mCurClient.uid)) {
mPackageManagerInternal.grantImplicitAccess(mSettings.getCurrentUserId(),
- null /* intent */, UserHandle.getAppId(getCurMethodUid()), mCurClient.uid,
+ null /* intent */, UserHandle.getAppId(getCurMethodUidLocked()), mCurClient.uid,
true /* direct */);
}
@@ -2298,22 +2341,22 @@
SoftInputShowHideReason.ATTACH_NEW_INPUT);
}
- String curId = getCurId();
+ String curId = getCurIdLocked();
final InputMethodInfo curInputMethodInfo = mMethodMap.get(curId);
final boolean suppressesSpellChecker =
curInputMethodInfo != null && curInputMethodInfo.suppressesSpellChecker();
return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
session.session, (session.channel != null ? session.channel.dup() : null),
- curId, getSequenceNumber(), suppressesSpellChecker);
+ curId, getSequenceNumberLocked(), suppressesSpellChecker);
}
@GuardedBy("mMethodMap")
@NonNull
InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
@NonNull EditorInfo attribute, @StartInputFlags int startInputFlags,
- @StartInputReason int startInputReason) {
+ @StartInputReason int startInputReason, int unverifiedTargetSdkVersion) {
// If no method is currently selected, do nothing.
- String selectedMethodId = getSelectedMethodId();
+ String selectedMethodId = getSelectedMethodIdLocked();
if (selectedMethodId == null) {
return InputBindResult.NO_IME;
}
@@ -2323,7 +2366,7 @@
// party code.
return new InputBindResult(
InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
- null, null, selectedMethodId, getSequenceNumber(), false);
+ null, null, selectedMethodId, getSequenceNumberLocked(), false);
}
if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
@@ -2355,15 +2398,27 @@
}
// Bump up the sequence for this client and attach it.
- advanceSequenceNumber();
+ advanceSequenceNumberLocked();
mCurClient = cs;
mCurInputContext = inputContext;
mCurAttribute = attribute;
+ // If configured, we want to avoid starting up the IME if it is not supposed to be showing
+ if (mPreventImeStartupUnlessTextEditor
+ && !InputMethodUtils.isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion,
+ startInputFlags)
+ && !mShowRequested) {
+ if (DEBUG) {
+ Slog.d(TAG, "Avoiding IME startup and unbinding current input method.");
+ }
+ mBindingController.unbindCurrentMethod();
+ return InputBindResult.NO_EDITOR;
+ }
+
// Check if the input method is changing.
// We expect the caller has already verified that the client is allowed to access this
// display ID.
- if (isSelectedMethodBound()) {
+ if (isSelectedMethodBoundLocked()) {
if (cs.curSession != null) {
// Fast case: if we are already connected to the input method,
// then just return it.
@@ -2377,14 +2432,15 @@
}
}
- mBindingController.unbindCurrentMethodLocked();
+ mBindingController.unbindCurrentMethod();
- return mBindingController.bindCurrentMethodLocked();
+ return mBindingController.bindCurrentMethod();
}
- private boolean isSelectedMethodBound() {
- String curId = getCurId();
- return curId != null && curId.equals(getSelectedMethodId())
+ @GuardedBy("mMethodMap")
+ private boolean isSelectedMethodBoundLocked() {
+ String curId = getCurIdLocked();
+ return curId != null && curId.equals(getSelectedMethodIdLocked())
&& mDisplayIdToShowIme == mCurTokenDisplayId;
}
@@ -2403,16 +2459,16 @@
@GuardedBy("mMethodMap")
@Nullable
private InputBindResult tryReuseConnectionLocked(@NonNull ClientState cs) {
- if (hasConnection()) {
- if (getCurMethod() != null) {
+ if (hasConnectionLocked()) {
+ if (getCurMethodLocked() != null) {
// Return to client, and we will get back with it when
// we have had a session made for it.
requestClientSessionLocked(cs);
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
- null, null, getCurId(), getSequenceNumber(), false);
+ null, null, getCurIdLocked(), getSequenceNumberLocked(), false);
} else {
- long bindingDuration = SystemClock.uptimeMillis() - getLastBindTime();
+ long bindingDuration = SystemClock.uptimeMillis() - getLastBindTimeLocked();
if (bindingDuration < TIME_TO_RECONNECT) {
// In this case we have connected to the service, but
// don't yet have its interface. If it hasn't been too
@@ -2423,10 +2479,10 @@
// to see if we can get back in touch with the service.
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
- null, null, getCurId(), getSequenceNumber(), false);
+ null, null, getCurIdLocked(), getSequenceNumberLocked(), false);
} else {
EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
- getSelectedMethodId(), bindingDuration, 0);
+ getSelectedMethodIdLocked(), bindingDuration, 0);
}
}
}
@@ -2479,7 +2535,7 @@
channel.dispose();
return;
}
- IInputMethod curMethod = getCurMethod();
+ IInputMethod curMethod = getCurMethodLocked();
if (curMethod != null && method != null
&& curMethod.asBinder() == method.asBinder()) {
if (mCurClient != null) {
@@ -2513,8 +2569,8 @@
@GuardedBy("mMethodMap")
void resetCurrentMethodAndClientLocked(@UnbindReason int unbindClientReason) {
- setSelectedMethodId(null);
- mBindingController.unbindCurrentMethodLocked();
+ setSelectedMethodIdLocked(null);
+ mBindingController.unbindCurrentMethod();
unbindCurrentClientLocked(unbindClientReason);
}
@@ -2532,7 +2588,7 @@
if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
InputChannel[] channels = InputChannel.openInputChannelPair(cs.toString());
cs.sessionRequested = true;
- IInputMethod curMethod = getCurMethod();
+ IInputMethod curMethod = getCurMethodLocked();
executeOrSendMessage(curMethod, mCaller.obtainMessageOOO(
MSG_CREATE_SESSION, curMethod, channels[1],
new MethodCallback(this, curMethod, channels[0])));
@@ -2567,7 +2623,7 @@
@GuardedBy("mMethodMap")
void clearClientSessionsLocked() {
- if (getCurMethod() != null) {
+ if (getCurMethodLocked() != null) {
final int numClients = mClients.size();
for (int i = 0; i < numClients; ++i) {
clearClientSessionLocked(mClients.valueAt(i));
@@ -2759,7 +2815,7 @@
// Caution! This method is called in this class. Handle multi-user carefully
@GuardedBy("mMethodMap")
private void updateSystemUiLocked(int vis, int backDisposition) {
- if (getCurToken() == null) {
+ if (getCurTokenLocked() == null) {
return;
}
if (DEBUG) {
@@ -2784,10 +2840,10 @@
// mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
if (mStatusBar != null) {
- mStatusBar.setImeWindowStatus(mCurTokenDisplayId, getCurToken(), vis,
+ mStatusBar.setImeWindowStatus(mCurTokenDisplayId, getCurTokenLocked(), vis,
backDisposition, needsToShowImeSwitcher);
}
- final InputMethodInfo imi = mMethodMap.get(getSelectedMethodId());
+ final InputMethodInfo imi = mMethodMap.get(getSelectedMethodIdLocked());
if (imi != null && needsToShowImeSwitcher) {
// Used to load label
final CharSequence title = mRes.getText(
@@ -2895,7 +2951,7 @@
}
// See if we need to notify a subtype change within the same IME.
- if (id.equals(getSelectedMethodId())) {
+ if (id.equals(getSelectedMethodIdLocked())) {
final int subtypeCount = info.getSubtypeCount();
if (subtypeCount <= 0) {
return;
@@ -2916,7 +2972,7 @@
}
if (newSubtype != oldSubtype) {
setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true);
- IInputMethod curMethod = getCurMethod();
+ IInputMethod curMethod = getCurMethodLocked();
if (curMethod != null) {
try {
updateSystemUiLocked(mImeWindowVis, mBackDisposition);
@@ -2938,7 +2994,7 @@
// mCurMethodId should be updated after setSelectedInputMethodAndSubtypeLocked()
// because mCurMethodId is stored as a history in
// setSelectedInputMethodAndSubtypeLocked().
- setSelectedMethodId(id);
+ setSelectedMethodIdLocked(id);
if (LocalServices.getService(ActivityManagerInternal.class).isSystemReady()) {
Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
@@ -3031,12 +3087,12 @@
return false;
}
- mBindingController.setCurrentMethodVisibleLocked();
- if (getCurMethod() != null) {
+ mBindingController.setCurrentMethodVisible();
+ if (getCurMethodLocked() != null) {
// create a placeholder token for IMS so that IMS cannot inject windows into client app.
Binder showInputToken = new Binder();
mShowRequestWindowMap.put(showInputToken, windowToken);
- IInputMethod curMethod = getCurMethod();
+ IInputMethod curMethod = getCurMethodLocked();
executeOrSendMessage(curMethod, mCaller.obtainMessageIIOOO(MSG_SHOW_SOFT_INPUT,
getImeShowFlagsLocked(), reason, curMethod, resultReceiver,
showInputToken));
@@ -3111,7 +3167,7 @@
// since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only
// IMMS#InputShown indicates that the software keyboard is shown.
// TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested.
- IInputMethod curMethod = getCurMethod();
+ IInputMethod curMethod = getCurMethodLocked();
final boolean shouldHideSoftInput = (curMethod != null) && (mInputShown
|| (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
boolean res;
@@ -3128,7 +3184,7 @@
} else {
res = false;
}
- mBindingController.setCurrentMethodNotVisibleLocked();
+ mBindingController.setCurrentMethodNotVisible();
mInputShown = false;
mShowRequested = false;
mShowExplicitlyRequested = false;
@@ -3302,7 +3358,7 @@
}
if (attribute != null) {
return startInputUncheckedLocked(cs, inputContext, attribute, startInputFlags,
- startInputReason);
+ startInputReason, unverifiedTargetSdkVersion);
}
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
@@ -3343,7 +3399,7 @@
if (isTextEditor && attribute != null
&& shouldRestoreImeVisibility(windowToken, softInputMode)) {
res = startInputUncheckedLocked(cs, inputContext, attribute, startInputFlags,
- startInputReason);
+ startInputReason, unverifiedTargetSdkVersion);
showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY);
return res;
@@ -3367,7 +3423,7 @@
// Note that we can trust client's display ID as long as it matches
// to the display ID obtained from the window.
if (cs.selfReportedDisplayId != mCurTokenDisplayId) {
- mBindingController.unbindCurrentMethodLocked();
+ mBindingController.unbindCurrentMethod();
}
}
} else if (isTextEditor && doAutoShow
@@ -3382,7 +3438,7 @@
if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
if (attribute != null) {
res = startInputUncheckedLocked(cs, inputContext, attribute,
- startInputFlags, startInputReason);
+ startInputFlags, startInputReason, unverifiedTargetSdkVersion);
didStart = true;
}
showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
@@ -3413,7 +3469,7 @@
unverifiedTargetSdkVersion, startInputFlags)) {
if (attribute != null) {
res = startInputUncheckedLocked(cs, inputContext, attribute,
- startInputFlags, startInputReason);
+ startInputFlags, startInputReason, unverifiedTargetSdkVersion);
didStart = true;
}
showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
@@ -3432,7 +3488,7 @@
if (!sameWindowFocused) {
if (attribute != null) {
res = startInputUncheckedLocked(cs, inputContext, attribute,
- startInputFlags, startInputReason);
+ startInputFlags, startInputReason, unverifiedTargetSdkVersion);
didStart = true;
}
showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
@@ -3461,7 +3517,7 @@
}
}
res = startInputUncheckedLocked(cs, inputContext, attribute, startInputFlags,
- startInputReason);
+ startInputReason, unverifiedTargetSdkVersion);
} else {
res = InputBindResult.NULL_EDITOR_INFO;
}
@@ -3489,10 +3545,10 @@
if (mCurFocusedWindowClient != null && client != null
&& mCurFocusedWindowClient.client.asBinder() == client.asBinder()) {
return true;
- } else if (getCurIntent() != null && InputMethodUtils.checkIfPackageBelongsToUid(
+ } else if (getCurIntentLocked() != null && InputMethodUtils.checkIfPackageBelongsToUid(
mAppOpsManager,
uid,
- getCurIntent().getComponent().getPackageName())) {
+ getCurIntentLocked().getComponent().getPackageName())) {
return true;
}
return false;
@@ -3578,7 +3634,7 @@
if (!calledFromValidUserLocked()) {
return;
}
- executeOrSendMessage(getCurMethod(), mCaller.obtainMessageO(
+ executeOrSendMessage(getCurMethodLocked(), mCaller.obtainMessageO(
MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
}
}
@@ -3599,7 +3655,7 @@
String targetLastImiId = null;
int subtypeId = NOT_A_SUBTYPE_ID;
if (lastIme != null && lastImi != null) {
- final boolean imiIdIsSame = lastImi.getId().equals(getSelectedMethodId());
+ final boolean imiIdIsSame = lastImi.getId().equals(getSelectedMethodIdLocked());
final int lastSubtypeHash = Integer.parseInt(lastIme.second);
final int currentSubtypeHash = mCurrentSubtype == null ? NOT_A_SUBTYPE_ID
: mCurrentSubtype.hashCode();
@@ -3645,7 +3701,7 @@
if (!TextUtils.isEmpty(targetLastImiId)) {
if (DEBUG) {
Slog.d(TAG, "Switch to: " + lastImi.getId() + ", " + lastIme.second
- + ", from: " + getSelectedMethodId() + ", " + subtypeId);
+ + ", from: " + getSelectedMethodIdLocked() + ", " + subtypeId);
}
setInputMethodWithSubtypeIdLocked(token, targetLastImiId, subtypeId);
return true;
@@ -3662,7 +3718,7 @@
return false;
}
final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
- onlyCurrentIme, mMethodMap.get(getSelectedMethodId()), mCurrentSubtype);
+ onlyCurrentIme, mMethodMap.get(getSelectedMethodIdLocked()), mCurrentSubtype);
if (nextSubtype == null) {
return false;
}
@@ -3679,7 +3735,7 @@
return false;
}
final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
- false /* onlyCurrentIme */, mMethodMap.get(getSelectedMethodId()),
+ false /* onlyCurrentIme */, mMethodMap.get(getSelectedMethodIdLocked()),
mCurrentSubtype);
if (nextSubtype == null) {
return false;
@@ -3894,8 +3950,8 @@
private void dumpDebug(ProtoOutputStream proto, long fieldId) {
synchronized (mMethodMap) {
final long token = proto.start(fieldId);
- proto.write(CUR_METHOD_ID, getSelectedMethodId());
- proto.write(CUR_SEQ, getSequenceNumber());
+ proto.write(CUR_METHOD_ID, getSelectedMethodIdLocked());
+ proto.write(CUR_SEQ, getSequenceNumberLocked());
proto.write(CUR_CLIENT, Objects.toString(mCurClient));
proto.write(CUR_FOCUSED_WINDOW_NAME,
mWindowManagerInternal.getWindowName(mCurFocusedWindow));
@@ -3906,17 +3962,17 @@
if (mCurAttribute != null) {
mCurAttribute.dumpDebug(proto, CUR_ATTRIBUTE);
}
- proto.write(CUR_ID, getCurId());
+ proto.write(CUR_ID, getCurIdLocked());
proto.write(SHOW_REQUESTED, mShowRequested);
proto.write(SHOW_EXPLICITLY_REQUESTED, mShowExplicitlyRequested);
proto.write(SHOW_FORCED, mShowForced);
proto.write(INPUT_SHOWN, mInputShown);
proto.write(IN_FULLSCREEN_MODE, mInFullscreenMode);
- proto.write(CUR_TOKEN, Objects.toString(getCurToken()));
+ proto.write(CUR_TOKEN, Objects.toString(getCurTokenLocked()));
proto.write(CUR_TOKEN_DISPLAY_ID, mCurTokenDisplayId);
proto.write(SYSTEM_READY, mSystemReady);
proto.write(LAST_SWITCH_USER_ID, mLastSwitchUserId);
- proto.write(HAVE_CONNECTION, hasConnection());
+ proto.write(HAVE_CONNECTION, hasConnectionLocked());
proto.write(BOUND_TO_METHOD, mBoundToMethod);
proto.write(IS_INTERACTIVE, mIsInteractive);
proto.write(BACK_DISPOSITION, mBackDisposition);
@@ -3934,14 +3990,14 @@
Slog.d(TAG, "Got the notification of a user action.");
}
synchronized (mMethodMap) {
- if (getCurToken() != token) {
+ if (getCurTokenLocked() != token) {
if (DEBUG) {
Slog.d(TAG, "Ignoring the user action notification from IMEs that are no longer"
+ " active.");
}
return;
}
- final InputMethodInfo imi = mMethodMap.get(getSelectedMethodId());
+ final InputMethodInfo imi = mMethodMap.get(getSelectedMethodIdLocked());
if (imi != null) {
mSwitchingController.onUserActionLocked(imi, mCurrentSubtype);
}
@@ -3985,7 +4041,7 @@
"Using null token requires permission "
+ android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
- } else if (getCurToken() != token) {
+ } else if (getCurTokenLocked() != token) {
Slog.w(TAG, "Ignoring setInputMethod of uid " + Binder.getCallingUid()
+ " token: " + token);
return;
@@ -4357,7 +4413,7 @@
boolean reportToImeController = false;
try {
reportToImeController = mPlatformCompat.isChangeEnabledByUid(
- FINISH_INPUT_NO_FALLBACK_CONNECTION, getCurMethodUid());
+ FINISH_INPUT_NO_FALLBACK_CONNECTION, getCurMethodUidLocked());
} catch (RemoteException e) {
}
scheduleSetActiveToClient(mCurClient, mIsInteractive, mInFullscreenMode,
@@ -4389,17 +4445,31 @@
static void queryInputMethodServicesInternal(Context context,
@UserIdInt int userId, ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap,
- ArrayMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList) {
+ ArrayMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList,
+ @DirectBootAwareness int directBootAwareness) {
methodList.clear();
methodMap.clear();
- // Note: We do not specify PackageManager.MATCH_ENCRYPTION_* flags here because the default
- // behavior of PackageManager is exactly what we want. It by default picks up appropriate
- // services depending on the unlock state for the specified user.
+ final int directBootAwarenessFlags;
+ switch (directBootAwareness) {
+ case DirectBootAwareness.ANY:
+ directBootAwarenessFlags = PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+ break;
+ case DirectBootAwareness.AUTO:
+ directBootAwarenessFlags = PackageManager.MATCH_DIRECT_BOOT_AUTO;
+ break;
+ default:
+ directBootAwarenessFlags = PackageManager.MATCH_DIRECT_BOOT_AUTO;
+ Slog.e(TAG, "Unknown directBootAwareness=" + directBootAwareness
+ + ". Falling back to DirectBootAwareness.AUTO");
+ break;
+ }
+ final int flags = PackageManager.GET_META_DATA
+ | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+ | directBootAwarenessFlags;
final List<ResolveInfo> services = context.getPackageManager().queryIntentServicesAsUser(
- new Intent(InputMethod.SERVICE_INTERFACE),
- PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS,
- userId);
+ new Intent(InputMethod.SERVICE_INTERFACE), flags, userId);
methodList.ensureCapacity(services.size());
methodMap.ensureCapacity(services.size());
@@ -4448,7 +4518,7 @@
mMyPackageMonitor.clearKnownImePackageNamesLocked();
queryInputMethodServicesInternal(mContext, mSettings.getCurrentUserId(),
- mAdditionalSubtypeMap, mMethodMap, mMethodList);
+ mAdditionalSubtypeMap, mMethodMap, mMethodList, DirectBootAwareness.AUTO);
// Construct the set of possible IME packages for onPackageChanged() to avoid false
// negatives when the package state remains to be the same but only the component state is
@@ -4647,7 +4717,8 @@
@GuardedBy("mMethodMap")
private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
boolean setSubtypeOnly) {
- mSettings.saveCurrentInputMethodAndSubtypeToHistory(getSelectedMethodId(), mCurrentSubtype);
+ mSettings.saveCurrentInputMethodAndSubtypeToHistory(getSelectedMethodIdLocked(),
+ mCurrentSubtype);
// Set Subtype here
if (imi == null || subtypeId < 0) {
@@ -4706,7 +4777,7 @@
@GuardedBy("mMethodMap")
InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
- String selectedMethodId = getSelectedMethodId();
+ String selectedMethodId = getSelectedMethodIdLocked();
if (selectedMethodId == null) {
return null;
}
@@ -4747,12 +4818,12 @@
@Nullable
String getCurrentMethodId() {
- return getSelectedMethodId();
+ return getSelectedMethodIdLocked();
}
private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
synchronized (mMethodMap) {
- return getInputMethodListLocked(userId);
+ return getInputMethodListLocked(userId, DirectBootAwareness.AUTO);
}
}
@@ -4777,7 +4848,7 @@
new ArrayMap<>();
AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
- methodMap, methodList);
+ methodMap, methodList, DirectBootAwareness.AUTO);
return methodMap;
}
@@ -4960,11 +5031,11 @@
synchronized (mMethodMap) {
final int uid = Binder.getCallingUid();
- if (getSelectedMethodId() == null) {
+ if (getSelectedMethodIdLocked() == null) {
return null;
}
- if (getCurToken() != token) {
- Slog.e(TAG, "Ignoring createInputContentUriToken mCurToken=" + getCurToken()
+ if (getCurTokenLocked() != token) {
+ Slog.e(TAG, "Ignoring createInputContentUriToken mCurToken=" + getCurTokenLocked()
+ " token=" + token);
return null;
}
@@ -5099,24 +5170,24 @@
p.println(" sessionRequested=" + ci.sessionRequested);
p.println(" curSession=" + ci.curSession);
}
- p.println(" mCurMethodId=" + getSelectedMethodId());
+ p.println(" mCurMethodId=" + getSelectedMethodIdLocked());
client = mCurClient;
- p.println(" mCurClient=" + client + " mCurSeq=" + getSequenceNumber());
+ p.println(" mCurClient=" + client + " mCurSeq=" + getSequenceNumberLocked());
p.println(" mCurPerceptible=" + mCurPerceptible);
p.println(" mCurFocusedWindow=" + mCurFocusedWindow
+ " softInputMode=" +
InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode)
+ " client=" + mCurFocusedWindowClient);
focusedWindowClient = mCurFocusedWindowClient;
- p.println(" mCurId=" + getCurId() + " mHaveConnection=" + hasConnection()
+ p.println(" mCurId=" + getCurIdLocked() + " mHaveConnection=" + hasConnectionLocked()
+ " mBoundToMethod=" + mBoundToMethod + " mVisibleBound="
+ mBindingController.isVisibleBound());
- p.println(" mCurToken=" + getCurToken());
+ p.println(" mCurToken=" + getCurTokenLocked());
p.println(" mCurTokenDisplayId=" + mCurTokenDisplayId);
p.println(" mCurHostInputToken=" + mCurHostInputToken);
- p.println(" mCurIntent=" + getCurIntent());
- method = getCurMethod();
- p.println(" mCurMethod=" + getCurMethod());
+ p.println(" mCurIntent=" + getCurIntentLocked());
+ method = getCurMethodLocked();
+ p.println(" mCurMethod=" + getCurMethodLocked());
p.println(" mEnabledSession=" + mEnabledSession);
p.println(" mShowRequested=" + mShowRequested
+ " mShowExplicitlyRequested=" + mShowExplicitlyRequested
@@ -5406,7 +5477,7 @@
mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
for (int userId : userIds) {
final List<InputMethodInfo> methods = all
- ? getInputMethodListLocked(userId)
+ ? getInputMethodListLocked(userId, DirectBootAwareness.AUTO)
: getEnabledInputMethodListLocked(userId);
if (userIds.length > 1) {
pr.print("User #");
@@ -5616,7 +5687,7 @@
if (userId == mSettings.getCurrentUserId()) {
hideCurrentInputLocked(mCurFocusedWindow, 0, null,
SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND);
- mBindingController.unbindCurrentMethodLocked();
+ mBindingController.unbindCurrentMethod();
// Reset the current IME
resetSelectedInputMethodAndSubtypeLocked(null);
// Also reset the settings of the current IME
@@ -5641,7 +5712,7 @@
new ArrayMap<>();
AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
- methodMap, methodList);
+ methodMap, methodList, DirectBootAwareness.AUTO);
final InputMethodSettings settings = new InputMethodSettings(
mContext.getResources(), mContext.getContentResolver(), methodMap,
userId, false);
@@ -5678,7 +5749,7 @@
final PrintWriter pw = shellCommand.getOutPrintWriter();
switch (cmd) {
case "start":
- ImeTracing.getInstance().getInstance().startTrace(pw);
+ ImeTracing.getInstance().startTrace(pw);
break; // proceed to the next step to update the IME client processes.
case "stop":
ImeTracing.getInstance().stopTrace(pw);
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
index 0fd7cc1..e40d86a 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
@@ -331,15 +331,7 @@
mAppOpsManager = context.getSystemService(AppOpsManager.class);
startMonitoringOpChanges();
-
- HostEndpointInfo info = new HostEndpointInfo();
- info.hostEndpointId = (char) mHostEndPointId;
- info.packageName = mPackage;
- info.attributionTag = mAttributionTag;
- info.type = (mUid == Process.SYSTEM_UID)
- ? HostEndpointInfo.Type.TYPE_FRAMEWORK
- : HostEndpointInfo.Type.TYPE_APP;
- mContextHubProxy.onHostEndpointConnected(info);
+ sendHostEndpointConnectedEvent();
}
/* package */ ContextHubClientBroker(
@@ -556,6 +548,9 @@
/* package */ void onHubReset() {
invokeCallback(callback -> callback.onHubReset());
sendPendingIntent(() -> createIntent(ContextHubManager.EVENT_HUB_RESET));
+
+ // Re-send the host endpoint connected event as the Context Hub restarted.
+ sendHostEndpointConnectedEvent();
}
/**
@@ -895,6 +890,17 @@
}
}
+ private void sendHostEndpointConnectedEvent() {
+ HostEndpointInfo info = new HostEndpointInfo();
+ info.hostEndpointId = (char) mHostEndPointId;
+ info.packageName = mPackage;
+ info.attributionTag = mAttributionTag;
+ info.type = (mUid == Process.SYSTEM_UID)
+ ? HostEndpointInfo.Type.TYPE_FRAMEWORK
+ : HostEndpointInfo.Type.TYPE_APP;
+ mContextHubProxy.onHostEndpointConnected(info);
+ }
+
/**
* Dump debugging info as ClientBrokerProto
*
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index fc9697d..61e6d14 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -72,6 +72,9 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
@@ -138,11 +141,23 @@
// The manager for the internal nanoapp state cache
private final NanoAppStateManager mNanoAppStateManager = new NanoAppStateManager();
+ // An executor and the future object for scheduling timeout timers
+ private final ScheduledThreadPoolExecutor mDailyMetricTimer =
+ new ScheduledThreadPoolExecutor(1);
+
+
+ // The period of the recurring time
+ private static final int PERIOD_METRIC_QUERY_DAYS = 1;
+
// True if WiFi is available for the Context Hub
private boolean mIsWifiAvailable = false;
private boolean mIsWifiScanningEnabled = false;
private boolean mIsWifiMainEnabled = false;
+ // A hashmap used to record if a contexthub is waiting for daily query
+ private Set<Integer> mMetricQueryPendingContextHubIds =
+ Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());
+
// Lock object for sendWifiSettingUpdate()
private final Object mSendWifiSettingUpdateLock = new Object();
@@ -317,6 +332,8 @@
});
}
+
+ scheduleDailyMetricSnapshot();
}
/**
@@ -747,6 +764,18 @@
* @param nanoappStateList the list of loaded nanoapps
*/
private void handleQueryAppsCallback(int contextHubId, List<NanoAppState> nanoappStateList) {
+ if (mMetricQueryPendingContextHubIds.contains(contextHubId)) {
+ for (NanoAppState nanoappState : nanoappStateList) {
+ ContextHubStatsLog.write(
+ ContextHubStatsLog.CONTEXT_HUB_LOADED_NANOAPP_SNAPSHOT_REPORTED,
+ contextHubId, nanoappState.getNanoAppId(),
+ (int) nanoappState.getNanoAppVersion());
+ }
+ mMetricQueryPendingContextHubIds.remove(contextHubId);
+ if (mMetricQueryPendingContextHubIds.isEmpty()) {
+ scheduleDailyMetricSnapshot();
+ }
+ }
mNanoAppStateManager.updateCache(contextHubId, nanoappStateList);
mTransactionManager.onQueryResponse(nanoappStateList);
}
@@ -1135,6 +1164,23 @@
sendMicrophoneDisableSettingUpdate(isEnabled);
}
+ /**
+ * Invokes a daily timer to query all context hubs
+ */
+ private void scheduleDailyMetricSnapshot() {
+ Runnable queryAllContextHub = () -> {
+ for (int contextHubId : mContextHubIdToInfoMap.keySet()) {
+ mMetricQueryPendingContextHubIds.add(contextHubId);
+ queryNanoAppsInternal(contextHubId);
+ }
+ };
+ try {
+ mDailyMetricTimer.schedule(queryAllContextHub, PERIOD_METRIC_QUERY_DAYS,
+ TimeUnit.DAYS);
+ } catch (Exception e) {
+ Log.e(TAG, "Error when schedule a timer", e);
+ }
+ }
private String getCallingPackageName() {
return mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
index abf5a24..19f7c4d 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
@@ -463,8 +463,12 @@
};
long timeoutSeconds = transaction.getTimeout(TimeUnit.SECONDS);
- mTimeoutFuture = mTimeoutExecutor.schedule(onTimeoutFunc, timeoutSeconds,
+ try {
+ mTimeoutFuture = mTimeoutExecutor.schedule(onTimeoutFunc, timeoutSeconds,
TimeUnit.SECONDS);
+ } catch (Exception e) {
+ Log.e(TAG, "Error when schedule a timer", e);
+ }
} else {
transaction.onTransactionComplete(
ContextHubServiceUtil.toTransactionResult(result));
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index 9078f3f..cc5aaf4 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -41,8 +41,10 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
@@ -320,9 +322,8 @@
private static class ContextHubWrapperAidl extends IContextHubWrapper {
private android.hardware.contexthub.IContextHub mHub;
- private ICallback mCallback = null;
-
- private ContextHubAidlCallback mAidlCallback = new ContextHubAidlCallback();
+ private final Map<Integer, ContextHubAidlCallback> mAidlCallbackMap =
+ new HashMap<>();
// Use this thread in case where the execution requires to be on a service thread.
// For instance, AppOpsManager.noteOp requires the UPDATE_APP_OPS_STATS permission.
@@ -332,6 +333,14 @@
private class ContextHubAidlCallback extends
android.hardware.contexthub.IContextHubCallback.Stub {
+ private final int mContextHubId;
+ private final ICallback mCallback;
+
+ ContextHubAidlCallback(int contextHubId, ICallback callback) {
+ mContextHubId = contextHubId;
+ mCallback = callback;
+ }
+
public void handleNanoappInfo(android.hardware.contexthub.NanoappInfo[] appInfo) {
List<NanoAppState> nanoAppStateList =
ContextHubServiceUtil.createNanoAppStateList(appInfo);
@@ -481,8 +490,8 @@
}
public void registerCallback(int contextHubId, ICallback callback) throws RemoteException {
- mCallback = callback;
- mHub.registerCallback(contextHubId, mAidlCallback);
+ mAidlCallbackMap.put(contextHubId, new ContextHubAidlCallback(contextHubId, callback));
+ mHub.registerCallback(contextHubId, mAidlCallbackMap.get(contextHubId));
}
@ContextHubTransaction.Result
@@ -508,10 +517,18 @@
protected ICallback mCallback = null;
- protected final ContextHubWrapperHidlCallback mHidlCallback =
- new ContextHubWrapperHidlCallback();
+ protected final Map<Integer, ContextHubWrapperHidlCallback> mHidlCallbackMap =
+ new HashMap<>();
protected class ContextHubWrapperHidlCallback extends IContexthubCallback.Stub {
+ private final int mContextHubId;
+ private final ICallback mCallback;
+
+ ContextHubWrapperHidlCallback(int contextHubId, ICallback callback) {
+ mContextHubId = contextHubId;
+ mCallback = callback;
+ }
+
@Override
public void handleClientMsg(ContextHubMsg message) {
mCallback.handleNanoappMessage(
@@ -612,8 +629,9 @@
}
public void registerCallback(int contextHubId, ICallback callback) throws RemoteException {
- mCallback = callback;
- mHub.registerCallback(contextHubId, mHidlCallback);
+ mHidlCallbackMap.put(contextHubId,
+ new ContextHubWrapperHidlCallback(contextHubId, callback));
+ mHub.registerCallback(contextHubId, mHidlCallbackMap.get(contextHubId));
}
public void onWifiMainSettingChanged(boolean enabled) {}
@@ -779,8 +797,9 @@
}
public void registerCallback(int contextHubId, ICallback callback) throws RemoteException {
- mCallback = callback;
- mHub.registerCallback_1_2(contextHubId, mHidlCallback);
+ mHidlCallbackMap.put(contextHubId,
+ new ContextHubWrapperHidlCallback(contextHubId, callback));
+ mHub.registerCallback_1_2(contextHubId, mHidlCallbackMap.get(contextHubId));
}
private void sendSettingChanged(byte setting, byte newValue) {
diff --git a/services/core/java/com/android/server/location/eventlog/LocalEventLog.java b/services/core/java/com/android/server/location/eventlog/LocalEventLog.java
index 47146c1..d08e5dc 100644
--- a/services/core/java/com/android/server/location/eventlog/LocalEventLog.java
+++ b/services/core/java/com/android/server/location/eventlog/LocalEventLog.java
@@ -21,26 +21,23 @@
import android.annotation.Nullable;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.lang.reflect.Array;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;
import java.util.Objects;
/**
* An in-memory event log to support historical event information. The log is of a constant size,
* and new events will overwrite old events as the log fills up.
- *
- * @param <T> log event type
*/
public class LocalEventLog<T> {
- /**
- * Consumer of log events for iterating over the log.
- *
- * @param <T> log event type
- */
+ /** Consumer of log events for iterating over the log. */
public interface LogConsumer<T> {
/** Invoked with a time and a logEvent. */
void acceptLog(long time, T logEvent);
@@ -48,12 +45,13 @@
// masks for the entries field. 1 bit is used to indicate whether this is a filler event or not,
// and 31 bits to store the time delta.
- private static final int IS_FILLER_MASK = 0b10000000000000000000000000000000;
+ private static final int IS_FILLER_MASK = 0b10000000000000000000000000000000;
private static final int TIME_DELTA_MASK = 0b01111111111111111111111111111111;
private static final int IS_FILLER_OFFSET = countTrailingZeros(IS_FILLER_MASK);
private static final int TIME_DELTA_OFFSET = countTrailingZeros(TIME_DELTA_MASK);
+ @VisibleForTesting
static final int MAX_TIME_DELTA = (1 << bitCount(TIME_DELTA_MASK)) - 1;
private static int countTrailingZeros(int i) {
@@ -79,7 +77,7 @@
return (entry & IS_FILLER_MASK) != 0;
}
- // circular buffer of log entries and events. each entry corrosponds to the log event at the
+ // circular buffer of log entries and events. each entry corresponds to the log event at the
// same index. the log entry holds the filler status and time delta according to the bit masks
// above, and the log event is the log event.
@@ -103,6 +101,9 @@
@GuardedBy("this")
long mLastLogTime;
+ @GuardedBy("this")
+ long mModificationCount;
+
@SuppressWarnings("unchecked")
public LocalEventLog(int size, Class<T> clazz) {
Preconditions.checkArgument(size > 0);
@@ -143,6 +144,7 @@
if (isEmpty()) {
mStartTime = time;
mLastLogTime = mStartTime;
+ mModificationCount++;
}
addLogEventInternal(false, (int) delta, logEvent);
@@ -156,6 +158,7 @@
if (mLogSize == mEntries.length) {
// if log is full, size will remain the same, but update the start time
mStartTime += getTimeDelta(mEntries[startIndex()]);
+ mModificationCount++;
} else {
// otherwise add an item
mLogSize++;
@@ -170,11 +173,12 @@
/** Clears the log of all entries. */
public synchronized void clear() {
- // clear entries to allow gc
+ // clear entries to aid gc
Arrays.fill(mLogEvents, null);
mLogEndIndex = 0;
mLogSize = 0;
+ mModificationCount++;
mStartTime = -1;
mLastLogTime = -1;
@@ -186,7 +190,10 @@
return mLogSize == 0;
}
- /** Iterates over the event log, passing each log string to the given consumer. */
+ /**
+ * Iterates over the event log, passing each log event to the given consumer. Locks the log
+ * while executing so that {@link ConcurrentModificationException}s cannot occur.
+ */
public synchronized void iterate(LogConsumer<? super T> consumer) {
LogIterator it = new LogIterator();
while (it.hasNext()) {
@@ -195,15 +202,53 @@
}
}
+ /**
+ * Iterates over all the given event logs in time order, passing each log event to the given
+ * consumer. It is the caller's responsibility to ensure that {@link
+ * ConcurrentModificationException}s cannot occur, whether through locking or other means.
+ */
+ @SafeVarargs
+ public static <T> void iterate(LogConsumer<? super T> consumer, LocalEventLog<T>... logs) {
+ ArrayList<LocalEventLog<T>.LogIterator> its = new ArrayList<>(logs.length);
+ for (LocalEventLog<T> log : logs) {
+ LocalEventLog<T>.LogIterator it = log.new LogIterator();
+ if (it.hasNext()) {
+ its.add(it);
+ it.next();
+ }
+ }
+
+ while (true) {
+ LocalEventLog<T>.LogIterator next = null;
+ for (LocalEventLog<T>.LogIterator it : its) {
+ if (it != null && (next == null || it.getTime() < next.getTime())) {
+ next = it;
+ }
+ }
+
+ if (next == null) {
+ return;
+ }
+
+ consumer.acceptLog(next.getTime(), next.getLog());
+
+ if (next.hasNext()) {
+ next.next();
+ } else {
+ its.remove(next);
+ }
+ }
+ }
+
// returns the index of the first element
@GuardedBy("this")
- private int startIndex() {
+ int startIndex() {
return wrapIndex(mLogEndIndex - mLogSize);
}
// returns the index after this one
@GuardedBy("this")
- private int incrementIndex(int index) {
+ int incrementIndex(int index) {
if (index == -1) {
return startIndex();
} else if (index >= 0) {
@@ -215,12 +260,15 @@
// rolls over the given index if necessary
@GuardedBy("this")
- private int wrapIndex(int index) {
+ int wrapIndex(int index) {
// java modulo will keep negative sign, we need to rollover
return (index % mEntries.length + mEntries.length) % mEntries.length;
}
- private class LogIterator {
+ /** Iterator over log times and events. */
+ protected final class LogIterator {
+
+ private final long mModificationCount;
private long mLogTime;
private int mIndex;
@@ -229,8 +277,10 @@
private long mCurrentTime;
private T mCurrentLogEvent;
- LogIterator() {
+ public LogIterator() {
synchronized (LocalEventLog.this) {
+ mModificationCount = LocalEventLog.this.mModificationCount;
+
mLogTime = mStartTime;
mIndex = -1;
mCount = -1;
@@ -241,6 +291,7 @@
public boolean hasNext() {
synchronized (LocalEventLog.this) {
+ checkModifications();
return mCount < mLogSize;
}
}
@@ -277,5 +328,12 @@
}
} while (mCount < mLogSize && isFiller(mEntries[mIndex]));
}
+
+ @GuardedBy("LocalEventLog.this")
+ private void checkModifications() {
+ if (mModificationCount != LocalEventLog.this.mModificationCount) {
+ throw new ConcurrentModificationException();
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
index 94953e0..45436e7 100644
--- a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
+++ b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
@@ -52,16 +52,28 @@
if (D) {
return 600;
} else {
+ return 300;
+ }
+ }
+
+ private static int getLocationsLogSize() {
+ if (D) {
return 200;
+ } else {
+ return 100;
}
}
@GuardedBy("mAggregateStats")
private final ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> mAggregateStats;
- public LocationEventLog() {
+ @GuardedBy("this")
+ private final LocationsEventLog mLocationsLog;
+
+ private LocationEventLog() {
super(getLogSize(), Object.class);
mAggregateStats = new ArrayMap<>(4);
+ mLocationsLog = new LocationsEventLog(getLocationsLogSize());
}
/** Copies out all aggregated stats. */
@@ -95,39 +107,39 @@
/** Logs a user switched event. */
public void logUserSwitched(int userIdFrom, int userIdTo) {
- addLogEvent(new UserSwitchedEvent(userIdFrom, userIdTo));
+ addLog(new UserSwitchedEvent(userIdFrom, userIdTo));
}
/** Logs a location enabled/disabled event. */
public void logLocationEnabled(int userId, boolean enabled) {
- addLogEvent(new LocationEnabledEvent(userId, enabled));
+ addLog(new LocationEnabledEvent(userId, enabled));
}
/** Logs a location enabled/disabled event. */
public void logAdasLocationEnabled(int userId, boolean enabled) {
- addLogEvent(new LocationAdasEnabledEvent(userId, enabled));
+ addLog(new LocationAdasEnabledEvent(userId, enabled));
}
/** Logs a location provider enabled/disabled event. */
public void logProviderEnabled(String provider, int userId, boolean enabled) {
- addLogEvent(new ProviderEnabledEvent(provider, userId, enabled));
+ addLog(new ProviderEnabledEvent(provider, userId, enabled));
}
/** Logs a location provider being replaced/unreplaced by a mock provider. */
public void logProviderMocked(String provider, boolean mocked) {
- addLogEvent(new ProviderMockedEvent(provider, mocked));
+ addLog(new ProviderMockedEvent(provider, mocked));
}
/** Logs a new client registration for a location provider. */
public void logProviderClientRegistered(String provider, CallerIdentity identity,
LocationRequest request) {
- addLogEvent(new ProviderClientRegisterEvent(provider, true, identity, request));
+ addLog(new ProviderClientRegisterEvent(provider, true, identity, request));
getAggregateStats(provider, identity).markRequestAdded(request.getIntervalMillis());
}
/** Logs a client unregistration for a location provider. */
public void logProviderClientUnregistered(String provider, CallerIdentity identity) {
- addLogEvent(new ProviderClientRegisterEvent(provider, false, identity, null));
+ addLog(new ProviderClientRegisterEvent(provider, false, identity, null));
getAggregateStats(provider, identity).markRequestRemoved();
}
@@ -144,7 +156,7 @@
/** Logs a client for a location provider entering the foreground state. */
public void logProviderClientForeground(String provider, CallerIdentity identity) {
if (D) {
- addLogEvent(new ProviderClientForegroundEvent(provider, true, identity));
+ addLog(new ProviderClientForegroundEvent(provider, true, identity));
}
getAggregateStats(provider, identity).markRequestForeground();
}
@@ -152,7 +164,7 @@
/** Logs a client for a location provider leaving the foreground state. */
public void logProviderClientBackground(String provider, CallerIdentity identity) {
if (D) {
- addLogEvent(new ProviderClientForegroundEvent(provider, false, identity));
+ addLog(new ProviderClientForegroundEvent(provider, false, identity));
}
getAggregateStats(provider, identity).markRequestBackground();
}
@@ -160,32 +172,34 @@
/** Logs a client for a location provider entering the permitted state. */
public void logProviderClientPermitted(String provider, CallerIdentity identity) {
if (D) {
- addLogEvent(new ProviderClientPermittedEvent(provider, true, identity));
+ addLog(new ProviderClientPermittedEvent(provider, true, identity));
}
}
/** Logs a client for a location provider leaving the permitted state. */
public void logProviderClientUnpermitted(String provider, CallerIdentity identity) {
if (D) {
- addLogEvent(new ProviderClientPermittedEvent(provider, false, identity));
+ addLog(new ProviderClientPermittedEvent(provider, false, identity));
}
}
/** Logs a change to the provider request for a location provider. */
public void logProviderUpdateRequest(String provider, ProviderRequest request) {
- addLogEvent(new ProviderUpdateEvent(provider, request));
+ addLog(new ProviderUpdateEvent(provider, request));
}
/** Logs a new incoming location for a location provider. */
public void logProviderReceivedLocations(String provider, int numLocations) {
- addLogEvent(new ProviderReceiveLocationEvent(provider, numLocations));
+ synchronized (this) {
+ mLocationsLog.logProviderReceivedLocations(provider, numLocations);
+ }
}
/** Logs a location deliver for a client of a location provider. */
public void logProviderDeliveredLocations(String provider, int numLocations,
CallerIdentity identity) {
- if (D) {
- addLogEvent(new ProviderDeliverLocationEvent(provider, numLocations, identity));
+ synchronized (this) {
+ mLocationsLog.logProviderDeliveredLocations(provider, numLocations, identity);
}
getAggregateStats(provider, identity).markLocationDelivered();
}
@@ -193,19 +207,24 @@
/** Logs that a provider has entered or exited stationary throttling. */
public void logProviderStationaryThrottled(String provider, boolean throttled,
ProviderRequest request) {
- addLogEvent(new ProviderStationaryThrottledEvent(provider, throttled, request));
+ addLog(new ProviderStationaryThrottledEvent(provider, throttled, request));
}
/** Logs that the location power save mode has changed. */
public void logLocationPowerSaveMode(
@LocationPowerSaveMode int locationPowerSaveMode) {
- addLogEvent(new LocationPowerSaveModeEvent(locationPowerSaveMode));
+ addLog(new LocationPowerSaveModeEvent(locationPowerSaveMode));
}
- private void addLogEvent(Object logEvent) {
+ private void addLog(Object logEvent) {
addLog(SystemClock.elapsedRealtime(), logEvent);
}
+ @Override
+ public synchronized void iterate(LogConsumer<? super Object> consumer) {
+ iterate(consumer, this, mLocationsLog);
+ }
+
public void iterate(Consumer<String> consumer) {
iterate(consumer, null);
}
@@ -488,6 +507,26 @@
}
}
+ private static final class LocationsEventLog extends LocalEventLog<Object> {
+
+ LocationsEventLog(int size) {
+ super(size, Object.class);
+ }
+
+ public void logProviderReceivedLocations(String provider, int numLocations) {
+ addLog(new ProviderReceiveLocationEvent(provider, numLocations));
+ }
+
+ public void logProviderDeliveredLocations(String provider, int numLocations,
+ CallerIdentity identity) {
+ addLog(new ProviderDeliverLocationEvent(provider, numLocations, identity));
+ }
+
+ private void addLog(Object logEvent) {
+ this.addLog(SystemClock.elapsedRealtime(), logEvent);
+ }
+ }
+
/**
* Aggregate statistics for a single package under a single provider.
*/
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index e696d1e..771bf19 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -2846,10 +2846,13 @@
@Override
public void sendResult(Bundle data) {
+ final long identity = Binder.clearCallingIdentity();
try {
mWakeLock.release();
} catch (RuntimeException e) {
Log.e(TAG, "wakelock over-released by " + mIdentity, e);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index bf50db8..65c5b88 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -255,6 +255,7 @@
import com.android.internal.util.StatLogger;
import com.android.internal.util.XmlUtils;
import com.android.net.module.util.NetworkIdentityUtils;
+import com.android.net.module.util.NetworkStatsUtils;
import com.android.net.module.util.PermissionUtils;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
@@ -2004,7 +2005,7 @@
for (final NetworkStateSnapshot snapshot : snapshots) {
mNetIdToSubId.put(snapshot.getNetwork().getNetId(), parseSubId(snapshot));
- // Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype
+ // Policies matched by NPMS only match by subscriber ID or by network ID. Thus subtype
// in the object created here is never used and its value doesn't matter, so use
// NETWORK_TYPE_UNKNOWN.
final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot,
@@ -2368,7 +2369,8 @@
templateMeteredness = readIntAttribute(in, ATTR_TEMPLATE_METERED);
} else {
- subscriberIdMatchRule = NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT;
+ subscriberIdMatchRule =
+ NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT;
if (templateType == MATCH_MOBILE) {
Log.d(TAG, "Update template match rule from mobile to carrier and"
+ " force to metered");
@@ -2431,12 +2433,20 @@
} else {
inferred = false;
}
- final NetworkTemplate template = new NetworkTemplate(templateType,
- subscriberId, new String[] { subscriberId },
- networkId, templateMeteredness, NetworkStats.ROAMING_ALL,
- NetworkStats.DEFAULT_NETWORK_ALL, NetworkTemplate.NETWORK_TYPE_ALL,
- NetworkTemplate.OEM_MANAGED_ALL, subscriberIdMatchRule);
- if (template.isPersistable()) {
+ final NetworkTemplate.Builder builder =
+ new NetworkTemplate.Builder(templateType)
+ .setMeteredness(templateMeteredness);
+ if (subscriberIdMatchRule
+ == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT) {
+ final ArraySet<String> ids = new ArraySet<>();
+ ids.add(subscriberId);
+ builder.setSubscriberIds(ids);
+ }
+ if (networkId != null) {
+ builder.setWifiNetworkKeys(Set.of(networkId));
+ }
+ final NetworkTemplate template = builder.build();
+ if (NetworkPolicy.isTemplatePersistable(template)) {
mNetworkPolicy.put(template, new NetworkPolicy(template, cycleRule,
warningBytes, limitBytes, lastWarningSnooze,
lastLimitSnooze, metered, inferred));
@@ -2585,35 +2595,39 @@
* into {@link WifiConfiguration}.
*/
private void upgradeWifiMeteredOverride() {
- final ArrayMap<String, Boolean> wifiNetworkIds = new ArrayMap<>();
+ final ArrayMap<String, Boolean> wifiNetworkKeys = new ArrayMap<>();
synchronized (mNetworkPoliciesSecondLock) {
for (int i = 0; i < mNetworkPolicy.size();) {
final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
if (policy.template.getMatchRule() == NetworkTemplate.MATCH_WIFI
&& !policy.inferred) {
mNetworkPolicy.removeAt(i);
- wifiNetworkIds.put(policy.template.getNetworkId(), policy.metered);
+ final Set<String> keys = policy.template.getWifiNetworkKeys();
+ wifiNetworkKeys.put(keys.isEmpty() ? null : keys.iterator().next(),
+ policy.metered);
} else {
i++;
}
}
}
- if (wifiNetworkIds.isEmpty()) {
+ if (wifiNetworkKeys.isEmpty()) {
return;
}
final WifiManager wm = mContext.getSystemService(WifiManager.class);
final List<WifiConfiguration> configs = wm.getConfiguredNetworks();
for (int i = 0; i < configs.size(); ++i) {
final WifiConfiguration config = configs.get(i);
- final String networkId = resolveNetworkId(config);
- final Boolean metered = wifiNetworkIds.get(networkId);
- if (metered != null) {
- Slog.d(TAG, "Found network " + networkId + "; upgrading metered hint");
- config.meteredOverride = metered
- ? WifiConfiguration.METERED_OVERRIDE_METERED
- : WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
- wm.updateNetwork(config);
+ for (String key : config.getAllPersistableNetworkKeys()) {
+ final Boolean metered = wifiNetworkKeys.get(key);
+ if (metered != null) {
+ Slog.d(TAG, "Found network " + key + "; upgrading metered hint");
+ config.meteredOverride = metered
+ ? WifiConfiguration.METERED_OVERRIDE_METERED
+ : WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
+ wm.updateNetwork(config);
+ break;
+ }
}
}
@@ -2643,7 +2657,7 @@
for (int i = 0; i < mNetworkPolicy.size(); i++) {
final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
final NetworkTemplate template = policy.template;
- if (!template.isPersistable()) continue;
+ if (!NetworkPolicy.isTemplatePersistable(template)) continue;
out.startTag(null, TAG_NETWORK_POLICY);
writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, template.getMatchRule());
@@ -2651,11 +2665,13 @@
if (subscriberId != null) {
out.attribute(null, ATTR_SUBSCRIBER_ID, subscriberId);
}
- writeIntAttribute(out, ATTR_SUBSCRIBER_ID_MATCH_RULE,
- template.getSubscriberIdMatchRule());
- final String networkId = template.getNetworkId();
- if (networkId != null) {
- out.attribute(null, ATTR_NETWORK_ID, networkId);
+ final int subscriberIdMatchRule = template.getSubscriberIds().isEmpty()
+ ? NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL
+ : NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT;
+ writeIntAttribute(out, ATTR_SUBSCRIBER_ID_MATCH_RULE, subscriberIdMatchRule);
+ if (!template.getWifiNetworkKeys().isEmpty()) {
+ out.attribute(null, ATTR_NETWORK_ID,
+ template.getWifiNetworkKeys().iterator().next());
}
writeIntAttribute(out, ATTR_TEMPLATE_METERED,
template.getMeteredness());
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 137fc85..2068632 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -7871,7 +7871,9 @@
int index = mToastQueue.indexOf(record);
if (index >= 0) {
- mToastQueue.remove(index);
+ ToastRecord toast = mToastQueue.remove(index);
+ mWindowManagerInternal.removeWindowToken(
+ toast.windowToken, true /* removeWindows */, toast.displayId);
}
record = (mToastQueue.size() > 0) ? mToastQueue.get(0) : null;
}
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 1945ed0..c2e4145 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -146,7 +146,6 @@
import com.android.server.pm.verify.domain.DomainVerificationUtils;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.utils.WatchedArrayMap;
-import com.android.server.utils.WatchedArraySet;
import com.android.server.utils.WatchedLongSparseArray;
import com.android.server.utils.WatchedSparseBooleanArray;
import com.android.server.utils.WatchedSparseIntArray;
@@ -321,10 +320,7 @@
private final WatchedArrayMap<String, AndroidPackage> mPackages;
private final WatchedArrayMap<ComponentName, ParsedInstrumentation>
mInstrumentation;
- private final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
- mStaticLibsByDeclaringPackage;
- private final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
- mSharedLibraries;
+ private final SharedLibrariesRead mSharedLibraries;
private final ComponentName mLocalResolveComponentName;
private final ActivityInfo mResolveActivity;
private final WatchedSparseBooleanArray mWebInstantAppsDisabled;
@@ -333,7 +329,7 @@
private final InstantAppRegistry mInstantAppRegistry;
private final ApplicationInfo mLocalAndroidApplication;
private final AppsFilter mAppsFilter;
- private final WatchedArraySet<String> mFrozenPackages;
+ private final WatchedArrayMap<String, Integer> mFrozenPackages;
// Immutable service attribute
private final String mAppPredictionServicePackage;
@@ -376,8 +372,7 @@
mSettings = new Settings(args.settings);
mIsolatedOwners = args.isolatedOwners;
mPackages = args.packages;
- mSharedLibraries = args.sharedLibs;
- mStaticLibsByDeclaringPackage = args.staticLibs;
+ mSharedLibraries = args.sharedLibraries;
mInstrumentation = args.instrumentation;
mWebInstantAppsDisabled = args.webInstantAppsDisabled;
mLocalResolveComponentName = args.resolveComponentName;
@@ -2007,8 +2002,7 @@
@Nullable
public final SharedLibraryInfo getSharedLibraryInfo(String name, long version) {
- return SharedLibraryHelper.getSharedLibraryInfo(
- name, version, mSharedLibraries, null);
+ return mSharedLibraries.getSharedLibraryInfo(name, version);
}
/**
@@ -2059,7 +2053,7 @@
// Is this a static library?
WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
- mStaticLibsByDeclaringPackage.get(packageName);
+ mSharedLibraries.getStaticLibraryInfos(packageName);
if (versionedLib == null || versionedLib.size() <= 0) {
return packageName;
}
@@ -3057,54 +3051,8 @@
}
case DumpState.DUMP_LIBS:
- {
- boolean printedHeader = false;
- final int numSharedLibraries = mSharedLibraries.size();
- for (int index = 0; index < numSharedLibraries; index++) {
- final String libName = mSharedLibraries.keyAt(index);
- final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
- mSharedLibraries.get(libName);
- if (versionedLib == null) {
- continue;
- }
- final int versionCount = versionedLib.size();
- for (int i = 0; i < versionCount; i++) {
- SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
- if (!checkin) {
- if (!printedHeader) {
- if (dumpState.onTitlePrinted()) {
- pw.println();
- }
- pw.println("Libraries:");
- printedHeader = true;
- }
- pw.print(" ");
- } else {
- pw.print("lib,");
- }
- pw.print(libraryInfo.getName());
- if (libraryInfo.isStatic()) {
- pw.print(" version=" + libraryInfo.getLongVersion());
- }
- if (!checkin) {
- pw.print(" -> ");
- }
- if (libraryInfo.getPath() != null) {
- if (libraryInfo.isNative()) {
- pw.print(" (so) ");
- } else {
- pw.print(" (jar) ");
- }
- pw.print(libraryInfo.getPath());
- } else {
- pw.print(" (apk) ");
- pw.print(libraryInfo.getPackageName());
- }
- pw.println();
- }
- }
+ mSharedLibraries.dump(pw, dumpState);
break;
- }
case DumpState.DUMP_PREFERRED:
mSettings.dumpPreferred(pw, dumpState, packageName);
@@ -3545,7 +3493,7 @@
@NonNull
@Override
public WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getSharedLibraries() {
- return mSharedLibraries;
+ return mSharedLibraries.getAll();
}
@NonNull
@@ -3580,7 +3528,7 @@
return PackageManagerService.PACKAGE_STARTABILITY_NOT_SYSTEM;
}
- if (mFrozenPackages.contains(packageName)) {
+ if (mFrozenPackages.containsKey(packageName)) {
return PackageManagerService.PACKAGE_STARTABILITY_FROZEN;
}
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index e84d990..c26f3b3 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -547,7 +547,6 @@
true /*notLaunched*/,
false /*hidden*/,
0 /*distractionFlags*/,
- false /*suspended*/,
null /*suspendParams*/,
false /*instantApp*/,
false /*virtualPreload*/,
diff --git a/services/core/java/com/android/server/pm/DumpHelper.java b/services/core/java/com/android/server/pm/DumpHelper.java
index c670e1f..55d1293 100644
--- a/services/core/java/com/android/server/pm/DumpHelper.java
+++ b/services/core/java/com/android/server/pm/DumpHelper.java
@@ -25,7 +25,6 @@
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.SharedLibraryInfo;
import android.os.Binder;
import android.os.UserHandle;
import android.os.incremental.PerUidReadTimeouts;
@@ -37,7 +36,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
-import com.android.server.utils.WatchedLongSparseArray;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -504,6 +502,9 @@
ipw.println("(none)");
} else {
for (int i = 0; i < mPm.mFrozenPackages.size(); i++) {
+ ipw.print("package=");
+ ipw.print(mPm.mFrozenPackages.keyAt(i));
+ ipw.print(", refCounts=");
ipw.println(mPm.mFrozenPackages.valueAt(i));
}
}
@@ -707,7 +708,7 @@
proto.end(verifierPackageToken);
}
- dumpSharedLibrariesProto(proto);
+ mPm.mInjector.getSharedLibrariesImpl().dumpProto(proto);
dumpFeaturesProto(proto);
mPm.mSettings.dumpPackagesProto(proto);
mPm.mSettings.dumpSharedUsersProto(proto);
@@ -725,33 +726,4 @@
}
}
}
-
- private void dumpSharedLibrariesProto(ProtoOutputStream proto) {
- final int count = mPm.mSharedLibraries.size();
- for (int i = 0; i < count; i++) {
- final String libName = mPm.mSharedLibraries.keyAt(i);
- WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
- mPm.mSharedLibraries.get(libName);
- if (versionedLib == null) {
- continue;
- }
- final int versionCount = versionedLib.size();
- for (int j = 0; j < versionCount; j++) {
- final SharedLibraryInfo libraryInfo = versionedLib.valueAt(j);
- final long sharedLibraryToken =
- proto.start(PackageServiceDumpProto.SHARED_LIBRARIES);
- proto.write(PackageServiceDumpProto.SharedLibraryProto.NAME, libraryInfo.getName());
- final boolean isJar = (libraryInfo.getPath() != null);
- proto.write(PackageServiceDumpProto.SharedLibraryProto.IS_JAR, isJar);
- if (isJar) {
- proto.write(PackageServiceDumpProto.SharedLibraryProto.PATH,
- libraryInfo.getPath());
- } else {
- proto.write(PackageServiceDumpProto.SharedLibraryProto.APK,
- libraryInfo.getPackageName());
- }
- proto.end(sharedLibraryToken);
- }
- }
- }
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 8e6746d..c595b97 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -207,6 +207,7 @@
private final PackageAbiHelper mPackageAbiHelper;
private final ViewCompiler mViewCompiler;
private final IBackupManager mIBackupManager;
+ private final SharedLibrariesImpl mSharedLibraries;
// TODO(b/198166813): remove PMS dependency
InstallPackageHelper(PackageManagerService pm, AppDataHelper appDataHelper) {
@@ -226,6 +227,7 @@
mPackageAbiHelper = pm.mInjector.getAbiHelper();
mViewCompiler = pm.mInjector.getViewCompiler();
mIBackupManager = pm.mInjector.getIBackupManager();
+ mSharedLibraries = pm.mInjector.getSharedLibrariesImpl();
}
InstallPackageHelper(PackageManagerService pm) {
@@ -325,7 +327,7 @@
}
if (reconciledPkg.mCollectedSharedLibraryInfos != null) {
- mPm.executeSharedLibrariesUpdateLPr(pkg, pkgSetting, null, null,
+ mSharedLibraries.executeSharedLibrariesUpdateLPw(pkg, pkgSetting, null, null,
reconciledPkg.mCollectedSharedLibraryInfos, allUsers);
}
@@ -388,13 +390,13 @@
synchronized (mPm.mLock) {
if (!ArrayUtils.isEmpty(reconciledPkg.mAllowedSharedLibraryInfos)) {
for (SharedLibraryInfo info : reconciledPkg.mAllowedSharedLibraryInfos) {
- mPm.commitSharedLibraryInfoLocked(info);
+ mSharedLibraries.commitSharedLibraryInfoLPw(info);
}
final Map<String, AndroidPackage> combinedSigningDetails =
reconciledPkg.getCombinedAvailablePackages();
try {
// Shared libraries for the package need to be updated.
- mPm.updateSharedLibrariesLocked(pkg, pkgSetting, null, null,
+ mSharedLibraries.updateSharedLibrariesLPw(pkg, pkgSetting, null, null,
combinedSigningDetails);
} catch (PackageManagerException e) {
Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
@@ -402,7 +404,7 @@
// Update all applications that use this library. Skip when booting
// since this will be done after all packages are scaned.
if ((scanFlags & SCAN_BOOTING) == 0) {
- clientLibPkgs = mPm.updateAllSharedLibrariesLocked(pkg, pkgSetting,
+ clientLibPkgs = mSharedLibraries.updateAllSharedLibrariesLPw(pkg, pkgSetting,
combinedSigningDetails);
}
}
@@ -855,7 +857,7 @@
mPm.notifyInstallObserver(request.mInstallResult, request.mArgs.mObserver);
}
- @GuardedBy("mInstallLock")
+ @GuardedBy("mPm.mInstallLock")
private void installPackagesTracedLI(List<InstallRequest> requests) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
@@ -884,7 +886,7 @@
*
* Failure at any phase will result in a full failure to install all packages.
*/
- @GuardedBy("mInstallLock")
+ @GuardedBy("mPm.mInstallLock")
private void installPackagesLI(List<InstallRequest> requests) {
final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
@@ -945,7 +947,7 @@
if (result.mStaticSharedLibraryInfo != null
|| result.mSdkSharedLibraryInfo != null) {
final PackageSetting sharedLibLatestVersionSetting =
- mPm.getSharedLibLatestVersionSetting(result);
+ mSharedLibraries.getSharedLibLatestVersionSetting(result);
if (sharedLibLatestVersionSetting != null) {
lastStaticSharedLibSettings.put(
result.mPkgSetting.getPkg().getPackageName(),
@@ -961,7 +963,7 @@
reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
installResults,
prepareResults,
- mPm.mSharedLibraries,
+ mSharedLibraries.getAll(),
Collections.unmodifiableMap(mPm.mPackages), versionInfos,
lastStaticSharedLibSettings);
CommitRequest commitRequest = null;
@@ -1036,7 +1038,7 @@
}
}
- @GuardedBy("mInstallLock")
+ @GuardedBy("mPm.mInstallLock")
private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
throws PrepareFailure {
final int installFlags = args.mInstallFlags;
@@ -1207,7 +1209,7 @@
// the package setting for the latest library version.
PackageSetting signatureCheckPs = ps;
if (parsedPackage.isStaticSharedLibrary()) {
- SharedLibraryInfo libraryInfo = mPm.getLatestSharedLibraVersionLPr(
+ SharedLibraryInfo libraryInfo = mSharedLibraries.getLatestSharedLibraVersionLPr(
parsedPackage);
if (libraryInfo != null) {
signatureCheckPs = mPm.mSettings.getPackageLPr(
@@ -1880,7 +1882,7 @@
}
}
- @GuardedBy("mLock")
+ @GuardedBy("mPm.mLock")
private void commitPackagesLocked(final CommitRequest request) {
// TODO: remove any expected failures from this method; this should only be able to fail due
// to unavoidable errors (I/O, etc.)
@@ -1997,7 +1999,7 @@
ApplicationPackageManager.invalidateGetPackagesForUidCache();
}
- @GuardedBy("mLock")
+ @GuardedBy("mPm.mLock")
private boolean disableSystemPackageLPw(AndroidPackage oldPkg) {
return mPm.mSettings.disableSystemPackageLPw(oldPkg.getPackageName(), true);
}
@@ -2969,7 +2971,8 @@
synchronized (mPm.mLock) {
mAppDataHelper.prepareAppDataAfterInstallLIF(pkg);
try {
- mPm.updateSharedLibrariesLocked(pkg, stubPkgSetting, null, null,
+ mSharedLibraries.updateSharedLibrariesLPw(
+ pkg, stubPkgSetting, null, null,
Collections.unmodifiableMap(mPm.mPackages));
} catch (PackageManagerException e) {
Slog.w(TAG, "updateAllSharedLibrariesLPw failed: ", e);
@@ -2992,7 +2995,8 @@
installPackageFromSystemLIF(stubPkg.getPath(),
mPm.mUserManager.getUserIds() /*allUserHandles*/,
null /*origUserHandles*/,
- true /*writeSettings*/);
+ true /*writeSettings*/,
+ Process.INVALID_UID /*previousAppId*/);
} catch (PackageManagerException pme) {
// Serious WTF; we have to be able to install the stub
Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(),
@@ -3118,8 +3122,11 @@
if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
try {
synchronized (mPm.mInstallLock) {
+ final int[] origUsers = outInfo == null ? null : outInfo.mOrigUsers;
+ final int previousAppId = disabledPs.getAppId() != deletedPs.getAppId()
+ ? deletedPs.getAppId() : Process.INVALID_UID;
installPackageFromSystemLIF(disabledPs.getPathString(), allUserHandles,
- outInfo == null ? null : outInfo.mOrigUsers, writeSettings);
+ origUsers, writeSettings, previousAppId);
}
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to restore system package:" + deletedPs.getPackageName() + ": "
@@ -3160,7 +3167,8 @@
*/
@GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
private void installPackageFromSystemLIF(@NonNull String codePathString,
- @NonNull int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings)
+ @NonNull int[] allUserHandles, @Nullable int[] origUserHandles,
+ boolean writeSettings, int previousAppId)
throws PackageManagerException {
final File codePath = new File(codePathString);
@ParsingPackageUtils.ParseFlags int parseFlags =
@@ -3175,7 +3183,7 @@
try {
// update shared libraries for the newly re-installed system package
- mPm.updateSharedLibrariesLocked(pkg, pkgSetting, null, null,
+ mSharedLibraries.updateSharedLibrariesLPw(pkg, pkgSetting, null, null,
Collections.unmodifiableMap(mPm.mPackages));
} catch (PackageManagerException e) {
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
@@ -3184,11 +3192,12 @@
mAppDataHelper.prepareAppDataAfterInstallLIF(pkg);
setPackageInstalledForSystemPackage(pkg, allUserHandles,
- origUserHandles, writeSettings);
+ origUserHandles, writeSettings, previousAppId);
}
private void setPackageInstalledForSystemPackage(@NonNull AndroidPackage pkg,
- @NonNull int[] allUserHandles, @Nullable int[] origUserHandles, boolean writeSettings) {
+ @NonNull int[] allUserHandles, @Nullable int[] origUserHandles,
+ boolean writeSettings, int previousAppId) {
// writer
synchronized (mPm.mLock) {
PackageSetting ps = mPm.mSettings.getPackageLPr(pkg.getPackageName());
@@ -3222,8 +3231,7 @@
// The method below will take care of removing obsolete permissions and granting
// install permissions.
- mPm.mPermissionManager.onPackageInstalled(pkg,
- Process.INVALID_UID /* previousAppId */,
+ mPm.mPermissionManager.onPackageInstalled(pkg, previousAppId,
PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT,
UserHandle.USER_ALL);
for (final int userId : allUserHandles) {
@@ -3554,15 +3562,14 @@
ReconcilePackageUtils.reconcilePackages(
new ReconcileRequest(
Collections.singletonMap(pkgName, scanResult),
- mPm.mSharedLibraries,
+ mSharedLibraries.getAll(),
mPm.mPackages,
Collections.singletonMap(
pkgName,
mPm.getSettingsVersionForPackage(
parsedPackage)),
- Collections.singletonMap(pkgName,
- mPm.getSharedLibLatestVersionSetting(
- scanResult))),
+ Collections.singletonMap(pkgName, mSharedLibraries
+ .getSharedLibLatestVersionSetting(scanResult))),
mPm.mSettings.getKeySetManagerService(), mPm.mInjector);
appIdCreated = optimisticallyRegisterAppId(scanResult);
commitReconciledScanResultLocked(
@@ -4187,8 +4194,8 @@
long minVersionCode = Long.MIN_VALUE;
long maxVersionCode = Long.MAX_VALUE;
- WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mPm.mSharedLibraries.get(
- pkg.getStaticSharedLibName());
+ WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
+ mSharedLibraries.getSharedLibraryInfos(pkg.getStaticSharedLibName());
if (versionedLib != null) {
final int versionCount = versionedLib.size();
for (int i = 0; i < versionCount; i++) {
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index a380344..47be7e6 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -100,6 +100,8 @@
public static final int FLAG_FREE_CACHE_V2 = IInstalld.FLAG_FREE_CACHE_V2;
public static final int FLAG_FREE_CACHE_V2_DEFY_QUOTA = IInstalld.FLAG_FREE_CACHE_V2_DEFY_QUOTA;
public static final int FLAG_FREE_CACHE_NOOP = IInstalld.FLAG_FREE_CACHE_NOOP;
+ public static final int FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES =
+ IInstalld.FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES;
public static final int FLAG_USE_QUOTA = IInstalld.FLAG_USE_QUOTA;
public static final int FLAG_FORCE = IInstalld.FLAG_FORCE;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 6e6773f..0777cde 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -1685,14 +1685,12 @@
continue;
}
final String[] filteredPackagesWithoutExtras =
- getFilteredPackageNames(packages, cookie);
- // If all packages are filtered, skip notifying listener.
- if (ArrayUtils.isEmpty(filteredPackagesWithoutExtras)) {
- continue;
- }
+ getFilteredPackageNames(packagesNullExtras, cookie);
try {
- listener.onPackagesSuspended(user, filteredPackagesWithoutExtras,
- /* launcherExtras= */ null);
+ if (!ArrayUtils.isEmpty(filteredPackagesWithoutExtras)) {
+ listener.onPackagesSuspended(user, filteredPackagesWithoutExtras,
+ /* launcherExtras= */ null);
+ }
for (int idx = 0; idx < packagesWithExtras.size(); idx++) {
Pair<String, Bundle> packageExtraPair = packagesWithExtras.get(idx);
if (!isPackageVisibleToListener(packageExtraPair.first, cookie)) {
diff --git a/services/core/java/com/android/server/pm/MovePackageHelper.java b/services/core/java/com/android/server/pm/MovePackageHelper.java
index 19ebb5d..652a9ae 100644
--- a/services/core/java/com/android/server/pm/MovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/MovePackageHelper.java
@@ -130,7 +130,7 @@
"Device admin cannot be moved");
}
- if (mPm.mFrozenPackages.contains(packageName)) {
+ if (mPm.mFrozenPackages.containsKey(packageName)) {
throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
"Failed to move already frozen package");
}
@@ -188,6 +188,7 @@
for (int userId : installedUserIds) {
if (StorageManager.isFileEncryptedNativeOrEmulated()
&& !StorageManager.isUserKeyUnlocked(userId)) {
+ freezer.close();
throw new PackageManagerException(MOVE_FAILED_LOCKED_USER,
"User " + userId + " must be unlocked");
}
@@ -230,6 +231,7 @@
final IPackageInstallObserver2 installObserver = new IPackageInstallObserver2.Stub() {
@Override
public void onUserActionRequired(Intent intent) throws RemoteException {
+ freezer.close();
throw new IllegalStateException();
}
diff --git a/services/core/java/com/android/server/pm/PackageFreezer.java b/services/core/java/com/android/server/pm/PackageFreezer.java
index ecc92b7..1e0a1f2 100644
--- a/services/core/java/com/android/server/pm/PackageFreezer.java
+++ b/services/core/java/com/android/server/pm/PackageFreezer.java
@@ -31,8 +31,6 @@
final class PackageFreezer implements AutoCloseable {
private final String mPackageName;
- private final boolean mWeFroze;
-
private final AtomicBoolean mClosed = new AtomicBoolean();
private final CloseGuard mCloseGuard = CloseGuard.get();
@@ -48,7 +46,7 @@
PackageFreezer(PackageManagerService pm) {
mPm = pm;
mPackageName = null;
- mWeFroze = false;
+ mClosed.set(true);
mCloseGuard.open("close");
}
@@ -58,7 +56,9 @@
mPackageName = packageName;
final PackageSetting ps;
synchronized (mPm.mLock) {
- mWeFroze = mPm.mFrozenPackages.add(mPackageName);
+ final int refCounts = mPm.mFrozenPackages
+ .getOrDefault(mPackageName, 0 /* defaultValue */) + 1;
+ mPm.mFrozenPackages.put(mPackageName, refCounts);
ps = mPm.mSettings.getPackageLPr(mPackageName);
}
if (ps != null) {
@@ -82,7 +82,11 @@
mCloseGuard.close();
if (mClosed.compareAndSet(false, true)) {
synchronized (mPm.mLock) {
- if (mWeFroze) {
+ final int refCounts = mPm.mFrozenPackages
+ .getOrDefault(mPackageName, 0 /* defaultValue */) - 1;
+ if (refCounts > 0) {
+ mPm.mFrozenPackages.put(mPackageName, refCounts);
+ } else {
mPm.mFrozenPackages.remove(mPackageName);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java
index 217bc23..d1ea41a 100644
--- a/services/core/java/com/android/server/pm/PackageHandler.java
+++ b/services/core/java/com/android/server/pm/PackageHandler.java
@@ -388,7 +388,8 @@
}
case PRUNE_UNUSED_STATIC_SHARED_LIBRARIES: {
try {
- mPm.pruneUnusedStaticSharedLibraries(Long.MAX_VALUE,
+ mPm.mInjector.getSharedLibrariesImpl().pruneUnusedStaticSharedLibraries(
+ Long.MAX_VALUE,
Settings.Global.getLong(mPm.mContext.getContentResolver(),
Settings.Global.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD,
DEFAULT_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD));
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6f8703b..248944e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -239,6 +239,9 @@
import com.android.server.pm.pkg.PackageUserState;
import com.android.server.pm.pkg.PackageUserStateInternal;
import com.android.server.pm.pkg.SuspendParams;
+import com.android.server.pm.pkg.mutate.PackageStateMutator;
+import com.android.server.pm.pkg.mutate.PackageStateWrite;
+import com.android.server.pm.pkg.mutate.PackageUserStateWrite;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.pm.verify.domain.DomainVerificationService;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
@@ -249,8 +252,6 @@
import com.android.server.utils.Watchable;
import com.android.server.utils.Watched;
import com.android.server.utils.WatchedArrayMap;
-import com.android.server.utils.WatchedArraySet;
-import com.android.server.utils.WatchedLongSparseArray;
import com.android.server.utils.WatchedSparseBooleanArray;
import com.android.server.utils.WatchedSparseIntArray;
import com.android.server.utils.Watcher;
@@ -280,7 +281,6 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -290,7 +290,6 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -598,6 +597,16 @@
// the suffix "Locked". Some methods may use the legacy suffix "LP"
final PackageManagerTracedLock mLock;
+ // Lock alias for doing package state mutation
+ private final PackageManagerTracedLock mPackageStateWriteLock;
+
+ // Lock alias to track syncing a consistent Computer
+ private final PackageManagerTracedLock mLiveComputerSyncLock;
+
+ private final PackageStateMutator mPackageStateMutator = new PackageStateMutator(
+ this::getPackageSettingForMutation,
+ this::getDisabledPackageSettingForMutation);
+
// Keys are String (package name), values are Package.
@Watched
@GuardedBy("mLock")
@@ -646,15 +655,16 @@
final Settings mSettings;
/**
- * Set of package names that are currently "frozen", which means active
- * surgery is being done on the code/data for that package. The platform
- * will refuse to launch frozen packages to avoid race conditions.
+ * Map of package names to frozen counts that are currently "frozen",
+ * which means active surgery is being done on the code/data for that
+ * package. The platform will refuse to launch frozen packages to avoid
+ * race conditions.
*
* @see PackageFreezer
*/
@GuardedBy("mLock")
- final WatchedArraySet<String> mFrozenPackages = new WatchedArraySet<>();
- private final SnapshotCache<WatchedArraySet<String>> mFrozenPackagesSnapshot =
+ final WatchedArrayMap<String, Integer> mFrozenPackages = new WatchedArrayMap<>();
+ private final SnapshotCache<WatchedArrayMap<String, Integer>> mFrozenPackagesSnapshot =
new SnapshotCache.Auto(mFrozenPackages, mFrozenPackages,
"PackageManagerService.mFrozenPackages");
@@ -757,19 +767,7 @@
// Currently known shared libraries.
@Watched
- final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
- mSharedLibraries = new WatchedArrayMap<>();
- private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
- mSharedLibrariesSnapshot =
- new SnapshotCache.Auto<>(mSharedLibraries, mSharedLibraries,
- "PackageManagerService.mSharedLibraries");
- @Watched
- final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
- mStaticLibsByDeclaringPackage = new WatchedArrayMap<>();
- private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
- mStaticLibsByDeclaringPackageSnapshot =
- new SnapshotCache.Auto<>(mStaticLibsByDeclaringPackage, mStaticLibsByDeclaringPackage,
- "PackageManagerService.mStaticLibsByDeclaringPackage");
+ private final SharedLibrariesImpl mSharedLibraries;
// Mapping from instrumentation class names to info about them.
@Watched
@@ -1002,8 +1000,6 @@
public final Settings settings;
public final WatchedSparseIntArray isolatedOwners;
public final WatchedArrayMap<String, AndroidPackage> packages;
- public final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> sharedLibs;
- public final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> staticLibs;
public final WatchedArrayMap<ComponentName, ParsedInstrumentation> instrumentation;
public final WatchedSparseBooleanArray webInstantAppsDisabled;
public final ComponentName resolveComponentName;
@@ -1016,15 +1012,14 @@
public final AppsFilter appsFilter;
public final ComponentResolver componentResolver;
public final PackageManagerService service;
- public final WatchedArraySet<String> frozenPackages;
+ public final WatchedArrayMap<String, Integer> frozenPackages;
+ public final SharedLibrariesRead sharedLibraries;
Snapshot(int type) {
if (type == Snapshot.SNAPPED) {
settings = mSettings.snapshot();
isolatedOwners = mIsolatedOwnersSnapshot.snapshot();
packages = mPackagesSnapshot.snapshot();
- sharedLibs = mSharedLibrariesSnapshot.snapshot();
- staticLibs = mStaticLibsByDeclaringPackageSnapshot.snapshot();
instrumentation = mInstrumentationSnapshot.snapshot();
resolveComponentName = mResolveComponentName.clone();
resolveActivity = new ActivityInfo(mResolveActivity);
@@ -1043,12 +1038,11 @@
appsFilter = mAppsFilter.snapshot();
componentResolver = mComponentResolver.snapshot();
frozenPackages = mFrozenPackagesSnapshot.snapshot();
+ sharedLibraries = mSharedLibraries.snapshot();
} else if (type == Snapshot.LIVE) {
settings = mSettings;
isolatedOwners = mIsolatedOwners;
packages = mPackages;
- sharedLibs = mSharedLibraries;
- staticLibs = mStaticLibsByDeclaringPackage;
instrumentation = mInstrumentation;
resolveComponentName = mResolveComponentName;
resolveActivity = mResolveActivity;
@@ -1061,6 +1055,7 @@
appsFilter = mAppsFilter;
componentResolver = mComponentResolver;
frozenPackages = mFrozenPackages;
+ sharedLibraries = mSharedLibraries;
} else {
throw new IllegalArgumentException();
}
@@ -1522,7 +1517,8 @@
context::getSystemService,
(i, pm) -> new BackgroundDexOptService(i.getContext(), i.getDexManager(), pm),
(i, pm) -> IBackupManager.Stub.asInterface(ServiceManager.getService(
- Context.BACKUP_SERVICE)));
+ Context.BACKUP_SERVICE)),
+ (i, pm) -> new SharedLibrariesImpl(pm, i));
if (Build.VERSION.SDK_INT <= 0) {
Slog.w(TAG, "**** ro.build.version.sdk not set!");
@@ -1594,7 +1590,6 @@
private void registerObserver() {
mPackages.registerObserver(mWatcher);
mSharedLibraries.registerObserver(mWatcher);
- mStaticLibsByDeclaringPackage.registerObserver(mWatcher);
mInstrumentation.registerObserver(mWatcher);
mWebInstantAppsDisabled.registerObserver(mWatcher);
mAppsFilter.registerObserver(mWatcher);
@@ -1626,11 +1621,14 @@
mInstaller = injector.getInstaller();
mInstallLock = injector.getInstallLock();
mLock = injector.getLock();
+ mPackageStateWriteLock = mLock;
+ mLiveComputerSyncLock = mLock;
mPermissionManager = injector.getPermissionManagerServiceInternal();
mSettings = injector.getSettings();
mUserManager = injector.getUserManagerService();
mDomainVerificationManager = injector.getDomainVerificationManagerInternal();
mHandler = injector.getHandler();
+ mSharedLibraries = injector.getSharedLibrariesImpl();
mApexManager = testParams.apexManager;
mArtManagerService = testParams.artManagerService;
@@ -1708,6 +1706,7 @@
mPreferredActivityHelper = testParams.preferredActivityHelper;
mResolveIntentHelper = testParams.resolveIntentHelper;
mDexOptHelper = testParams.dexOptHelper;
+ mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
invalidatePackageInfoCache();
}
@@ -1729,6 +1728,8 @@
mInjector.bootstrap(this);
mLock = injector.getLock();
+ mPackageStateWriteLock = mLock;
+ mLiveComputerSyncLock = mLock;
mInstallLock = injector.getInstallLock();
LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES);
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
@@ -1817,6 +1818,7 @@
mArtManagerService = injector.getArtManagerService();
mMoveCallbacks = new MovePackageHelper.MoveCallbacks(FgThread.get().getLooper());
mViewCompiler = injector.getViewCompiler();
+ mSharedLibraries = mInjector.getSharedLibrariesImpl();
mContext.getSystemService(DisplayManager.class)
.getDisplay(Display.DEFAULT_DISPLAY).getMetrics(mMetrics);
@@ -1846,6 +1848,7 @@
mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this);
mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
mAppDataHelper);
+ mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
mPreferredActivityHelper = new PreferredActivityHelper(this);
mResolveIntentHelper = new ResolveIntentHelper(this, mPreferredActivityHelper);
mDexOptHelper = new DexOptHelper(this);
@@ -1877,7 +1880,7 @@
= systemConfig.getSharedLibraries();
final int builtInLibCount = libConfig.size();
for (int i = 0; i < builtInLibCount; i++) {
- addBuiltInSharedLibraryLocked(libConfig.valueAt(i));
+ mSharedLibraries.addBuiltInSharedLibraryLPw(libConfig.valueAt(i));
}
// Now that we have added all the libraries, iterate again to add dependency
@@ -1996,7 +1999,8 @@
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
- updateAllSharedLibrariesLocked(null, null, Collections.unmodifiableMap(mPackages));
+ mSharedLibraries.updateAllSharedLibrariesLPw(
+ null, null, Collections.unmodifiableMap(mPackages));
for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
// NOTE: We ignore potential failures here during a system scan (like
@@ -2780,6 +2784,23 @@
}
/**
+ * Blocking call to clear all cached app data above quota.
+ */
+ public void freeAllAppCacheAboveQuota(String volumeUuid) throws IOException {
+ synchronized (mInstallLock) {
+ // To avoid refactoring Installer.freeCache() and InstalldNativeService.freeCache(),
+ // Long.MAX_VALUE is passed as an argument which is used in neither of two methods
+ // when FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES is set
+ try {
+ mInstaller.freeCache(volumeUuid, Long.MAX_VALUE, Installer.FLAG_FREE_CACHE_V2
+ | Installer.FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES);
+ } catch (InstallerException ignored) {
+ }
+ }
+ return;
+ }
+
+ /**
* Blocking call to clear various types of cached data across the system
* until the requested bytes are available.
*/
@@ -2818,7 +2839,7 @@
if (file.getUsableSpace() >= bytes) return;
// 5. Consider shared libraries with refcount=0 and age>min cache period
- if (internalVolume && pruneUnusedStaticSharedLibraries(bytes,
+ if (internalVolume && mSharedLibraries.pruneUnusedStaticSharedLibraries(bytes,
android.provider.Settings.Global.getLong(mContext.getContentResolver(),
Global.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD,
FREE_STORAGE_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD))) {
@@ -2880,85 +2901,6 @@
throw new IOException("Failed to free " + bytes + " on storage device at " + file);
}
- private PackageSetting getLibraryPackage(SharedLibraryInfo libInfo) {
- final VersionedPackage declaringPackage = libInfo.getDeclaringPackage();
- if (libInfo.isStatic()) {
- // Resolve the package name - we use synthetic package names internally
- final String internalPackageName = resolveInternalPackageNameLPr(
- declaringPackage.getPackageName(),
- declaringPackage.getLongVersionCode());
- return mSettings.getPackageLPr(internalPackageName);
- }
- if (libInfo.isSdk()) {
- return mSettings.getPackageLPr(declaringPackage.getPackageName());
- }
- return null;
- }
-
- boolean pruneUnusedStaticSharedLibraries(long neededSpace, long maxCachePeriod)
- throws IOException {
- final StorageManager storage = mInjector.getSystemService(StorageManager.class);
- final File volume = storage.findPathForUuid(StorageManager.UUID_PRIVATE_INTERNAL);
-
- List<VersionedPackage> packagesToDelete = null;
- final long now = System.currentTimeMillis();
-
- // Important: We skip shared libs used for some user since
- // in such a case we need to keep the APK on the device. The check for
- // a lib being used for any user is performed by the uninstall call.
- synchronized (mLock) {
- final int libCount = mSharedLibraries.size();
- for (int i = 0; i < libCount; i++) {
- final WatchedLongSparseArray<SharedLibraryInfo> versionedLib
- = mSharedLibraries.valueAt(i);
- if (versionedLib == null) {
- continue;
- }
- final int versionCount = versionedLib.size();
- for (int j = 0; j < versionCount; j++) {
- SharedLibraryInfo libInfo = versionedLib.valueAt(j);
- final PackageSetting ps = getLibraryPackage(libInfo);
- if (ps == null) {
- continue;
- }
- // Skip unused libs cached less than the min period to prevent pruning a lib
- // needed by a subsequently installed package.
- if (now - ps.getLastUpdateTime() < maxCachePeriod) {
- continue;
- }
-
- if (ps.getPkg().isSystem()) {
- continue;
- }
-
- if (packagesToDelete == null) {
- packagesToDelete = new ArrayList<>();
- }
- packagesToDelete.add(new VersionedPackage(ps.getPkg().getPackageName(),
- libInfo.getDeclaringPackage().getLongVersionCode()));
- }
- }
- }
-
- if (packagesToDelete != null) {
- final int packageCount = packagesToDelete.size();
- for (int i = 0; i < packageCount; i++) {
- final VersionedPackage pkgToDelete = packagesToDelete.get(i);
- // Delete the package synchronously (will fail of the lib used for any user).
- if (mDeletePackageHelper.deletePackageX(pkgToDelete.getPackageName(),
- pkgToDelete.getLongVersionCode(), UserHandle.USER_SYSTEM,
- PackageManager.DELETE_ALL_USERS,
- true /*removedBySystem*/) == PackageManager.DELETE_SUCCEEDED) {
- if (volume.getUsableSpace() >= neededSpace) {
- return true;
- }
- }
- }
- }
-
- return false;
- }
-
/**
* Update given flags when being used to request {@link PackageInfo}.
*/
@@ -3944,40 +3886,6 @@
return mComputer.getSharedLibraryInfo(name, version);
}
- SharedLibraryInfo getLatestSharedLibraVersionLPr(AndroidPackage pkg) {
- WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(
- pkg.getStaticSharedLibName());
- if (versionedLib == null) {
- return null;
- }
- long previousLibVersion = -1;
- final int versionCount = versionedLib.size();
- for (int i = 0; i < versionCount; i++) {
- final long libVersion = versionedLib.keyAt(i);
- if (libVersion < pkg.getStaticSharedLibVersion()) {
- previousLibVersion = Math.max(previousLibVersion, libVersion);
- }
- }
- if (previousLibVersion >= 0) {
- return versionedLib.get(previousLibVersion);
- }
- return null;
- }
-
- @Nullable
- PackageSetting getSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) {
- PackageSetting sharedLibPackage = null;
- synchronized (mLock) {
- final SharedLibraryInfo latestSharedLibraVersionLPr =
- getLatestSharedLibraVersionLPr(scanResult.mRequest.mParsedPackage);
- if (latestSharedLibraVersionLPr != null) {
- sharedLibPackage = mSettings.getPackageLPr(
- latestSharedLibraVersionLPr.getPackageName());
- }
- }
- return sharedLibPackage;
- }
-
public void shutdown() {
mCompilerStats.writeNow();
mDexManager.writePackageDexUsageNow();
@@ -4032,253 +3940,6 @@
return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId };
}
- @GuardedBy("mLock")
- private void applyDefiningSharedLibraryUpdateLocked(
- AndroidPackage pkg, SharedLibraryInfo libInfo,
- BiConsumer<SharedLibraryInfo, SharedLibraryInfo> action) {
- // Note that libraries defined by this package may be null if:
- // - Package manager was unable to create the shared library. The package still
- // gets installed, but the shared library does not get created.
- // Or:
- // - Package manager is in a state where package isn't scanned yet. This will
- // get called again after scanning to fix the dependencies.
- if (AndroidPackageUtils.isLibrary(pkg)) {
- if (pkg.getSdkLibName() != null) {
- SharedLibraryInfo definedLibrary = getSharedLibraryInfo(
- pkg.getSdkLibName(), pkg.getSdkLibVersionMajor());
- if (definedLibrary != null) {
- action.accept(definedLibrary, libInfo);
- }
- } else if (pkg.getStaticSharedLibName() != null) {
- SharedLibraryInfo definedLibrary = getSharedLibraryInfo(
- pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion());
- if (definedLibrary != null) {
- action.accept(definedLibrary, libInfo);
- }
- } else {
- for (String libraryName : pkg.getLibraryNames()) {
- SharedLibraryInfo definedLibrary = getSharedLibraryInfo(
- libraryName, SharedLibraryInfo.VERSION_UNDEFINED);
- if (definedLibrary != null) {
- action.accept(definedLibrary, libInfo);
- }
- }
- }
- }
- }
-
- @GuardedBy("mLock")
- private void addSharedLibraryLPr(AndroidPackage pkg, Set<String> usesLibraryFiles,
- SharedLibraryInfo libInfo, @Nullable AndroidPackage changingLib,
- @Nullable PackageSetting changingLibSetting) {
- if (libInfo.getPath() != null) {
- usesLibraryFiles.add(libInfo.getPath());
- return;
- }
- AndroidPackage pkgForCodePaths = mPackages.get(libInfo.getPackageName());
- PackageSetting pkgSetting = mSettings.getPackageLPr(libInfo.getPackageName());
- if (changingLib != null && changingLib.getPackageName().equals(libInfo.getPackageName())) {
- // If we are doing this while in the middle of updating a library apk,
- // then we need to make sure to use that new apk for determining the
- // dependencies here. (We haven't yet finished committing the new apk
- // to the package manager state.)
- if (pkgForCodePaths == null
- || pkgForCodePaths.getPackageName().equals(changingLib.getPackageName())) {
- pkgForCodePaths = changingLib;
- pkgSetting = changingLibSetting;
- }
- }
- if (pkgForCodePaths != null) {
- usesLibraryFiles.addAll(AndroidPackageUtils.getAllCodePaths(pkgForCodePaths));
- // If the package provides libraries, add the dependency to them.
- applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, SharedLibraryInfo::addDependency);
- if (pkgSetting != null) {
- usesLibraryFiles.addAll(pkgSetting.getPkgState().getUsesLibraryFiles());
- }
- }
- }
-
- @GuardedBy("mLock")
- void updateSharedLibrariesLocked(AndroidPackage pkg, PackageSetting pkgSetting,
- @Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting,
- Map<String, AndroidPackage> availablePackages)
- throws PackageManagerException {
- final ArrayList<SharedLibraryInfo> sharedLibraryInfos =
- SharedLibraryHelper.collectSharedLibraryInfos(
- pkgSetting.getPkg(), availablePackages, mSharedLibraries,
- null /* newLibraries */, mInjector.getCompatibility());
- executeSharedLibrariesUpdateLPr(pkg, pkgSetting, changingLib, changingLibSetting,
- sharedLibraryInfos, mUserManager.getUserIds());
- }
-
- void executeSharedLibrariesUpdateLPr(AndroidPackage pkg,
- @NonNull PackageSetting pkgSetting, @Nullable AndroidPackage changingLib,
- @Nullable PackageSetting changingLibSetting,
- ArrayList<SharedLibraryInfo> usesLibraryInfos, int[] allUsers) {
- // If the package provides libraries, clear their old dependencies.
- // This method will set them up again.
- applyDefiningSharedLibraryUpdateLocked(pkg, null, (definingLibrary, dependency) -> {
- definingLibrary.clearDependencies();
- });
- if (usesLibraryInfos != null) {
- pkgSetting.getPkgState().setUsesLibraryInfos(usesLibraryInfos);
- // Use LinkedHashSet to preserve the order of files added to
- // usesLibraryFiles while eliminating duplicates.
- Set<String> usesLibraryFiles = new LinkedHashSet<>();
- for (SharedLibraryInfo libInfo : usesLibraryInfos) {
- addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib,
- changingLibSetting);
- }
- pkgSetting.setPkgStateLibraryFiles(usesLibraryFiles);
-
- // let's make sure we mark all static shared libraries as installed for the same users
- // that its dependent packages are installed for.
- int[] installedUsers = new int[allUsers.length];
- int installedUserCount = 0;
- for (int u = 0; u < allUsers.length; u++) {
- if (pkgSetting.getInstalled(allUsers[u])) {
- installedUsers[installedUserCount++] = allUsers[u];
- }
- }
- for (SharedLibraryInfo sharedLibraryInfo : usesLibraryInfos) {
- if (!sharedLibraryInfo.isStatic()) {
- continue;
- }
- final PackageSetting staticLibPkgSetting =
- getPackageSettingForMutation(sharedLibraryInfo.getPackageName());
- if (staticLibPkgSetting == null) {
- Slog.wtf(TAG, "Shared lib without setting: " + sharedLibraryInfo);
- continue;
- }
- for (int u = 0; u < installedUserCount; u++) {
- staticLibPkgSetting.setInstalled(true, installedUsers[u]);
- }
- }
- } else {
- pkgSetting.getPkgState().setUsesLibraryInfos(Collections.emptyList())
- .setUsesLibraryFiles(Collections.emptyList());
- }
- }
-
- private static boolean hasString(List<String> list, List<String> which) {
- if (list == null || which == null) {
- return false;
- }
- for (int i=list.size()-1; i>=0; i--) {
- for (int j=which.size()-1; j>=0; j--) {
- if (which.get(j).equals(list.get(i))) {
- return true;
- }
- }
- }
- return false;
- }
-
- @GuardedBy("mLock")
- ArrayList<AndroidPackage> updateAllSharedLibrariesLocked(
- @Nullable AndroidPackage updatedPkg, @Nullable PackageSetting updatedPkgSetting,
- Map<String, AndroidPackage> availablePackages) {
- ArrayList<AndroidPackage> resultList = null;
- // Set of all descendants of a library; used to eliminate cycles
- ArraySet<String> descendants = null;
- // The current list of packages that need updating
- List<Pair<AndroidPackage, PackageSetting>> needsUpdating = null;
- if (updatedPkg != null && updatedPkgSetting != null) {
- needsUpdating = new ArrayList<>(1);
- needsUpdating.add(Pair.create(updatedPkg, updatedPkgSetting));
- }
- do {
- final Pair<AndroidPackage, PackageSetting> changingPkgPair =
- (needsUpdating == null) ? null : needsUpdating.remove(0);
- final AndroidPackage changingPkg = changingPkgPair != null
- ? changingPkgPair.first : null;
- final PackageSetting changingPkgSetting = changingPkgPair != null
- ? changingPkgPair.second : null;
- for (int i = mPackages.size() - 1; i >= 0; --i) {
- final AndroidPackage pkg = mPackages.valueAt(i);
- final PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.getPackageName());
- if (changingPkg != null
- && !hasString(pkg.getUsesLibraries(), changingPkg.getLibraryNames())
- && !hasString(pkg.getUsesOptionalLibraries(), changingPkg.getLibraryNames())
- && !ArrayUtils.contains(pkg.getUsesStaticLibraries(),
- changingPkg.getStaticSharedLibName())
- && !ArrayUtils.contains(pkg.getUsesSdkLibraries(),
- changingPkg.getSdkLibName())) {
- continue;
- }
- if (resultList == null) {
- resultList = new ArrayList<>();
- }
- resultList.add(pkg);
- // if we're updating a shared library, all of its descendants must be updated
- if (changingPkg != null) {
- if (descendants == null) {
- descendants = new ArraySet<>();
- }
- if (!descendants.contains(pkg.getPackageName())) {
- descendants.add(pkg.getPackageName());
- needsUpdating.add(Pair.create(pkg, pkgSetting));
- }
- }
- try {
- updateSharedLibrariesLocked(pkg, pkgSetting, changingPkg,
- changingPkgSetting, availablePackages);
- } catch (PackageManagerException e) {
- // If a system app update or an app and a required lib missing we
- // delete the package and for updated system apps keep the data as
- // it is better for the user to reinstall than to be in an limbo
- // state. Also libs disappearing under an app should never happen
- // - just in case.
- if (!pkg.isSystem() || pkgSetting.getPkgState().isUpdatedSystemApp()) {
- final int flags = pkgSetting.getPkgState().isUpdatedSystemApp()
- ? PackageManager.DELETE_KEEP_DATA : 0;
- mDeletePackageHelper.deletePackageLIF(pkg.getPackageName(), null, true,
- mUserManager.getUserIds(), flags, null,
- true);
- }
- Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
- }
- }
- } while (needsUpdating != null && needsUpdating.size() > 0);
- return resultList;
- }
-
- @GuardedBy("mLock")
- private void addBuiltInSharedLibraryLocked(SystemConfig.SharedLibraryEntry entry) {
- if (nonStaticSharedLibExistsLocked(entry.name)) {
- return;
- }
-
- SharedLibraryInfo libraryInfo = new SharedLibraryInfo(entry.filename, null, null,
- entry.name, SharedLibraryInfo.VERSION_UNDEFINED,
- SharedLibraryInfo.TYPE_BUILTIN,
- new VersionedPackage(PLATFORM_PACKAGE_NAME, (long)0), null, null,
- entry.isNative);
-
- commitSharedLibraryInfoLocked(libraryInfo);
- }
-
- @GuardedBy("mLock")
- private boolean nonStaticSharedLibExistsLocked(String name) {
- return SharedLibraryHelper.sharedLibExists(name, SharedLibraryInfo.VERSION_UNDEFINED,
- mSharedLibraries);
- }
-
- @GuardedBy("mLock")
- void commitSharedLibraryInfoLocked(SharedLibraryInfo libraryInfo) {
- final String name = libraryInfo.getName();
- WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(name);
- if (versionedLib == null) {
- versionedLib = new WatchedLongSparseArray<>();
- mSharedLibraries.put(name, versionedLib);
- }
- final String declaringPackageName = libraryInfo.getDeclaringPackage().getPackageName();
- if (libraryInfo.getType() == SharedLibraryInfo.TYPE_STATIC) {
- mStaticLibsByDeclaringPackage.put(declaringPackageName, versionedLib);
- }
- versionedLib.put(libraryInfo.getLongVersion(), libraryInfo);
- }
-
@Override
public Property getProperty(String propertyName, String packageName, String className) {
Objects.requireNonNull(propertyName);
@@ -4909,8 +4570,8 @@
if (pus.isSuspended()) {
for (int i = 0; i < pus.getSuspendParams().size(); i++) {
final SuspendParams params = pus.getSuspendParams().valueAt(i);
- if (params != null && params.appExtras != null) {
- allExtras.putAll(params.appExtras);
+ if (params != null && params.getAppExtras() != null) {
+ allExtras.putAll(params.getAppExtras());
}
}
}
@@ -4983,9 +4644,9 @@
synchronized (mLock) {
for (String packageName : packagesToChange) {
final PackageSetting ps = mSettings.getPackageLPr(packageName);
- if (ps != null && ps.getSuspended(userId)) {
+ if (ps != null && ps.getUserStateOrDefault(userId).isSuspended()) {
ps.removeSuspension(suspendingPackagePredicate, userId);
- if (!ps.getSuspended(userId)) {
+ if (!ps.getUserStateOrDefault(userId).isSuspended()) {
unsuspendedPackages.add(ps.getPackageName());
unsuspendedUids.add(UserHandle.getUid(userId, ps.getAppId()));
}
@@ -7255,7 +6916,7 @@
*/
void checkPackageFrozen(String packageName) {
synchronized (mLock) {
- if (!mFrozenPackages.contains(packageName)) {
+ if (!mFrozenPackages.containsKey(packageName)) {
Slog.wtf(TAG, "Expected " + packageName + " to be frozen!", new Throwable());
}
}
@@ -7769,8 +7430,8 @@
if (userState.isSuspended()) {
for (int i = 0; i < userState.getSuspendParams().size(); i++) {
final SuspendParams params = userState.getSuspendParams().valueAt(i);
- if (params != null && params.launcherExtras != null) {
- allExtras.putAll(params.launcherExtras);
+ if (params != null && params.getLauncherExtras() != null) {
+ allExtras.putAll(params.getLauncherExtras());
}
}
}
@@ -7859,7 +7520,7 @@
}
final SuspendParams suspendParams = suspendParamsMap.get(suspendingPackage);
- return (suspendParams != null) ? suspendParams.dialogInfo : null;
+ return (suspendParams != null) ? suspendParams.getDialogInfo() : null;
}
@Override
@@ -8305,7 +7966,13 @@
@Override
public void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked,
@UserIdInt int userId) {
- PackageManagerService.this.forEachInstalledPackage(actionLocked, userId);
+ forEachInstalledPackage(true, actionLocked, userId);
+ }
+
+ @Override
+ public void forEachInstalledPackage(boolean locked,
+ @NonNull Consumer<AndroidPackage> action, int userId) {
+ PackageManagerService.this.forEachInstalledPackage(locked, action, userId);
}
@Override
@@ -8578,51 +8245,24 @@
@Override
public void withPackageSettingsSnapshot(
@NonNull Consumer<Function<String, PackageStateInternal>> block) {
- final Computer snapshot = snapshotComputer();
-
- // This method needs to either lock or not lock consistently throughout the method,
- // so if the live computer is returned, force a wrapping sync block.
- if (snapshot == mLiveComputer) {
- synchronized (mLock) {
- block.accept(snapshot::getPackageStateInternal);
- }
- } else {
- block.accept(snapshot::getPackageStateInternal);
- }
+ executeWithConsistentComputer(computer ->
+ block.accept(computer::getPackageStateInternal));
}
@Override
public <Output> Output withPackageSettingsSnapshotReturning(
@NonNull FunctionalUtils.ThrowingFunction<Function<String, PackageStateInternal>,
Output> block) {
- final Computer snapshot = snapshotComputer();
-
- // This method needs to either lock or not lock consistently throughout the method,
- // so if the live computer is returned, force a wrapping sync block.
- if (snapshot == mLiveComputer) {
- synchronized (mLock) {
- return block.apply(snapshot::getPackageStateInternal);
- }
- } else {
- return block.apply(snapshot::getPackageStateInternal);
- }
+ return executeWithConsistentComputerReturning(computer ->
+ block.apply(computer::getPackageStateInternal));
}
@Override
public <ExceptionType extends Exception> void withPackageSettingsSnapshotThrowing(
@NonNull FunctionalUtils.ThrowingCheckedConsumer<Function<String,
PackageStateInternal>, ExceptionType> block) throws ExceptionType {
- final Computer snapshot = snapshotComputer();
-
- // This method needs to either lock or not lock consistently throughout the method,
- // so if the live computer is returned, force a wrapping sync block.
- if (snapshot == mLiveComputer) {
- synchronized (mLock) {
- block.accept(snapshot::getPackageStateInternal);
- }
- } else {
- block.accept(snapshot::getPackageStateInternal);
- }
+ executeWithConsistentComputerThrowing(computer ->
+ block.accept(computer::getPackageStateInternal));
}
@Override
@@ -8632,17 +8272,9 @@
Function<String, PackageStateInternal>, ExceptionOne,
ExceptionTwo> block)
throws ExceptionOne, ExceptionTwo {
- final Computer snapshot = snapshotComputer();
-
- // This method needs to either lock or not lock consistently throughout the method,
- // so if the live computer is returned, force a wrapping sync block.
- if (snapshot == mLiveComputer) {
- synchronized (mLock) {
- block.accept(snapshot::getPackageStateInternal);
- }
- } else {
- block.accept(snapshot::getPackageStateInternal);
- }
+ executeWithConsistentComputerThrowing2(
+ (FunctionalUtils.ThrowingChecked2Consumer<Computer, ExceptionOne,
+ ExceptionTwo>) computer -> block.accept(computer::getPackageStateInternal));
}
@Override
@@ -8652,17 +8284,8 @@
Function<String, PackageStateInternal>, Output,
ExceptionType> block)
throws ExceptionType {
- final Computer snapshot = snapshotComputer();
-
- // This method needs to either lock or not lock consistently throughout the method,
- // so if the live computer is returned, force a wrapping sync block.
- if (snapshot == mLiveComputer) {
- synchronized (mLock) {
- return block.apply(snapshot::getPackageStateInternal);
- }
- } else {
- return block.apply(snapshot::getPackageStateInternal);
- }
+ return executeWithConsistentComputerReturningThrowing(computer ->
+ block.apply(computer::getPackageStateInternal));
}
@Override
@@ -8671,6 +8294,20 @@
PackageManagerService.this.mAppDataHelper.reconcileAppsData(userId, flags,
migrateAppsData);
}
+
+ @NonNull
+ @Override
+ public PackageStateMutator.InitialState recordInitialState() {
+ return PackageManagerService.this.recordInitialState();
+ }
+
+ @Nullable
+ @Override
+ public PackageStateMutator.Result commitPackageStateMutation(
+ @Nullable PackageStateMutator.InitialState state,
+ @NonNull Consumer<PackageStateMutator> consumer) {
+ return PackageManagerService.this.commitPackageStateMutation(state, consumer);
+ }
}
@Override
@@ -8713,7 +8350,15 @@
@Nullable
@GuardedBy("mLock")
PackageSetting getPackageSettingForMutation(String packageName) {
- return (PackageSetting) mComputer.getPackageStateInternal(packageName);
+ return mSettings.getPackageLPr(packageName);
+ }
+
+ // TODO: Remove
+ @Deprecated
+ @Nullable
+ @GuardedBy("mLock")
+ PackageSetting getDisabledPackageSettingForMutation(String packageName) {
+ return mSettings.getDisabledSystemPkgLPr(packageName);
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
@@ -8721,7 +8366,7 @@
PackageStateInternal getPackageStateInternal(String packageName) {
Computer computer = snapshotComputer();
if (computer == mLiveComputer) {
- synchronized (mLock) {
+ synchronized (mLiveComputerSyncLock) {
PackageSetting pkgSetting =
(PackageSetting) computer.getPackageStateInternal(packageName);
if (pkgSetting == null) {
@@ -8730,15 +8375,16 @@
return new PackageSetting(pkgSetting);
}
+ } else {
+ return computer.getPackageStateInternal(packageName);
}
- return computer.getPackageStateInternal(packageName);
}
@Nullable
PackageStateInternal getPackageStateInternal(String packageName, int callingUid) {
Computer computer = snapshotComputer();
if (computer == mLiveComputer) {
- synchronized (mLock) {
+ synchronized (mLiveComputerSyncLock) {
PackageSetting pkgSetting =
(PackageSetting) computer.getPackageStateInternal(packageName, callingUid);
if (pkgSetting == null) {
@@ -8747,8 +8393,9 @@
return new PackageSetting(pkgSetting);
}
+ } else {
+ return computer.getPackageStateInternal(packageName, callingUid);
}
- return computer.getPackageStateInternal(packageName, callingUid);
}
@Nullable
@@ -8756,7 +8403,7 @@
int callingUid, @UserIdInt int userId) {
Computer computer = snapshotComputer();
if (computer == mLiveComputer) {
- synchronized (mLock) {
+ synchronized (mLiveComputerSyncLock) {
PackageSetting pkgSetting =
(PackageSetting) filterPackageStateForInstalledAndFiltered(computer,
packageName, callingUid, userId);
@@ -8765,9 +8412,10 @@
}
return new PackageSetting(pkgSetting);
}
+ } else {
+ return filterPackageStateForInstalledAndFiltered(computer, packageName, callingUid,
+ userId);
}
-
- return filterPackageStateForInstalledAndFiltered(computer, packageName, callingUid, userId);
}
@Nullable
@@ -8795,16 +8443,8 @@
Computer computer = snapshotComputer();
if (computer == mLiveComputer) {
return new ArrayMap<>(computer.getPackageStates());
- }
- return computer.getPackageStates();
- }
-
- void forEachPackage(Consumer<AndroidPackage> actionLocked) {
- synchronized (mLock) {
- int numPackages = mPackages.size();
- for (int i = 0; i < numPackages; i++) {
- actionLocked.accept(mPackages.valueAt(i));
- }
+ } else {
+ return computer.getPackageStates();
}
}
@@ -8817,17 +8457,31 @@
}
}
- private void forEachPackageState(boolean locked, Consumer<PackageStateInternal> action) {
+ void forEachPackageState(boolean locked, Consumer<PackageStateInternal> action) {
if (locked) {
- forEachPackageSetting(action::accept);
+ synchronized (mLiveComputerSyncLock) {
+ forEachPackageState(mComputer.getPackageStates(), action);
+ }
} else {
Computer computer = snapshotComputer();
if (computer == mLiveComputer) {
- synchronized (mLock) {
+ synchronized (mLiveComputerSyncLock) {
forEachPackageState(computer.getPackageStates(), action);
- };
+ }
+ } else {
+ forEachPackageState(computer.getPackageStates(), action);
}
- forEachPackageState(computer.getPackageStates(), action);
+ }
+ }
+
+ void forEachPackage(Consumer<AndroidPackage> action) {
+ Computer computer = snapshotComputer();
+ if (computer == mLiveComputer) {
+ synchronized (mLiveComputerSyncLock) {
+ forEachPackage(computer.getPackageStates(), action);
+ }
+ } else {
+ forEachPackage(computer.getPackageStates(), action);
}
}
@@ -8841,21 +8495,106 @@
}
}
- void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked,
- @UserIdInt int userId) {
- synchronized (mLock) {
- int numPackages = mPackages.size();
- for (int i = 0; i < numPackages; i++) {
- AndroidPackage pkg = mPackages.valueAt(i);
- PackageSetting setting = mSettings.getPackageLPr(pkg.getPackageName());
- if (setting == null || !setting.getInstalled(userId)) {
- continue;
- }
- actionLocked.accept(pkg);
+ private void forEachPackage(
+ @NonNull ArrayMap<String, ? extends PackageStateInternal> packageStates,
+ @NonNull Consumer<AndroidPackage> consumer) {
+ int size = packageStates.size();
+ for (int index = 0; index < size; index++) {
+ PackageStateInternal packageState = packageStates.valueAt(index);
+ if (packageState.getPkg() != null) {
+ consumer.accept(packageState.getPkg());
}
}
}
+ void forEachInstalledPackage(boolean locked, @NonNull Consumer<AndroidPackage> action,
+ @UserIdInt int userId) {
+ Consumer<PackageStateInternal> actionWrapped = packageState -> {
+ if (packageState.getPkg() != null
+ && packageState.getUserStateOrDefault(userId).isInstalled()) {
+ action.accept(packageState.getPkg());
+ }
+ };
+ if (locked) {
+ synchronized (mLiveComputerSyncLock) {
+ forEachPackageState(mComputer.getPackageStates(), actionWrapped);
+ }
+ } else {
+ Computer computer = snapshotComputer();
+ if (computer == mLiveComputer) {
+ synchronized (mLiveComputerSyncLock) {
+ forEachPackageState(computer.getPackageStates(), actionWrapped);
+ }
+ } else {
+ forEachPackageState(computer.getPackageStates(), actionWrapped);
+ }
+ }
+ }
+
+ private void executeWithConsistentComputer(
+ @NonNull FunctionalUtils.ThrowingConsumer<Computer> consumer) {
+ Computer computer = snapshotComputer();
+ if (computer == mLiveComputer) {
+ synchronized (mLiveComputerSyncLock) {
+ consumer.accept(computer);
+ }
+ } else {
+ consumer.accept(computer);
+ }
+ }
+
+ private <T> T executeWithConsistentComputerReturning(
+ @NonNull FunctionalUtils.ThrowingFunction<Computer, T> function) {
+ Computer computer = snapshotComputer();
+ if (computer == mLiveComputer) {
+ synchronized (mLiveComputerSyncLock) {
+ return function.apply(computer);
+ }
+ } else {
+ return function.apply(computer);
+ }
+ }
+
+ private <ExceptionType extends Exception> void executeWithConsistentComputerThrowing(
+ @NonNull FunctionalUtils.ThrowingCheckedConsumer<Computer, ExceptionType> consumer)
+ throws ExceptionType {
+ Computer computer = snapshotComputer();
+ if (computer == mLiveComputer) {
+ synchronized (mLiveComputerSyncLock) {
+ consumer.accept(computer);
+ }
+ } else {
+ consumer.accept(computer);
+ }
+ }
+
+ private <ExceptionOne extends Exception, ExceptionTwo extends Exception> void
+ executeWithConsistentComputerThrowing2(
+ @NonNull FunctionalUtils.ThrowingChecked2Consumer<Computer, ExceptionOne,
+ ExceptionTwo> consumer) throws ExceptionOne, ExceptionTwo {
+ Computer computer = snapshotComputer();
+ if (computer == mLiveComputer) {
+ synchronized (mLiveComputerSyncLock) {
+ consumer.accept(computer);
+ }
+ } else {
+ consumer.accept(computer);
+ }
+ }
+
+ private <T, ExceptionType extends Exception> T executeWithConsistentComputerReturningThrowing(
+ @NonNull FunctionalUtils.ThrowingCheckedFunction<Computer, T, ExceptionType> function)
+ throws ExceptionType {
+ Computer computer = snapshotComputer();
+ if (computer == mLiveComputer) {
+ synchronized (mLiveComputerSyncLock) {
+ return function.apply(computer);
+ }
+ } else {
+ return function.apply(computer);
+ }
+ }
+
boolean isHistoricalPackageUsageAvailable() {
return mPackageUsage.isHistoricalPackageUsageAvailable();
}
@@ -9051,7 +8790,8 @@
enforceOwnerRights(packageName, Binder.getCallingUid());
final boolean changed;
synchronized (mLock) {
- changed = mSettings.getPackageLPr(packageName).setMimeGroup(mimeGroup, mimeTypes);
+ changed = mSettings.getPackageLPr(packageName).setMimeGroup(mimeGroup,
+ new ArraySet<>(mimeTypes));
}
if (changed) {
applyMimeGroupChanges(packageName, mimeGroup);
@@ -9510,7 +9250,8 @@
}
boolean isOverlayMutable(String packageName) {
- return mOverlayConfig.isMutable(packageName);
+ return (mOverlayConfig != null ? mOverlayConfig
+ : OverlayConfig.getSystemInstance()).isMutable(packageName);
}
@ScanFlags int getSystemPackageScanFlags(File codePath) {
@@ -9553,4 +9294,62 @@
return new Pair<>(rescanFlags, reparseFlags);
}
+
+ /**
+ * @see PackageManagerInternal#recordInitialState()
+ */
+ @NonNull
+ public PackageStateMutator.InitialState recordInitialState() {
+ return mPackageStateMutator.initialState(mChangedPackagesSequenceNumber);
+ }
+
+ /**
+ * @see PackageManagerInternal#commitPackageStateMutation(PackageStateMutator.InitialState,
+ * Consumer)
+ */
+ @NonNull
+ public PackageStateMutator.Result commitPackageStateMutation(
+ @Nullable PackageStateMutator.InitialState initialState,
+ @NonNull Consumer<PackageStateMutator> consumer) {
+ synchronized (mPackageStateWriteLock) {
+ final PackageStateMutator.Result result = mPackageStateMutator.generateResult(
+ initialState, mChangedPackagesSequenceNumber);
+ if (result != PackageStateMutator.Result.SUCCESS) {
+ return result;
+ }
+
+ consumer.accept(mPackageStateMutator);
+ onChanged();
+ }
+
+ return PackageStateMutator.Result.SUCCESS;
+ }
+
+ /**
+ * @see PackageManagerInternal#commitPackageStateMutation(PackageStateMutator.InitialState,
+ * Consumer)
+ */
+ @NonNull
+ public PackageStateMutator.Result commitPackageStateMutation(
+ @Nullable PackageStateMutator.InitialState initialState, @NonNull String packageName,
+ @NonNull Consumer<PackageStateWrite> consumer) {
+ synchronized (mPackageStateWriteLock) {
+ final PackageStateMutator.Result result = mPackageStateMutator.generateResult(
+ initialState, mChangedPackagesSequenceNumber);
+ if (result != PackageStateMutator.Result.SUCCESS) {
+ return result;
+ }
+
+ PackageStateWrite state = mPackageStateMutator.forPackage(packageName);
+ if (state == null) {
+ return PackageStateMutator.Result.SPECIFIC_PACKAGE_NULL;
+ } else {
+ consumer.accept(state);
+ }
+
+ onChanged();
+ }
+
+ return PackageStateMutator.Result.SUCCESS;
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
index d14cc1f..05bb01e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
@@ -137,6 +137,7 @@
private final Singleton<Handler> mHandlerProducer;
private final Singleton<BackgroundDexOptService> mBackgroundDexOptService;
private final Singleton<IBackupManager> mIBackupManager;
+ private final Singleton<SharedLibrariesImpl> mSharedLibrariesProducer;
PackageManagerServiceInjector(Context context, PackageManagerTracedLock lock,
Installer installer, Object installLock, PackageAbiHelper abiHelper,
@@ -173,7 +174,8 @@
ServiceProducer getLocalServiceProducer,
ServiceProducer getSystemServiceProducer,
Producer<BackgroundDexOptService> backgroundDexOptService,
- Producer<IBackupManager> iBackupManager) {
+ Producer<IBackupManager> iBackupManager,
+ Producer<SharedLibrariesImpl> sharedLibrariesProducer) {
mContext = context;
mLock = lock;
mInstaller = installer;
@@ -224,6 +226,7 @@
mHandlerProducer = new Singleton<>(handlerProducer);
mBackgroundDexOptService = new Singleton<>(backgroundDexOptService);
mIBackupManager = new Singleton<>(iBackupManager);
+ mSharedLibrariesProducer = new Singleton<>(sharedLibrariesProducer);
}
/**
@@ -392,6 +395,10 @@
return mIBackupManager.get(this, mPackageManager);
}
+ public SharedLibrariesImpl getSharedLibrariesImpl() {
+ return mSharedLibrariesProducer.get(this, mPackageManager);
+ }
+
/** Provides an abstraction to static access to system state. */
public interface SystemWrapper {
void disablePackageCaches();
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 923a133..0da57bc 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -395,14 +395,13 @@
return this;
}
- public boolean setMimeGroup(String mimeGroup, List<String> mimeTypes) {
+ public boolean setMimeGroup(String mimeGroup, ArraySet<String> newMimeTypes) {
Set<String> oldMimeTypes = mimeGroups == null ? null : mimeGroups.get(mimeGroup);
if (oldMimeTypes == null) {
throw new IllegalArgumentException("Unknown MIME group " + mimeGroup
+ " for package " + mName);
}
- ArraySet<String> newMimeTypes = new ArraySet<>(mimeTypes);
boolean hasChanges = !newMimeTypes.equals(oldMimeTypes);
mimeGroups.put(mimeGroup, newMimeTypes);
if (hasChanges) {
@@ -670,6 +669,15 @@
return state;
}
+ public PackageUserStateImpl getOrCreateUserState(@UserIdInt int userId) {
+ PackageUserStateImpl state = mUserStates.get(userId);
+ if (state == null) {
+ state = new PackageUserStateImpl();
+ mUserStates.put(userId, state);
+ }
+ return state;
+ }
+
@NonNull
public PackageUserStateInternal readUserState(int userId) {
PackageUserStateInternal state = mUserStates.get(userId);
@@ -832,7 +840,6 @@
}
final SuspendParams oldSuspendParams =
existingUserState.getSuspendParams().put(suspendingPackage, newSuspendParams);
- existingUserState.setSuspended(true);
onChanged();
return !Objects.equals(oldSuspendParams, newSuspendParams);
}
@@ -848,7 +855,6 @@
existingUserState.setSuspendParams(null);
}
}
- existingUserState.setSuspended((existingUserState.getSuspendParams() != null));
onChanged();
return wasModified;
}
@@ -866,7 +872,6 @@
existingUserState.setSuspendParams(null);
}
}
- existingUserState.setSuspended((existingUserState.getSuspendParams() != null));
onChanged();
}
@@ -889,7 +894,7 @@
}
void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
- boolean notLaunched, boolean hidden, int distractionFlags, boolean suspended,
+ boolean notLaunched, boolean hidden, int distractionFlags,
ArrayMap<String, SuspendParams> suspendParams, boolean instantApp,
boolean virtualPreload, String lastDisableAppCaller,
ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
@@ -904,7 +909,6 @@
.setNotLaunched(notLaunched)
.setHidden(hidden)
.setDistractionFlags(distractionFlags)
- .setSuspended(suspended)
.setLastDisableAppCaller(lastDisableAppCaller)
.setEnabledComponents(enabledComponents)
.setDisabledComponents(disabledComponents)
@@ -919,11 +923,9 @@
void setUserState(int userId, PackageUserStateInternal otherState) {
setUserState(userId, otherState.getCeDataInode(), otherState.getEnabledState(),
- otherState.isInstalled(),
- otherState.isStopped(), otherState.isNotLaunched(), otherState.isHidden(),
- otherState.getDistractionFlags(), otherState.isSuspended(),
- otherState.getSuspendParams(),
- otherState.isInstantApp(),
+ otherState.isInstalled(), otherState.isStopped(), otherState.isNotLaunched(),
+ otherState.isHidden(), otherState.getDistractionFlags(),
+ otherState.getSuspendParams(), otherState.isInstantApp(),
otherState.isVirtualPreload(), otherState.getLastDisableAppCaller(),
new ArraySet<>(otherState.getEnabledComponentsNoCopy()),
new ArraySet<>(otherState.getDisabledComponentsNoCopy()),
@@ -1553,10 +1555,10 @@
}
@DataClass.Generated(
- time = 1635870549646L,
+ time = 1636145878985L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/PackageSetting.java",
- inputSignatures = "private int sharedUserId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackage pkg\nprivate @android.annotation.Nullable com.android.server.pm.SharedUserSetting sharedUser\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate float mLoadingProgress\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate long mLastModifiedTime\nprivate long firstInstallTime\nprivate long lastUpdateTime\nprivate long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate int categoryOverride\nprivate boolean updateAvailable\nprivate boolean forceQueryableOverride\nprivate @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic com.android.server.pm.PackageSetting snapshot()\npublic void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic java.util.List<java.lang.String> getMimeGroup(java.lang.String)\nprivate java.util.Set<java.lang.String> getMimeGroupInternal(java.lang.String)\npublic boolean isSharedUser()\npublic com.android.server.pm.PackageSetting setAppId(int)\npublic com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic com.android.server.pm.PackageSetting setFirstInstallTime(long)\npublic com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic com.android.server.pm.PackageSetting setInstallerPackageName(java.lang.String)\npublic com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic boolean setMimeGroup(java.lang.String,java.util.List<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPkg(com.android.server.pm.parsing.pkg.AndroidPackage)\npublic com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic int getSharedUserIdInt()\npublic @java.lang.Override java.lang.String toString()\nprotected void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic void updateFrom(com.android.server.pm.PackageSetting)\n com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic boolean isPrivileged()\npublic boolean isOem()\npublic boolean isVendor()\npublic boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic boolean isSystemExt()\npublic boolean isOdm()\npublic boolean isSystem()\npublic android.content.pm.SigningDetails getSigningDetails()\npublic com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic void copyPackageSetting(com.android.server.pm.PackageSetting)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n void setEnabled(int,int,java.lang.String)\n int getEnabled(int)\n java.lang.String getLastDisabledAppCaller(int)\n void setInstalled(boolean,int)\n boolean getInstalled(int)\n int getInstallReason(int)\n void setInstallReason(int,int)\n int getUninstallReason(int)\n void setUninstallReason(int,int)\n boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getOverlayPathsForLibrary(int)\n boolean isAnyInstalled(int[])\n int[] queryInstalledUsers(int[],boolean)\n long getCeDataInode(int)\n void setCeDataInode(long,int)\n boolean getStopped(int)\n void setStopped(boolean,int)\n boolean getNotLaunched(int)\n void setNotLaunched(boolean,int)\n boolean getHidden(int)\n void setHidden(boolean,int)\n int getDistractionFlags(int)\n void setDistractionFlags(int,int)\n boolean getSuspended(int)\n boolean addOrUpdateSuspension(java.lang.String,android.content.pm.SuspendDialogInfo,android.os.PersistableBundle,android.os.PersistableBundle,int)\n boolean removeSuspension(java.lang.String,int)\n void removeSuspension(java.util.function.Predicate<java.lang.String>,int)\npublic boolean getInstantApp(int)\n void setInstantApp(boolean,int)\n boolean getVirtualPreload(int)\n void setVirtualPreload(boolean,int)\n void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,boolean,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String)\n void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n android.util.ArraySet<java.lang.String> getEnabledComponents(int)\n android.util.ArraySet<java.lang.String> getDisabledComponents(int)\n void setEnabledComponents(android.util.ArraySet<java.lang.String>,int)\n void setDisabledComponents(android.util.ArraySet<java.lang.String>,int)\n void setEnabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n void setDisabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n void addDisabledComponent(java.lang.String,int)\n void addEnabledComponent(java.lang.String,int)\n boolean enableComponentLPw(java.lang.String,int)\n boolean disableComponentLPw(java.lang.String,int)\n boolean restoreComponentLPw(java.lang.String,int)\n int getCurrentEnabledStateLPr(java.lang.String,int)\n void removeUser(int)\npublic int[] getNotInstalledUserIds()\n void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n void setHarmfulAppWarning(int,java.lang.String)\n java.lang.String getHarmfulAppWarning(int)\n com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic void resetOverrideComponentLabelIcon(int)\npublic void setSplashScreenTheme(int,java.lang.String)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic boolean isLoading()\npublic com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackageApi getAndroidPackage()\npublic @android.annotation.Nullable @java.lang.Override java.lang.Integer getSharedUserId()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<android.content.pm.SharedLibraryInfo> getUsesLibraryInfos()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic com.android.server.pm.PackageSetting setSharedUser(com.android.server.pm.SharedUserSetting)\npublic com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
+ inputSignatures = "private int sharedUserId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackage pkg\nprivate @android.annotation.Nullable com.android.server.pm.SharedUserSetting sharedUser\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate float mLoadingProgress\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate long mLastModifiedTime\nprivate long firstInstallTime\nprivate long lastUpdateTime\nprivate long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate int categoryOverride\nprivate boolean updateAvailable\nprivate boolean forceQueryableOverride\nprivate @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic com.android.server.pm.PackageSetting snapshot()\npublic void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic boolean isSharedUser()\npublic com.android.server.pm.PackageSetting setAppId(int)\npublic com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic com.android.server.pm.PackageSetting setFirstInstallTime(long)\npublic com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic com.android.server.pm.PackageSetting setInstallerPackageName(java.lang.String)\npublic com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic boolean setMimeGroup(java.lang.String,java.util.List<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPkg(com.android.server.pm.parsing.pkg.AndroidPackage)\npublic com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic int getSharedUserIdInt()\npublic @java.lang.Override java.lang.String toString()\nprotected void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic void updateFrom(com.android.server.pm.PackageSetting)\n com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic boolean isPrivileged()\npublic boolean isOem()\npublic boolean isVendor()\npublic boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic boolean isSystemExt()\npublic boolean isOdm()\npublic boolean isSystem()\npublic android.content.pm.SigningDetails getSigningDetails()\npublic com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic void copyPackageSetting(com.android.server.pm.PackageSetting)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n void setEnabled(int,int,java.lang.String)\n int getEnabled(int)\n java.lang.String getLastDisabledAppCaller(int)\n void setInstalled(boolean,int)\n boolean getInstalled(int)\n int getInstallReason(int)\n void setInstallReason(int,int)\n int getUninstallReason(int)\n void setUninstallReason(int,int)\n boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getOverlayPathsForLibrary(int)\n boolean isAnyInstalled(int[])\n int[] queryInstalledUsers(int[],boolean)\n long getCeDataInode(int)\n void setCeDataInode(long,int)\n boolean getStopped(int)\n void setStopped(boolean,int)\n boolean getNotLaunched(int)\n void setNotLaunched(boolean,int)\n boolean getHidden(int)\n void setHidden(boolean,int)\n int getDistractionFlags(int)\n void setDistractionFlags(int,int)\npublic boolean getInstantApp(int)\n void setInstantApp(boolean,int)\n boolean getVirtualPreload(int)\n void setVirtualPreload(boolean,int)\n void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String)\n void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n android.util.ArraySet<java.lang.String> getEnabledComponents(int)\n android.util.ArraySet<java.lang.String> getDisabledComponents(int)\n void setEnabledComponents(android.util.ArraySet<java.lang.String>,int)\n void setDisabledComponents(android.util.ArraySet<java.lang.String>,int)\n void setEnabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n void setDisabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n void addDisabledComponent(java.lang.String,int)\n void addEnabledComponent(java.lang.String,int)\n boolean enableComponentLPw(java.lang.String,int)\n boolean disableComponentLPw(java.lang.String,int)\n boolean restoreComponentLPw(java.lang.String,int)\n int getCurrentEnabledStateLPr(java.lang.String,int)\n void removeUser(int)\npublic int[] getNotInstalledUserIds()\n void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n void setHarmfulAppWarning(int,java.lang.String)\n java.lang.String getHarmfulAppWarning(int)\n com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic void resetOverrideComponentLabelIcon(int)\npublic void setSplashScreenTheme(int,java.lang.String)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic boolean isLoading()\npublic com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackageApi getAndroidPackage()\npublic @android.annotation.Nullable @java.lang.Override java.lang.Integer getSharedUserId()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<android.content.pm.SharedLibraryInfo> getUsesLibraryInfos()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic com.android.server.pm.PackageSetting setSharedUser(com.android.server.pm.SharedUserSetting)\npublic com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 749495c..d60d019 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -29,10 +29,7 @@
import android.annotation.NonNull;
import android.content.pm.PackageManager;
-import android.content.pm.SharedLibraryInfo;
-import android.content.pm.VersionedPackage;
import android.content.pm.parsing.component.ParsedInstrumentation;
-import android.os.Process;
import android.os.UserHandle;
import android.os.incremental.IncrementalManager;
import android.util.Log;
@@ -46,7 +43,6 @@
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.utils.WatchedLongSparseArray;
import java.io.File;
import java.util.Collections;
@@ -62,6 +58,7 @@
private final Installer mInstaller;
private final UserManagerInternal mUserManagerInternal;
private final PermissionManagerServiceInternal mPermissionManager;
+ private final SharedLibrariesImpl mSharedLibraries;
private final AppDataHelper mAppDataHelper;
// TODO(b/198166813): remove PMS dependency
@@ -71,6 +68,7 @@
mInstaller = mPm.mInjector.getInstaller();
mUserManagerInternal = mPm.mInjector.getUserManagerInternal();
mPermissionManager = mPm.mInjector.getPermissionManagerServiceInternal();
+ mSharedLibraries = mPm.mInjector.getSharedLibrariesImpl();
mAppDataHelper = appDataHelper;
}
@@ -174,7 +172,7 @@
final int libraryNamesSize = pkg.getLibraryNames().size();
for (i = 0; i < libraryNamesSize; i++) {
String name = pkg.getLibraryNames().get(i);
- if (removeSharedLibraryLPw(name, 0)) {
+ if (mSharedLibraries.removeSharedLibraryLPw(name, 0)) {
if (DEBUG_REMOVE && chatty) {
if (r == null) {
r = new StringBuilder(256);
@@ -191,7 +189,8 @@
// Any package can hold SDK or static shared libraries.
if (pkg.getSdkLibName() != null) {
- if (removeSharedLibraryLPw(pkg.getSdkLibName(), pkg.getSdkLibVersionMajor())) {
+ if (mSharedLibraries.removeSharedLibraryLPw(
+ pkg.getSdkLibName(), pkg.getSdkLibVersionMajor())) {
if (DEBUG_REMOVE && chatty) {
if (r == null) {
r = new StringBuilder(256);
@@ -203,7 +202,7 @@
}
}
if (pkg.getStaticSharedLibName() != null) {
- if (removeSharedLibraryLPw(pkg.getStaticSharedLibName(),
+ if (mSharedLibraries.removeSharedLibraryLPw(pkg.getStaticSharedLibName(),
pkg.getStaticSharedLibVersion())) {
if (DEBUG_REMOVE && chatty) {
if (r == null) {
@@ -221,44 +220,6 @@
}
}
- private boolean removeSharedLibraryLPw(String name, long version) {
- WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mPm.mSharedLibraries.get(name);
- if (versionedLib == null) {
- return false;
- }
- final int libIdx = versionedLib.indexOfKey(version);
- if (libIdx < 0) {
- return false;
- }
- SharedLibraryInfo libraryInfo = versionedLib.valueAt(libIdx);
-
- // Remove the shared library overlays from its dependent packages.
- for (int currentUserId : UserManagerService.getInstance().getUserIds()) {
- final List<VersionedPackage> dependents = mPm.getPackagesUsingSharedLibrary(
- libraryInfo, 0, Process.SYSTEM_UID, currentUserId);
- if (dependents == null) {
- continue;
- }
- for (VersionedPackage dependentPackage : dependents) {
- final PackageSetting ps = mPm.mSettings.getPackageLPr(
- dependentPackage.getPackageName());
- if (ps != null) {
- ps.setOverlayPathsForLibrary(libraryInfo.getName(), null, currentUserId);
- }
- }
- }
-
- versionedLib.remove(version);
- if (versionedLib.size() <= 0) {
- mPm.mSharedLibraries.remove(name);
- if (libraryInfo.getType() == SharedLibraryInfo.TYPE_STATIC) {
- mPm.mStaticLibsByDeclaringPackage.remove(libraryInfo.getDeclaringPackage()
- .getPackageName());
- }
- }
- return true;
- }
-
/*
* This method deletes the package from internal data structures. If the DELETE_KEEP_DATA
* flag is not set, the data directory is removed as well.
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index ed85ff9..4345d51 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -22,6 +22,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.permission.LegacyPermissionState;
+import com.android.server.pm.pkg.mutate.PackageStateMutator;
import com.android.server.utils.Snappable;
import com.android.server.utils.Watchable;
import com.android.server.utils.WatchableImpl;
@@ -88,6 +89,7 @@
* Notify listeners that this object has changed.
*/
protected void onChanged() {
+ PackageStateMutator.onPackageStateChanged();
dispatchChange(this);
}
@@ -122,7 +124,7 @@
return mLegacyPermissionsState;
}
- SettingBase setFlags(int pkgFlags) {
+ public SettingBase setFlags(int pkgFlags) {
this.mPkgFlags = pkgFlags
& (ApplicationInfo.FLAG_SYSTEM
| ApplicationInfo.FLAG_EXTERNAL_STORAGE
@@ -131,7 +133,7 @@
return this;
}
- SettingBase setPrivateFlags(int pkgPrivateFlags) {
+ public SettingBase setPrivateFlags(int pkgPrivateFlags) {
this.mPkgPrivateFlags = pkgPrivateFlags
& (ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
| ApplicationInfo.PRIVATE_FLAG_OEM
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index b1ce6a2..6c47eb0 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -114,6 +114,7 @@
import com.android.server.pm.permission.LegacyPermissionSettings;
import com.android.server.pm.permission.LegacyPermissionState;
import com.android.server.pm.permission.LegacyPermissionState.PermissionState;
+import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageUserState;
import com.android.server.pm.pkg.PackageUserStateInternal;
import com.android.server.pm.pkg.SuspendParams;
@@ -162,6 +163,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
+import java.util.function.Consumer;
/**
* Holds information about dynamic settings.
@@ -257,7 +259,7 @@
public static final int SIGNATURE_MALFORMED_RECOVER = 3;
}
- private static final boolean DEBUG_STOPPED = false;
+ static final boolean DEBUG_STOPPED = false;
private static final boolean DEBUG_MU = false;
private static final boolean DEBUG_KERNEL = false;
private static final boolean DEBUG_PARSER = false;
@@ -625,7 +627,15 @@
mOtherAppIds = new WatchedSparseArray<>();
mPermissions = new LegacyPermissionSettings(lock);
mRuntimePermissionsPersistence = new RuntimePermissionPersistence(
- runtimePermissionsPersistence);
+ runtimePermissionsPersistence, new Consumer<Integer>() {
+ @Override
+ public void accept(Integer userId) {
+ synchronized (mLock) {
+ mRuntimePermissionsPersistence.writeStateForUserSync(userId,
+ mPermissionDataProvider, mPackages, mSharedUsers);
+ }
+ }
+ });
mPermissionDataProvider = permissionDataProvider;
mSystemDir = new File(dataDir, "system");
@@ -989,7 +999,6 @@
true /*notLaunched*/,
false /*hidden*/,
0 /*distractionFlags*/,
- false /*suspended*/,
null /*suspendParams*/,
instantApp,
virtualPreload,
@@ -1423,7 +1432,7 @@
void writeAllRuntimePermissionsLPr() {
for (int userId : UserManagerService.getInstance().getUserIds()) {
- mRuntimePermissionsPersistence.writeStateForUserAsyncLPr(userId);
+ mRuntimePermissionsPersistence.writeStateForUserAsync(userId);
}
}
@@ -1432,15 +1441,15 @@
}
void updateRuntimePermissionsFingerprintLPr(@UserIdInt int userId) {
- mRuntimePermissionsPersistence.updateRuntimePermissionsFingerprintLPr(userId);
+ mRuntimePermissionsPersistence.updateRuntimePermissionsFingerprint(userId);
}
int getDefaultRuntimePermissionsVersionLPr(int userId) {
- return mRuntimePermissionsPersistence.getVersionLPr(userId);
+ return mRuntimePermissionsPersistence.getVersion(userId);
}
void setDefaultRuntimePermissionsVersionLPr(int version, int userId) {
- mRuntimePermissionsPersistence.setVersionLPr(version, userId);
+ mRuntimePermissionsPersistence.setVersion(version, userId);
}
void setPermissionControllerVersion(long version) {
@@ -1646,7 +1655,6 @@
false /*notLaunched*/,
false /*hidden*/,
0 /*distractionFlags*/,
- false /*suspended*/,
null /*suspendParams*/,
false /*instantApp*/,
false /*virtualPreload*/,
@@ -1816,10 +1824,9 @@
setBlockUninstallLPw(userId, name, true);
}
ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
- hidden, distractionFlags, suspended, suspendParamsMap,
- instantApp, virtualPreload, enabledCaller, enabledComponents,
- disabledComponents, installReason, uninstallReason, harmfulAppWarning,
- splashScreenTheme);
+ hidden, distractionFlags, suspendParamsMap, instantApp, virtualPreload,
+ enabledCaller, enabledComponents, disabledComponents, installReason,
+ uninstallReason, harmfulAppWarning, splashScreenTheme);
mDomainVerificationManager.setLegacyUserState(name, userId, verifState);
} else if (tagName.equals("preferred-activities")) {
@@ -3100,7 +3107,8 @@
}
for (UserInfo user : users) {
- mRuntimePermissionsPersistence.readStateForUserSyncLPr(user.id);
+ mRuntimePermissionsPersistence.readStateForUserSync(user.id, getInternalVersion(),
+ mPackages, mSharedUsers, getUserRuntimePermissionsFile(user.id));
}
/*
@@ -3124,7 +3132,8 @@
}
void readPermissionStateForUserSyncLPr(@UserIdInt int userId) {
- mRuntimePermissionsPersistence.readStateForUserSyncLPr(userId);
+ mRuntimePermissionsPersistence.readStateForUserSync(userId, getInternalVersion(),
+ mPackages, mSharedUsers, getUserRuntimePermissionsFile(userId));
}
void applyDefaultPreferredAppsLPw(int userId) {
@@ -4120,7 +4129,7 @@
file.delete();
removeCrossProfileIntentFiltersLPw(userId);
- mRuntimePermissionsPersistence.onUserRemovedLPw(userId);
+ mRuntimePermissionsPersistence.onUserRemoved(userId);
mDomainVerificationManager.clearUser(userId);
writePackageListLPr();
@@ -4485,24 +4494,25 @@
}
}
for (UserInfo user : users) {
+ final PackageUserStateInternal userState = ps.getUserStateOrDefault(user.id);
pw.print(checkinTag);
pw.print("-");
pw.print("usr");
pw.print(",");
pw.print(user.id);
pw.print(",");
- pw.print(ps.getInstalled(user.id) ? "I" : "i");
- pw.print(ps.getHidden(user.id) ? "B" : "b");
- pw.print(ps.getSuspended(user.id) ? "SU" : "su");
- pw.print(ps.getStopped(user.id) ? "S" : "s");
- pw.print(ps.getNotLaunched(user.id) ? "l" : "L");
- pw.print(ps.getInstantApp(user.id) ? "IA" : "ia");
- pw.print(ps.getVirtualPreload(user.id) ? "VPI" : "vpi");
- String harmfulAppWarning = ps.getHarmfulAppWarning(user.id);
+ pw.print(userState.isInstalled() ? "I" : "i");
+ pw.print(userState.isHidden() ? "B" : "b");
+ pw.print(userState.isSuspended() ? "SU" : "su");
+ pw.print(userState.isStopped() ? "S" : "s");
+ pw.print(userState.isNotLaunched() ? "l" : "L");
+ pw.print(userState.isInstantApp() ? "IA" : "ia");
+ pw.print(userState.isVirtualPreload() ? "VPI" : "vpi");
+ String harmfulAppWarning = userState.getHarmfulAppWarning();
pw.print(harmfulAppWarning != null ? "HA" : "ha");
pw.print(",");
- pw.print(ps.getEnabled(user.id));
- String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id);
+ pw.print(userState.getEnabledState());
+ String lastDisabledAppCaller = userState.getLastDisableAppCaller();
pw.print(",");
pw.print(lastDisabledAppCaller != null ? lastDisabledAppCaller : "?");
pw.print(",");
@@ -4819,48 +4829,48 @@
}
for (UserInfo user : users) {
+ final PackageUserStateInternal userState = ps.getUserStateOrDefault(user.id);
pw.print(prefix); pw.print(" User "); pw.print(user.id); pw.print(": ");
pw.print("ceDataInode=");
- pw.print(ps.getCeDataInode(user.id));
+ pw.print(userState.getCeDataInode());
pw.print(" installed=");
- pw.print(ps.getInstalled(user.id));
+ pw.print(userState.isInstalled());
pw.print(" hidden=");
- pw.print(ps.getHidden(user.id));
+ pw.print(userState.isHidden());
pw.print(" suspended=");
- pw.print(ps.getSuspended(user.id));
+ pw.print(userState.isSuspended());
pw.print(" distractionFlags=");
- pw.print(ps.getDistractionFlags(user.id));
+ pw.print(userState.getDistractionFlags());
pw.print(" stopped=");
- pw.print(ps.getStopped(user.id));
+ pw.print(userState.isStopped());
pw.print(" notLaunched=");
- pw.print(ps.getNotLaunched(user.id));
+ pw.print(userState.isNotLaunched());
pw.print(" enabled=");
- pw.print(ps.getEnabled(user.id));
+ pw.print(userState.getEnabledState());
pw.print(" instant=");
- pw.print(ps.getInstantApp(user.id));
+ pw.print(userState.isInstantApp());
pw.print(" virtual=");
- pw.print(ps.getVirtualPreload(user.id));
+ pw.println(userState.isVirtualPreload());
pw.print(" installReason=");
- pw.println(ps.getInstallReason(user.id));
+ pw.println(userState.getInstallReason());
- if (ps.getSuspended(user.id)) {
+ if (userState.isSuspended()) {
pw.print(prefix);
pw.println(" Suspend params:");
- final PackageUserStateInternal pus = ps.readUserState(user.id);
- for (int i = 0; i < pus.getSuspendParams().size(); i++) {
+ for (int i = 0; i < userState.getSuspendParams().size(); i++) {
pw.print(prefix);
pw.print(" suspendingPackage=");
- pw.print(pus.getSuspendParams().keyAt(i));
- final SuspendParams params = pus.getSuspendParams().valueAt(i);
+ pw.print(userState.getSuspendParams().keyAt(i));
+ final SuspendParams params = userState.getSuspendParams().valueAt(i);
if (params != null) {
pw.print(" dialogInfo=");
- pw.print(params.dialogInfo);
+ pw.print(params.getDialogInfo());
}
pw.println();
}
}
- final OverlayPaths overlayPaths = ps.getOverlayPaths(user.id);
+ final OverlayPaths overlayPaths = userState.getOverlayPaths();
if (overlayPaths != null) {
if (!overlayPaths.getOverlayPaths().isEmpty()) {
pw.print(prefix);
@@ -4883,7 +4893,7 @@
}
final Map<String, OverlayPaths> sharedLibraryOverlayPaths =
- ps.getOverlayPathsForLibrary(user.id);
+ userState.getSharedLibraryOverlayPaths();
if (sharedLibraryOverlayPaths != null) {
for (Map.Entry<String, OverlayPaths> libOverlayPaths :
sharedLibraryOverlayPaths.entrySet()) {
@@ -4916,7 +4926,7 @@
}
}
- String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id);
+ String lastDisabledAppCaller = userState.getLastDisableAppCaller();
if (lastDisabledAppCaller != null) {
pw.print(prefix); pw.print(" lastDisabledCaller: ");
pw.println(lastDisabledAppCaller);
@@ -4929,21 +4939,21 @@
.getPermissionStates(user.id), dumpAll);
}
- String harmfulAppWarning = ps.getHarmfulAppWarning(user.id);
+ String harmfulAppWarning = userState.getHarmfulAppWarning();
if (harmfulAppWarning != null) {
pw.print(prefix); pw.print(" harmfulAppWarning: ");
pw.println(harmfulAppWarning);
}
if (permissionNames == null) {
- ArraySet<String> cmp = ps.getDisabledComponents(user.id);
+ Set<String> cmp = userState.getDisabledComponents();
if (cmp != null && cmp.size() > 0) {
pw.print(prefix); pw.println(" disabledComponents:");
for (String s : cmp) {
pw.print(prefix); pw.print(" "); pw.println(s);
}
}
- cmp = ps.getEnabledComponents(user.id);
+ cmp = userState.getEnabledComponents();
if (cmp != null && cmp.size() > 0) {
pw.print(prefix); pw.println(" enabledComponents:");
for (String s : cmp) {
@@ -5291,9 +5301,10 @@
public void writePermissionStateForUserLPr(int userId, boolean sync) {
if (sync) {
- mRuntimePermissionsPersistence.writeStateForUserSyncLPr(userId);
+ mRuntimePermissionsPersistence.writeStateForUserSync(userId, mPermissionDataProvider,
+ mPackages, mSharedUsers);
} else {
- mRuntimePermissionsPersistence.writeStateForUserAsyncLPr(userId);
+ mRuntimePermissionsPersistence.writeStateForUserAsync(userId);
}
}
@@ -5368,7 +5379,7 @@
}
}
- private final class RuntimePermissionPersistence {
+ private static final class RuntimePermissionPersistence {
private static final long WRITE_PERMISSIONS_DELAY_MILLIS = 200;
private static final long MAX_WRITE_PERMISSIONS_DELAY_MILLIS = 2000;
@@ -5381,6 +5392,8 @@
private final Handler mHandler = new MyHandler();
+ private final Object mLock = new Object();
+
@GuardedBy("mLock")
private final SparseBooleanArray mWriteScheduled = new SparseBooleanArray();
@@ -5400,45 +5413,58 @@
// The mapping keys are user ids.
private final SparseBooleanArray mPermissionUpgradeNeeded = new SparseBooleanArray();
- public RuntimePermissionPersistence(RuntimePermissionsPersistence persistence) {
+ // This is a hack to allow this class to invoke a write using Settings's data structures,
+ // to facilitate moving to a finer scoped lock without a significant refactor.
+ private final Consumer<Integer> mInvokeWriteUserStateAsyncCallback;
+
+ public RuntimePermissionPersistence(RuntimePermissionsPersistence persistence,
+ Consumer<Integer> invokeWriteUserStateAsyncCallback) {
mPersistence = persistence;
+ mInvokeWriteUserStateAsyncCallback = invokeWriteUserStateAsyncCallback;
}
- @GuardedBy("Settings.this.mLock")
- int getVersionLPr(int userId) {
- return mVersions.get(userId, INITIAL_VERSION);
- }
-
- @GuardedBy("Settings.this.mLock")
- void setVersionLPr(int version, int userId) {
- mVersions.put(userId, version);
- writeStateForUserAsyncLPr(userId);
- }
-
- @GuardedBy("Settings.this.mLock")
- public boolean isPermissionUpgradeNeeded(int userId) {
- return mPermissionUpgradeNeeded.get(userId, true);
- }
-
- @GuardedBy("Settings.this.mLock")
- public void updateRuntimePermissionsFingerprintLPr(@UserIdInt int userId) {
- if (mExtendedFingerprint == null) {
- throw new RuntimeException("The version of the permission controller hasn't been "
- + "set before trying to update the fingerprint.");
+ int getVersion(int userId) {
+ synchronized (mLock) {
+ return mVersions.get(userId, INITIAL_VERSION);
}
- mFingerprints.put(userId, mExtendedFingerprint);
- writeStateForUserAsyncLPr(userId);
+ }
+
+ void setVersion(int version, int userId) {
+ synchronized (mLock) {
+ mVersions.put(userId, version);
+ writeStateForUserAsync(userId);
+ }
+ }
+
+ public boolean isPermissionUpgradeNeeded(int userId) {
+ synchronized (mLock) {
+ return mPermissionUpgradeNeeded.get(userId, true);
+ }
+ }
+
+ public void updateRuntimePermissionsFingerprint(@UserIdInt int userId) {
+ synchronized (mLock) {
+ if (mExtendedFingerprint == null) {
+ throw new RuntimeException(
+ "The version of the permission controller hasn't been "
+ + "set before trying to update the fingerprint.");
+ }
+ mFingerprints.put(userId, mExtendedFingerprint);
+ writeStateForUserAsync(userId);
+ }
}
public void setPermissionControllerVersion(long version) {
- int numUser = mFingerprints.size();
- mExtendedFingerprint = getExtendedFingerprint(version);
+ synchronized (mLock) {
+ int numUser = mFingerprints.size();
+ mExtendedFingerprint = getExtendedFingerprint(version);
- for (int i = 0; i < numUser; i++) {
- int userId = mFingerprints.keyAt(i);
- String fingerprint = mFingerprints.valueAt(i);
- mPermissionUpgradeNeeded.put(userId,
- !TextUtils.equals(mExtendedFingerprint, fingerprint));
+ for (int i = 0; i < numUser; i++) {
+ int userId = mFingerprints.keyAt(i);
+ String fingerprint = mFingerprints.valueAt(i);
+ mPermissionUpgradeNeeded.put(userId,
+ !TextUtils.equals(mExtendedFingerprint, fingerprint));
+ }
}
}
@@ -5446,84 +5472,92 @@
return PackagePartitions.FINGERPRINT + "?pc_version=" + version;
}
- public void writeStateForUserAsyncLPr(int userId) {
- final long currentTimeMillis = SystemClock.uptimeMillis();
+ public void writeStateForUserAsync(int userId) {
+ synchronized (mLock) {
+ final long currentTimeMillis = SystemClock.uptimeMillis();
- if (mWriteScheduled.get(userId)) {
- mHandler.removeMessages(userId);
+ if (mWriteScheduled.get(userId)) {
+ mHandler.removeMessages(userId);
- // If enough time passed, write without holding off anymore.
- final long lastNotWrittenMutationTimeMillis = mLastNotWrittenMutationTimesMillis
- .get(userId);
- final long timeSinceLastNotWrittenMutationMillis = currentTimeMillis
- - lastNotWrittenMutationTimeMillis;
- if (timeSinceLastNotWrittenMutationMillis >= MAX_WRITE_PERMISSIONS_DELAY_MILLIS) {
- mHandler.obtainMessage(userId).sendToTarget();
- return;
+ // If enough time passed, write without holding off anymore.
+ final long lastNotWrittenMutationTimeMillis = mLastNotWrittenMutationTimesMillis
+ .get(userId);
+ final long timeSinceLastNotWrittenMutationMillis = currentTimeMillis
+ - lastNotWrittenMutationTimeMillis;
+ if (timeSinceLastNotWrittenMutationMillis
+ >= MAX_WRITE_PERMISSIONS_DELAY_MILLIS) {
+ mHandler.obtainMessage(userId).sendToTarget();
+ return;
+ }
+
+ // Hold off a bit more as settings are frequently changing.
+ final long maxDelayMillis = Math.max(lastNotWrittenMutationTimeMillis
+ + MAX_WRITE_PERMISSIONS_DELAY_MILLIS - currentTimeMillis, 0);
+ final long writeDelayMillis = Math.min(WRITE_PERMISSIONS_DELAY_MILLIS,
+ maxDelayMillis);
+
+ Message message = mHandler.obtainMessage(userId);
+ mHandler.sendMessageDelayed(message, writeDelayMillis);
+ } else {
+ mLastNotWrittenMutationTimesMillis.put(userId, currentTimeMillis);
+ Message message = mHandler.obtainMessage(userId);
+ mHandler.sendMessageDelayed(message, WRITE_PERMISSIONS_DELAY_MILLIS);
+ mWriteScheduled.put(userId, true);
}
-
- // Hold off a bit more as settings are frequently changing.
- final long maxDelayMillis = Math.max(lastNotWrittenMutationTimeMillis
- + MAX_WRITE_PERMISSIONS_DELAY_MILLIS - currentTimeMillis, 0);
- final long writeDelayMillis = Math.min(WRITE_PERMISSIONS_DELAY_MILLIS,
- maxDelayMillis);
-
- Message message = mHandler.obtainMessage(userId);
- mHandler.sendMessageDelayed(message, writeDelayMillis);
- } else {
- mLastNotWrittenMutationTimesMillis.put(userId, currentTimeMillis);
- Message message = mHandler.obtainMessage(userId);
- mHandler.sendMessageDelayed(message, WRITE_PERMISSIONS_DELAY_MILLIS);
- mWriteScheduled.put(userId, true);
}
}
- public void writeStateForUserSyncLPr(int userId) {
- mHandler.removeMessages(userId);
- mWriteScheduled.delete(userId);
+ public void writeStateForUserSync(int userId, @NonNull LegacyPermissionDataProvider
+ legacyPermissionDataProvider,
+ @NonNull WatchedArrayMap<String, ? extends PackageStateInternal> packageStates,
+ @NonNull WatchedArrayMap<String, SharedUserSetting> sharedUsers) {
+ synchronized (mLock) {
+ mHandler.removeMessages(userId);
+ mWriteScheduled.delete(userId);
- mPermissionDataProvider.writeLegacyPermissionStateTEMP();
+ legacyPermissionDataProvider.writeLegacyPermissionStateTEMP();
- int version = mVersions.get(userId, INITIAL_VERSION);
+ int version = mVersions.get(userId, INITIAL_VERSION);
- String fingerprint = mFingerprints.get(userId);
+ String fingerprint = mFingerprints.get(userId);
- Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
- new ArrayMap<>();
- int packagesSize = mPackages.size();
- for (int i = 0; i < packagesSize; i++) {
- String packageName = mPackages.keyAt(i);
- PackageSetting packageSetting = mPackages.valueAt(i);
- if (packageSetting.getSharedUser() == null) {
+ Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
+ new ArrayMap<>();
+ int packagesSize = packageStates.size();
+ for (int i = 0; i < packagesSize; i++) {
+ String packageName = packageStates.keyAt(i);
+ PackageStateInternal packageState = packageStates.valueAt(i);
+ if (packageState.getSharedUser() == null) {
+ List<RuntimePermissionsState.PermissionState> permissions =
+ getPermissionsFromPermissionsState(
+ packageState.getLegacyPermissionState(), userId);
+ if (permissions.isEmpty() && !packageState.isInstallPermissionsFixed()) {
+ // Storing an empty state means the package is known to the system and
+ // its install permissions have been granted and fixed. If this is not
+ // the case, we should not store anything.
+ continue;
+ }
+ packagePermissions.put(packageName, permissions);
+ }
+ }
+
+ Map<String, List<RuntimePermissionsState.PermissionState>> sharedUserPermissions =
+ new ArrayMap<>();
+ final int sharedUsersSize = sharedUsers.size();
+ for (int i = 0; i < sharedUsersSize; i++) {
+ String sharedUserName = sharedUsers.keyAt(i);
+ SharedUserSetting sharedUserSetting = sharedUsers.valueAt(i);
List<RuntimePermissionsState.PermissionState> permissions =
getPermissionsFromPermissionsState(
- packageSetting.getLegacyPermissionState(), userId);
- if (permissions.isEmpty() && !packageSetting.isInstallPermissionsFixed()) {
- // Storing an empty state means the package is known to the system and its
- // install permissions have been granted and fixed. If this is not the case,
- // we should not store anything.
- continue;
- }
- packagePermissions.put(packageName, permissions);
+ sharedUserSetting.getLegacyPermissionState(), userId);
+ sharedUserPermissions.put(sharedUserName, permissions);
}
+
+ RuntimePermissionsState runtimePermissions = new RuntimePermissionsState(version,
+ fingerprint, packagePermissions, sharedUserPermissions);
+
+ mPersistence.writeForUser(runtimePermissions, UserHandle.of(userId));
}
-
- Map<String, List<RuntimePermissionsState.PermissionState>> sharedUserPermissions =
- new ArrayMap<>();
- final int sharedUsersSize = mSharedUsers.size();
- for (int i = 0; i < sharedUsersSize; i++) {
- String sharedUserName = mSharedUsers.keyAt(i);
- SharedUserSetting sharedUserSetting = mSharedUsers.valueAt(i);
- List<RuntimePermissionsState.PermissionState> permissions =
- getPermissionsFromPermissionsState(
- sharedUserSetting.getLegacyPermissionState(), userId);
- sharedUserPermissions.put(sharedUserName, permissions);
- }
-
- RuntimePermissionsState runtimePermissions = new RuntimePermissionsState(version,
- fingerprint, packagePermissions, sharedUserPermissions);
-
- mPersistence.writeForUser(runtimePermissions, UserHandle.of(userId));
}
@NonNull
@@ -5541,82 +5575,91 @@
return permissions;
}
- @GuardedBy("Settings.this.mLock")
- private void onUserRemovedLPw(int userId) {
- // Make sure we do not
- mHandler.removeMessages(userId);
+ private void onUserRemoved(int userId) {
+ synchronized (mLock) {
+ // Make sure we do not
+ mHandler.removeMessages(userId);
- mPermissionUpgradeNeeded.delete(userId);
- mVersions.delete(userId);
- mFingerprints.remove(userId);
+ mPermissionUpgradeNeeded.delete(userId);
+ mVersions.delete(userId);
+ mFingerprints.remove(userId);
+ }
}
public void deleteUserRuntimePermissionsFile(int userId) {
- mPersistence.deleteForUser(UserHandle.of(userId));
+ synchronized (mLock) {
+ mPersistence.deleteForUser(UserHandle.of(userId));
+ }
}
- @GuardedBy("Settings.this.mLock")
- public void readStateForUserSyncLPr(int userId) {
- RuntimePermissionsState runtimePermissions = mPersistence.readForUser(UserHandle.of(
- userId));
- if (runtimePermissions == null) {
- readLegacyStateForUserSyncLPr(userId);
- writeStateForUserAsyncLPr(userId);
- return;
- }
-
- // If the runtime permissions file exists but the version is not set this is
- // an upgrade from P->Q. Hence mark it with the special UPGRADE_VERSION.
- int version = runtimePermissions.getVersion();
- if (version == RuntimePermissionsState.NO_VERSION) {
- version = UPGRADE_VERSION;
- }
- mVersions.put(userId, version);
-
- String fingerprint = runtimePermissions.getFingerprint();
- mFingerprints.put(userId, fingerprint);
-
- boolean isUpgradeToR = getInternalVersion().sdkVersion < Build.VERSION_CODES.R;
-
- Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
- runtimePermissions.getPackagePermissions();
- int packagesSize = mPackages.size();
- for (int i = 0; i < packagesSize; i++) {
- String packageName = mPackages.keyAt(i);
- PackageSetting packageSetting = mPackages.valueAt(i);
-
- List<RuntimePermissionsState.PermissionState> permissions =
- packagePermissions.get(packageName);
- if (permissions != null) {
- readPermissionsStateLpr(permissions, packageSetting.getLegacyPermissionState(),
- userId);
- packageSetting.setInstallPermissionsFixed(true);
- } else if (packageSetting.getSharedUser() == null && !isUpgradeToR) {
- Slog.w(TAG, "Missing permission state for package: " + packageName);
- packageSetting.getLegacyPermissionState().setMissing(true, userId);
+ public void readStateForUserSync(int userId, @NonNull VersionInfo internalVersion,
+ @NonNull WatchedArrayMap<String, PackageSetting> packageSettings,
+ @NonNull WatchedArrayMap<String, SharedUserSetting> sharedUsers,
+ @NonNull File userRuntimePermissionsFile) {
+ synchronized (mLock) {
+ RuntimePermissionsState runtimePermissions = mPersistence.readForUser(UserHandle.of(
+ userId));
+ if (runtimePermissions == null) {
+ readLegacyStateForUserSync(userId, userRuntimePermissionsFile, packageSettings,
+ sharedUsers);
+ writeStateForUserAsync(userId);
+ return;
}
- }
- Map<String, List<RuntimePermissionsState.PermissionState>> sharedUserPermissions =
- runtimePermissions.getSharedUserPermissions();
- int sharedUsersSize = mSharedUsers.size();
- for (int i = 0; i < sharedUsersSize; i++) {
- String sharedUserName = mSharedUsers.keyAt(i);
- SharedUserSetting sharedUserSetting = mSharedUsers.valueAt(i);
+ // If the runtime permissions file exists but the version is not set this is
+ // an upgrade from P->Q. Hence mark it with the special UPGRADE_VERSION.
+ int version = runtimePermissions.getVersion();
+ if (version == RuntimePermissionsState.NO_VERSION) {
+ version = UPGRADE_VERSION;
+ }
+ mVersions.put(userId, version);
- List<RuntimePermissionsState.PermissionState> permissions =
- sharedUserPermissions.get(sharedUserName);
- if (permissions != null) {
- readPermissionsStateLpr(permissions,
- sharedUserSetting.getLegacyPermissionState(), userId);
- } else if (!isUpgradeToR) {
- Slog.w(TAG, "Missing permission state for shared user: " + sharedUserName);
- sharedUserSetting.getLegacyPermissionState().setMissing(true, userId);
+ String fingerprint = runtimePermissions.getFingerprint();
+ mFingerprints.put(userId, fingerprint);
+
+ boolean isUpgradeToR = internalVersion.sdkVersion < Build.VERSION_CODES.R;
+
+ Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
+ runtimePermissions.getPackagePermissions();
+ int packagesSize = packageSettings.size();
+ for (int i = 0; i < packagesSize; i++) {
+ String packageName = packageSettings.keyAt(i);
+ PackageSetting packageSetting = packageSettings.valueAt(i);
+
+ List<RuntimePermissionsState.PermissionState> permissions =
+ packagePermissions.get(packageName);
+ if (permissions != null) {
+ readPermissionsState(permissions,
+ packageSetting.getLegacyPermissionState(),
+ userId);
+ packageSetting.setInstallPermissionsFixed(true);
+ } else if (packageSetting.getSharedUser() == null && !isUpgradeToR) {
+ Slog.w(TAG, "Missing permission state for package: " + packageName);
+ packageSetting.getLegacyPermissionState().setMissing(true, userId);
+ }
+ }
+
+ Map<String, List<RuntimePermissionsState.PermissionState>> sharedUserPermissions =
+ runtimePermissions.getSharedUserPermissions();
+ int sharedUsersSize = sharedUsers.size();
+ for (int i = 0; i < sharedUsersSize; i++) {
+ String sharedUserName = sharedUsers.keyAt(i);
+ SharedUserSetting sharedUserSetting = sharedUsers.valueAt(i);
+
+ List<RuntimePermissionsState.PermissionState> permissions =
+ sharedUserPermissions.get(sharedUserName);
+ if (permissions != null) {
+ readPermissionsState(permissions,
+ sharedUserSetting.getLegacyPermissionState(), userId);
+ } else if (!isUpgradeToR) {
+ Slog.w(TAG, "Missing permission state for shared user: " + sharedUserName);
+ sharedUserSetting.getLegacyPermissionState().setMissing(true, userId);
+ }
}
}
}
- private void readPermissionsStateLpr(
+ private void readPermissionsState(
@NonNull List<RuntimePermissionsState.PermissionState> permissions,
@NonNull LegacyPermissionState permissionsState, @UserIdInt int userId) {
int permissionsSize = permissions.size();
@@ -5630,77 +5673,86 @@
}
}
- @GuardedBy("Settings.this.mLock")
- private void readLegacyStateForUserSyncLPr(int userId) {
- File permissionsFile = getUserRuntimePermissionsFile(userId);
- if (!permissionsFile.exists()) {
- return;
- }
+ private void readLegacyStateForUserSync(int userId, @NonNull File permissionsFile,
+ @NonNull WatchedArrayMap<String, ? extends PackageStateInternal> packageStates,
+ @NonNull WatchedArrayMap<String, SharedUserSetting> sharedUsers) {
+ synchronized (mLock) {
+ if (!permissionsFile.exists()) {
+ return;
+ }
- FileInputStream in;
- try {
- in = new AtomicFile(permissionsFile).openRead();
- } catch (FileNotFoundException fnfe) {
- Slog.i(PackageManagerService.TAG, "No permissions state");
- return;
- }
+ FileInputStream in;
+ try {
+ in = new AtomicFile(permissionsFile).openRead();
+ } catch (FileNotFoundException fnfe) {
+ Slog.i(PackageManagerService.TAG, "No permissions state");
+ return;
+ }
- try {
- final TypedXmlPullParser parser = Xml.resolvePullParser(in);
- parseLegacyRuntimePermissionsLPr(parser, userId);
+ try {
+ final TypedXmlPullParser parser = Xml.resolvePullParser(in);
+ parseLegacyRuntimePermissions(parser, userId, packageStates, sharedUsers);
- } catch (XmlPullParserException | IOException e) {
- throw new IllegalStateException("Failed parsing permissions file: "
- + permissionsFile, e);
- } finally {
- IoUtils.closeQuietly(in);
+ } catch (XmlPullParserException | IOException e) {
+ throw new IllegalStateException("Failed parsing permissions file: "
+ + permissionsFile, e);
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
}
}
- // Private internals
-
- @GuardedBy("Settings.this.mLock")
- private void parseLegacyRuntimePermissionsLPr(TypedXmlPullParser parser, int userId)
+ private void parseLegacyRuntimePermissions(TypedXmlPullParser parser, int userId,
+ @NonNull WatchedArrayMap<String, ? extends PackageStateInternal> packageStates,
+ @NonNull WatchedArrayMap<String, SharedUserSetting> sharedUsers)
throws IOException, XmlPullParserException {
- final int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
+ synchronized (mLock) {
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
- switch (parser.getName()) {
- case TAG_RUNTIME_PERMISSIONS: {
- // If the permisions settings file exists but the version is not set this is
- // an upgrade from P->Q. Hence mark it with the special UPGRADE_VERSION
- int version = parser.getAttributeInt(null, ATTR_VERSION, UPGRADE_VERSION);
- mVersions.put(userId, version);
- String fingerprint = parser.getAttributeValue(null, ATTR_FINGERPRINT);
- mFingerprints.put(userId, fingerprint);
- } break;
-
- case TAG_PACKAGE: {
- String name = parser.getAttributeValue(null, ATTR_NAME);
- PackageSetting ps = mPackages.get(name);
- if (ps == null) {
- Slog.w(PackageManagerService.TAG, "Unknown package:" + name);
- XmlUtils.skipCurrentTag(parser);
- continue;
+ switch (parser.getName()) {
+ case TAG_RUNTIME_PERMISSIONS: {
+ // If the permisions settings file exists but the version is not set this is
+ // an upgrade from P->Q. Hence mark it with the special UPGRADE_VERSION
+ int version = parser.getAttributeInt(null, ATTR_VERSION,
+ UPGRADE_VERSION);
+ mVersions.put(userId, version);
+ String fingerprint = parser.getAttributeValue(null, ATTR_FINGERPRINT);
+ mFingerprints.put(userId, fingerprint);
}
- parseLegacyPermissionsLPr(parser, ps.getLegacyPermissionState(), userId);
- } break;
+ break;
- case TAG_SHARED_USER: {
- String name = parser.getAttributeValue(null, ATTR_NAME);
- SharedUserSetting sus = mSharedUsers.get(name);
- if (sus == null) {
- Slog.w(PackageManagerService.TAG, "Unknown shared user:" + name);
- XmlUtils.skipCurrentTag(parser);
- continue;
+ case TAG_PACKAGE: {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ PackageStateInternal ps = packageStates.get(name);
+ if (ps == null) {
+ Slog.w(PackageManagerService.TAG, "Unknown package:" + name);
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ parseLegacyPermissionsLPr(parser, ps.getLegacyPermissionState(),
+ userId);
}
- parseLegacyPermissionsLPr(parser, sus.getLegacyPermissionState(), userId);
- } break;
+ break;
+
+ case TAG_SHARED_USER: {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ SharedUserSetting sus = sharedUsers.get(name);
+ if (sus == null) {
+ Slog.w(PackageManagerService.TAG, "Unknown shared user:" + name);
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ parseLegacyPermissionsLPr(parser, sus.getLegacyPermissionState(),
+ userId);
+ }
+ break;
+ }
}
}
}
@@ -5708,25 +5760,27 @@
private void parseLegacyPermissionsLPr(TypedXmlPullParser parser,
LegacyPermissionState permissionsState, int userId)
throws IOException, XmlPullParserException {
- final int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- switch (parser.getName()) {
- case TAG_ITEM: {
- String name = parser.getAttributeValue(null, ATTR_NAME);
- final boolean granted =
- parser.getAttributeBoolean(null, ATTR_GRANTED, true);
- final int flags =
- parser.getAttributeIntHex(null, ATTR_FLAGS, 0);
- permissionsState.putPermissionState(new PermissionState(name, true,
- granted, flags), userId);
+ synchronized (mLock) {
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
}
- break;
+
+ switch (parser.getName()) {
+ case TAG_ITEM: {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ final boolean granted =
+ parser.getAttributeBoolean(null, ATTR_GRANTED, true);
+ final int flags =
+ parser.getAttributeIntHex(null, ATTR_FLAGS, 0);
+ permissionsState.putPermissionState(new PermissionState(name, true,
+ granted, flags), userId);
+ }
+ break;
+ }
}
}
}
@@ -5740,9 +5794,7 @@
public void handleMessage(Message message) {
final int userId = message.what;
Runnable callback = (Runnable) message.obj;
- synchronized (mLock) {
- writeStateForUserSyncLPr(userId);
- }
+ mInvokeWriteUserStateAsyncCallback.accept(userId);
if (callback != null) {
callback.run();
}
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
new file mode 100644
index 0000000..f38ae77
--- /dev/null
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -0,0 +1,824 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import static com.android.server.pm.PackageManagerService.TAG;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageManager;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.VersionedPackage;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+import android.service.pm.PackageServiceDumpProto;
+import android.util.ArraySet;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.SystemConfig;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.utils.Snappable;
+import com.android.server.utils.SnapshotCache;
+import com.android.server.utils.Watchable;
+import com.android.server.utils.WatchableImpl;
+import com.android.server.utils.Watched;
+import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.WatchedLongSparseArray;
+import com.android.server.utils.Watcher;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiConsumer;
+
+/**
+ * Current known shared libraries on the device.
+ */
+public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable, Snappable {
+
+ // TODO(b/200588896): remove PMS dependency
+ private final PackageManagerService mPm;
+ private final PackageManagerServiceInjector mInjector;
+ private DeletePackageHelper mDeletePackageHelper; // late init
+
+ // A map of library name to a list of {@link SharedLibraryInfo}s with different versions.
+ @Watched
+ private final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
+ mSharedLibraries;
+ private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
+ mSharedLibrariesSnapshot;
+
+ // A map of declaring package name to a list of {@link SharedLibraryInfo}s with different
+ // versions.
+ @Watched
+ private final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
+ mStaticLibsByDeclaringPackage;
+ private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
+ mStaticLibsByDeclaringPackageSnapshot;
+
+ /**
+ * Watchable machinery
+ */
+ private final WatchableImpl mWatchable = new WatchableImpl();
+
+ /**
+ * The observer that watches for changes from array members
+ */
+ private final Watcher mObserver = new Watcher() {
+ @Override
+ public void onChange(@Nullable Watchable what) {
+ SharedLibrariesImpl.this.dispatchChange(what);
+ }
+ };
+
+ private final SnapshotCache<SharedLibrariesImpl> mSnapshot;
+
+ // Create a snapshot cache
+ private SnapshotCache<SharedLibrariesImpl> makeCache() {
+ return new SnapshotCache<SharedLibrariesImpl>(this /* source */, this /* watchable */) {
+ @Override
+ public SharedLibrariesImpl createSnapshot() {
+ final SharedLibrariesImpl sharedLibrariesImpl = new SharedLibrariesImpl(mSource);
+ sharedLibrariesImpl.mWatchable.seal();
+ return sharedLibrariesImpl;
+ }};
+ }
+
+ /**
+ * Default constructor used in PackageManagerService.
+ */
+ SharedLibrariesImpl(PackageManagerService pm, PackageManagerServiceInjector injector) {
+ mPm = pm;
+ mInjector = injector;
+
+ mSharedLibraries = new WatchedArrayMap<>();
+ mSharedLibrariesSnapshot = new SnapshotCache.Auto<>(mSharedLibraries, mSharedLibraries,
+ "SharedLibrariesImpl.mSharedLibraries");
+ mStaticLibsByDeclaringPackage = new WatchedArrayMap<>();
+ mStaticLibsByDeclaringPackageSnapshot = new SnapshotCache.Auto<>(
+ mStaticLibsByDeclaringPackage, mStaticLibsByDeclaringPackage,
+ "SharedLibrariesImpl.mStaticLibsByDeclaringPackage");
+
+ registerObservers();
+ Watchable.verifyWatchedAttributes(this, mObserver);
+ mSnapshot = makeCache();
+ }
+
+ /**
+ * Invoked by PMS constructor after the instance of {@link DeletePackageHelper} is ready.
+ */
+ void setDeletePackageHelper(DeletePackageHelper deletePackageHelper) {
+ mDeletePackageHelper = deletePackageHelper;
+ }
+
+ private void registerObservers() {
+ mSharedLibraries.registerObserver(mObserver);
+ mStaticLibsByDeclaringPackage.registerObserver(mObserver);
+ }
+
+ /**
+ * A copy constructor used in snapshot().
+ */
+ private SharedLibrariesImpl(SharedLibrariesImpl source) {
+ mPm = source.mPm;
+ mInjector = source.mInjector;
+
+ mSharedLibraries = source.mSharedLibrariesSnapshot.snapshot();
+ mSharedLibrariesSnapshot = new SnapshotCache.Sealed<>();
+ mStaticLibsByDeclaringPackage = source.mStaticLibsByDeclaringPackageSnapshot.snapshot();
+ mStaticLibsByDeclaringPackageSnapshot = new SnapshotCache.Sealed<>();
+
+ // Do not register any Watchables and do not create a snapshot cache.
+ mSnapshot = new SnapshotCache.Sealed();
+ }
+
+ /**
+ * Ensures an observer is in the list, exactly once. The observer cannot be null. The
+ * function quietly returns if the observer is already in the list.
+ *
+ * @param observer The {@link Watcher} to be notified when the {@link Watchable} changes.
+ */
+ @Override
+ public void registerObserver(@NonNull Watcher observer) {
+ mWatchable.registerObserver(observer);
+ }
+
+ /**
+ * Ensures an observer is not in the list. The observer must not be null. The function
+ * quietly returns if the objserver is not in the list.
+ *
+ * @param observer The {@link Watcher} that should not be in the notification list.
+ */
+ @Override
+ public void unregisterObserver(@NonNull Watcher observer) {
+ mWatchable.unregisterObserver(observer);
+ }
+
+ /**
+ * Return true if the {@link Watcher} is a registered observer.
+ * @param observer A {@link Watcher} that might be registered
+ * @return true if the observer is registered with this {@link Watchable}.
+ */
+ @Override
+ public boolean isRegisteredObserver(@NonNull Watcher observer) {
+ return mWatchable.isRegisteredObserver(observer);
+ }
+
+ /**
+ * Invokes {@link Watcher#onChange} on each registered observer. The method can be called
+ * with the {@link Watchable} that generated the event. In a tree of {@link Watchable}s, this
+ * is generally the first (deepest) {@link Watchable} to detect a change.
+ *
+ * @param what The {@link Watchable} that generated the event.
+ */
+ @Override
+ public void dispatchChange(@Nullable Watchable what) {
+ mWatchable.dispatchChange(what);
+ }
+
+ /**
+ * Create an immutable copy of the object, suitable for read-only methods. A snapshot
+ * is free to omit state that is only needed for mutating methods.
+ */
+ @Override
+ public @NonNull SharedLibrariesRead snapshot() {
+ return mSnapshot.snapshot();
+ }
+
+ /**
+ * Returns all shared libraries on the device.
+ */
+ @GuardedBy("mPm.mLock")
+ @Override
+ public @NonNull WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getAll() {
+ return mSharedLibraries;
+ }
+
+ /**
+ * Given the library name, returns a list of shared libraries on all versions.
+ */
+ @GuardedBy("mPm.mLock")
+ @Override
+ public @NonNull WatchedLongSparseArray<SharedLibraryInfo> getSharedLibraryInfos(
+ @NonNull String libName) {
+ return mSharedLibraries.get(libName);
+ }
+
+ /**
+ * Returns the shared library with given library name and version number.
+ */
+ @GuardedBy("mPm.mLock")
+ @Override
+ public @Nullable SharedLibraryInfo getSharedLibraryInfo(@NonNull String libName, long version) {
+ final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
+ mSharedLibraries.get(libName);
+ if (versionedLib == null) {
+ return null;
+ }
+ return versionedLib.get(version);
+ }
+
+ /**
+ * Given the declaring package name, returns a list of static shared libraries on all versions.
+ */
+ @GuardedBy("mPm.mLock")
+ @Override
+ public @NonNull WatchedLongSparseArray<SharedLibraryInfo> getStaticLibraryInfos(
+ @NonNull String declaringPackageName) {
+ return mStaticLibsByDeclaringPackage.get(declaringPackageName);
+ }
+
+ @GuardedBy("mPm.mLock")
+ private @Nullable PackageSetting getLibraryPackageLPr(@NonNull SharedLibraryInfo libInfo) {
+ final VersionedPackage declaringPackage = libInfo.getDeclaringPackage();
+ if (libInfo.isStatic()) {
+ // Resolve the package name - we use synthetic package names internally
+ final String internalPackageName = mPm.resolveInternalPackageNameLPr(
+ declaringPackage.getPackageName(),
+ declaringPackage.getLongVersionCode());
+ return mPm.mSettings.getPackageLPr(internalPackageName);
+ }
+ if (libInfo.isSdk()) {
+ return mPm.mSettings.getPackageLPr(declaringPackage.getPackageName());
+ }
+ return null;
+ }
+
+ /**
+ * Finds all unused shared libraries which have cached more than the given
+ * {@code maxCachePeriod}. Deletes them one by one until the available storage space on the
+ * device is larger than {@code neededSpace}.
+ *
+ * @param neededSpace A minimum available storage space the device needs to reach
+ * @param maxCachePeriod A maximum period of time an unused shared library can be cached
+ * on the device.
+ * @return {@code true} if the available storage space is reached.
+ */
+ boolean pruneUnusedStaticSharedLibraries(long neededSpace, long maxCachePeriod)
+ throws IOException {
+ final StorageManager storage = mInjector.getSystemService(StorageManager.class);
+ final File volume = storage.findPathForUuid(StorageManager.UUID_PRIVATE_INTERNAL);
+
+ List<VersionedPackage> packagesToDelete = null;
+ final long now = System.currentTimeMillis();
+
+ // Important: We skip shared libs used for some user since
+ // in such a case we need to keep the APK on the device. The check for
+ // a lib being used for any user is performed by the uninstall call.
+ synchronized (mPm.mLock) {
+ final int libCount = mSharedLibraries.size();
+ for (int i = 0; i < libCount; i++) {
+ final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
+ mSharedLibraries.valueAt(i);
+ if (versionedLib == null) {
+ continue;
+ }
+ final int versionCount = versionedLib.size();
+ for (int j = 0; j < versionCount; j++) {
+ SharedLibraryInfo libInfo = versionedLib.valueAt(j);
+ final PackageSetting ps = getLibraryPackageLPr(libInfo);
+ if (ps == null) {
+ continue;
+ }
+ // Skip unused libs cached less than the min period to prevent pruning a lib
+ // needed by a subsequently installed package.
+ if (now - ps.getLastUpdateTime() < maxCachePeriod) {
+ continue;
+ }
+
+ if (ps.getPkg().isSystem()) {
+ continue;
+ }
+
+ if (packagesToDelete == null) {
+ packagesToDelete = new ArrayList<>();
+ }
+ packagesToDelete.add(new VersionedPackage(ps.getPkg().getPackageName(),
+ libInfo.getDeclaringPackage().getLongVersionCode()));
+ }
+ }
+ }
+
+ if (packagesToDelete != null) {
+ final int packageCount = packagesToDelete.size();
+ for (int i = 0; i < packageCount; i++) {
+ final VersionedPackage pkgToDelete = packagesToDelete.get(i);
+ // Delete the package synchronously (will fail of the lib used for any user).
+ if (mDeletePackageHelper.deletePackageX(pkgToDelete.getPackageName(),
+ pkgToDelete.getLongVersionCode(), UserHandle.USER_SYSTEM,
+ PackageManager.DELETE_ALL_USERS,
+ true /*removedBySystem*/) == PackageManager.DELETE_SUCCEEDED) {
+ if (volume.getUsableSpace() >= neededSpace) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Given a package of static shared library, returns its shared library info of
+ * the latest version.
+ *
+ * @param pkg A package of static shared library.
+ * @return The latest version of shared library info.
+ */
+ @GuardedBy("mPm.mLock")
+ @Nullable SharedLibraryInfo getLatestSharedLibraVersionLPr(@NonNull AndroidPackage pkg) {
+ WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(
+ pkg.getStaticSharedLibName());
+ if (versionedLib == null) {
+ return null;
+ }
+ long previousLibVersion = -1;
+ final int versionCount = versionedLib.size();
+ for (int i = 0; i < versionCount; i++) {
+ final long libVersion = versionedLib.keyAt(i);
+ if (libVersion < pkg.getStaticSharedLibVersion()) {
+ previousLibVersion = Math.max(previousLibVersion, libVersion);
+ }
+ }
+ if (previousLibVersion >= 0) {
+ return versionedLib.get(previousLibVersion);
+ }
+ return null;
+ }
+
+ /**
+ * Given a package scanned result of a static shared library, returns its package setting of
+ * the latest version
+ *
+ * @param scanResult The scanned result of a static shared library package.
+ * @return The package setting that represents the latest version of shared library info.
+ */
+ @Nullable
+ PackageSetting getSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) {
+ PackageSetting sharedLibPackage = null;
+ synchronized (mPm.mLock) {
+ final SharedLibraryInfo latestSharedLibraVersionLPr =
+ getLatestSharedLibraVersionLPr(scanResult.mRequest.mParsedPackage);
+ if (latestSharedLibraVersionLPr != null) {
+ sharedLibPackage = mPm.mSettings.getPackageLPr(
+ latestSharedLibraVersionLPr.getPackageName());
+ }
+ }
+ return sharedLibPackage;
+ }
+
+ /**
+ * Apply a given {@code action} to all the libraries defining in the package.
+ *
+ * @param pkg A package defining libraries.
+ * @param libInfo An extra shared library info passing to the action.
+ * @param action The action to apply.
+ */
+ @GuardedBy("mPm.mLock")
+ private void applyDefiningSharedLibraryUpdateLPr(
+ @NonNull AndroidPackage pkg, @Nullable SharedLibraryInfo libInfo,
+ @NonNull BiConsumer<SharedLibraryInfo, SharedLibraryInfo> action) {
+ // Note that libraries defined by this package may be null if:
+ // - Package manager was unable to create the shared library. The package still
+ // gets installed, but the shared library does not get created.
+ // Or:
+ // - Package manager is in a state where package isn't scanned yet. This will
+ // get called again after scanning to fix the dependencies.
+ if (AndroidPackageUtils.isLibrary(pkg)) {
+ if (pkg.getSdkLibName() != null) {
+ SharedLibraryInfo definedLibrary = getSharedLibraryInfo(
+ pkg.getSdkLibName(), pkg.getSdkLibVersionMajor());
+ if (definedLibrary != null) {
+ action.accept(definedLibrary, libInfo);
+ }
+ } else if (pkg.getStaticSharedLibName() != null) {
+ SharedLibraryInfo definedLibrary = getSharedLibraryInfo(
+ pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion());
+ if (definedLibrary != null) {
+ action.accept(definedLibrary, libInfo);
+ }
+ } else {
+ for (String libraryName : pkg.getLibraryNames()) {
+ SharedLibraryInfo definedLibrary = getSharedLibraryInfo(
+ libraryName, SharedLibraryInfo.VERSION_UNDEFINED);
+ if (definedLibrary != null) {
+ action.accept(definedLibrary, libInfo);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds shared library {@code libInfo}'s self code paths and using library files to the list
+ * {@code usesLibraryFiles}. Also, adds the dependencies to the shared libraries that are
+ * defining in the {@code pkg}.
+ *
+ * @param pkg A package that is using the {@code libInfo}.
+ * @param usesLibraryFiles A list to add code paths to.
+ * @param libInfo A shared library info that is used by the {@code pkg}.
+ * @param changingLib The updating library package.
+ * @param changingLibSetting The updating library package setting.
+ */
+ @GuardedBy("mPm.mLock")
+ private void addSharedLibraryLPr(@NonNull AndroidPackage pkg,
+ @NonNull Set<String> usesLibraryFiles, @NonNull SharedLibraryInfo libInfo,
+ @Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting) {
+ if (libInfo.getPath() != null) {
+ usesLibraryFiles.add(libInfo.getPath());
+ return;
+ }
+ AndroidPackage pkgForCodePaths = mPm.mPackages.get(libInfo.getPackageName());
+ PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(libInfo.getPackageName());
+ if (changingLib != null && changingLib.getPackageName().equals(libInfo.getPackageName())) {
+ // If we are doing this while in the middle of updating a library apk,
+ // then we need to make sure to use that new apk for determining the
+ // dependencies here. (We haven't yet finished committing the new apk
+ // to the package manager state.)
+ if (pkgForCodePaths == null
+ || pkgForCodePaths.getPackageName().equals(changingLib.getPackageName())) {
+ pkgForCodePaths = changingLib;
+ pkgSetting = changingLibSetting;
+ }
+ }
+ if (pkgForCodePaths != null) {
+ usesLibraryFiles.addAll(AndroidPackageUtils.getAllCodePaths(pkgForCodePaths));
+ // If the package provides libraries, add the dependency to them.
+ applyDefiningSharedLibraryUpdateLPr(pkg, libInfo, SharedLibraryInfo::addDependency);
+ if (pkgSetting != null) {
+ usesLibraryFiles.addAll(pkgSetting.getPkgState().getUsesLibraryFiles());
+ }
+ }
+ }
+
+ /**
+ * Collects all shared libraries being used by the target package. Rebuilds the dependencies
+ * of shared libraries and update the correct shared library code paths for it.
+ *
+ * @param pkg The target package to update shared library dependency.
+ * @param pkgSetting The target's package setting.
+ * @param changingLib The updating library package.
+ * @param changingLibSetting The updating library package setting.
+ * @param availablePackages All installed packages and current being installed packages.
+ */
+ @GuardedBy("mPm.mLock")
+ void updateSharedLibrariesLPw(@NonNull AndroidPackage pkg, @NonNull PackageSetting pkgSetting,
+ @Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting,
+ @NonNull Map<String, AndroidPackage> availablePackages)
+ throws PackageManagerException {
+ final ArrayList<SharedLibraryInfo> sharedLibraryInfos =
+ SharedLibraryHelper.collectSharedLibraryInfos(
+ pkgSetting.getPkg(), availablePackages, mSharedLibraries,
+ null /* newLibraries */, mInjector.getCompatibility());
+ executeSharedLibrariesUpdateLPw(pkg, pkgSetting, changingLib, changingLibSetting,
+ sharedLibraryInfos, mPm.mUserManager.getUserIds());
+ }
+
+ /**
+ * Rebuilds the dependencies of shared libraries for the target package, and update the
+ * shared library code paths to its package setting.
+ *
+ * @param pkg The target package to update shared library dependency.
+ * @param pkgSetting The target's package setting.
+ * @param changingLib The updating library package.
+ * @param changingLibSetting The updating library package setting.
+ * @param usesLibraryInfos The shared libraries used by the target package.
+ * @param allUsers All user ids on the device.
+ */
+ @GuardedBy("mPm.mLock")
+ void executeSharedLibrariesUpdateLPw(AndroidPackage pkg,
+ @NonNull PackageSetting pkgSetting, @Nullable AndroidPackage changingLib,
+ @Nullable PackageSetting changingLibSetting,
+ ArrayList<SharedLibraryInfo> usesLibraryInfos, int[] allUsers) {
+ // If the package provides libraries, clear their old dependencies.
+ // This method will set them up again.
+ applyDefiningSharedLibraryUpdateLPr(pkg, null, (definingLibrary, dependency) -> {
+ definingLibrary.clearDependencies();
+ });
+ if (usesLibraryInfos != null) {
+ pkgSetting.getPkgState().setUsesLibraryInfos(usesLibraryInfos);
+ // Use LinkedHashSet to preserve the order of files added to
+ // usesLibraryFiles while eliminating duplicates.
+ Set<String> usesLibraryFiles = new LinkedHashSet<>();
+ for (SharedLibraryInfo libInfo : usesLibraryInfos) {
+ addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib,
+ changingLibSetting);
+ }
+ pkgSetting.setPkgStateLibraryFiles(usesLibraryFiles);
+
+ // let's make sure we mark all static shared libraries as installed for the same users
+ // that its dependent packages are installed for.
+ int[] installedUsers = new int[allUsers.length];
+ int installedUserCount = 0;
+ for (int u = 0; u < allUsers.length; u++) {
+ if (pkgSetting.getInstalled(allUsers[u])) {
+ installedUsers[installedUserCount++] = allUsers[u];
+ }
+ }
+ for (SharedLibraryInfo sharedLibraryInfo : usesLibraryInfos) {
+ if (!sharedLibraryInfo.isStatic()) {
+ continue;
+ }
+ final PackageSetting staticLibPkgSetting =
+ mPm.getPackageSettingForMutation(sharedLibraryInfo.getPackageName());
+ if (staticLibPkgSetting == null) {
+ Slog.wtf(TAG, "Shared lib without setting: " + sharedLibraryInfo);
+ continue;
+ }
+ for (int u = 0; u < installedUserCount; u++) {
+ staticLibPkgSetting.setInstalled(true, installedUsers[u]);
+ }
+ }
+ } else {
+ pkgSetting.getPkgState().setUsesLibraryInfos(Collections.emptyList())
+ .setUsesLibraryFiles(Collections.emptyList());
+ }
+ }
+
+ private static boolean hasString(List<String> list, List<String> which) {
+ if (list == null || which == null) {
+ return false;
+ }
+ for (int i = list.size() - 1; i >= 0; i--) {
+ for (int j = which.size() - 1; j >= 0; j--) {
+ if (which.get(j).equals(list.get(i))) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Update shared library dependencies and code paths for applications that are using the
+ * library {@code updatedPkg}. Update all applications if the {@code updatedPkg} is null.
+ *
+ * @param updatedPkg The updating shared library package.
+ * @param updatedPkgSetting The updating shared library package setting.
+ * @param availablePackages All available packages on the device.
+ * @return Packages that has been updated.
+ */
+ @GuardedBy("mPm.mLock")
+ @Nullable ArrayList<AndroidPackage> updateAllSharedLibrariesLPw(
+ @Nullable AndroidPackage updatedPkg, @Nullable PackageSetting updatedPkgSetting,
+ @NonNull Map<String, AndroidPackage> availablePackages) {
+ ArrayList<AndroidPackage> resultList = null;
+ // Set of all descendants of a library; used to eliminate cycles
+ ArraySet<String> descendants = null;
+ // The current list of packages that need updating
+ List<Pair<AndroidPackage, PackageSetting>> needsUpdating = null;
+ if (updatedPkg != null && updatedPkgSetting != null) {
+ needsUpdating = new ArrayList<>(1);
+ needsUpdating.add(Pair.create(updatedPkg, updatedPkgSetting));
+ }
+ do {
+ final Pair<AndroidPackage, PackageSetting> changingPkgPair =
+ (needsUpdating == null) ? null : needsUpdating.remove(0);
+ final AndroidPackage changingPkg = changingPkgPair != null
+ ? changingPkgPair.first : null;
+ final PackageSetting changingPkgSetting = changingPkgPair != null
+ ? changingPkgPair.second : null;
+ for (int i = mPm.mPackages.size() - 1; i >= 0; --i) {
+ final AndroidPackage pkg = mPm.mPackages.valueAt(i);
+ final PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName());
+ if (changingPkg != null
+ && !hasString(pkg.getUsesLibraries(), changingPkg.getLibraryNames())
+ && !hasString(pkg.getUsesOptionalLibraries(), changingPkg.getLibraryNames())
+ && !ArrayUtils.contains(pkg.getUsesStaticLibraries(),
+ changingPkg.getStaticSharedLibName())
+ && !ArrayUtils.contains(pkg.getUsesSdkLibraries(),
+ changingPkg.getSdkLibName())) {
+ continue;
+ }
+ if (resultList == null) {
+ resultList = new ArrayList<>();
+ }
+ resultList.add(pkg);
+ // if we're updating a shared library, all of its descendants must be updated
+ if (changingPkg != null) {
+ if (descendants == null) {
+ descendants = new ArraySet<>();
+ }
+ if (!descendants.contains(pkg.getPackageName())) {
+ descendants.add(pkg.getPackageName());
+ needsUpdating.add(Pair.create(pkg, pkgSetting));
+ }
+ }
+ try {
+ updateSharedLibrariesLPw(pkg, pkgSetting, changingPkg,
+ changingPkgSetting, availablePackages);
+ } catch (PackageManagerException e) {
+ // If a system app update or an app and a required lib missing we
+ // delete the package and for updated system apps keep the data as
+ // it is better for the user to reinstall than to be in an limbo
+ // state. Also libs disappearing under an app should never happen
+ // - just in case.
+ if (!pkg.isSystem() || pkgSetting.getPkgState().isUpdatedSystemApp()) {
+ final int flags = pkgSetting.getPkgState().isUpdatedSystemApp()
+ ? PackageManager.DELETE_KEEP_DATA : 0;
+ mDeletePackageHelper.deletePackageLIF(pkg.getPackageName(), null, true,
+ mPm.mUserManager.getUserIds(), flags, null,
+ true);
+ }
+ Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
+ }
+ }
+ } while (needsUpdating != null && needsUpdating.size() > 0);
+ return resultList;
+ }
+
+ /**
+ * Add a build-in shared library info by given system configuration.
+ */
+ @GuardedBy("mPm.mLock")
+ void addBuiltInSharedLibraryLPw(@NonNull SystemConfig.SharedLibraryEntry entry) {
+ // check if built-in or dynamic library exists
+ if (getSharedLibraryInfo(entry.name, SharedLibraryInfo.VERSION_UNDEFINED) != null) {
+ return;
+ }
+
+ SharedLibraryInfo libraryInfo = new SharedLibraryInfo(entry.filename, null, null,
+ entry.name, SharedLibraryInfo.VERSION_UNDEFINED,
+ SharedLibraryInfo.TYPE_BUILTIN,
+ new VersionedPackage(PLATFORM_PACKAGE_NAME, 0L), null, null,
+ entry.isNative);
+
+ commitSharedLibraryInfoLPw(libraryInfo);
+ }
+
+ /**
+ * Add a shared library info to the system. This is invoked when the package is being added or
+ * scanned.
+ */
+ @GuardedBy("mPm.mLock")
+ void commitSharedLibraryInfoLPw(@NonNull SharedLibraryInfo libraryInfo) {
+ final String name = libraryInfo.getName();
+ WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(name);
+ if (versionedLib == null) {
+ versionedLib = new WatchedLongSparseArray<>();
+ mSharedLibraries.put(name, versionedLib);
+ }
+ final String declaringPackageName = libraryInfo.getDeclaringPackage().getPackageName();
+ if (libraryInfo.getType() == SharedLibraryInfo.TYPE_STATIC) {
+ mStaticLibsByDeclaringPackage.put(declaringPackageName, versionedLib);
+ }
+ versionedLib.put(libraryInfo.getLongVersion(), libraryInfo);
+ }
+
+ /**
+ * Remove a shared library from the system.
+ */
+ @GuardedBy("mPm.mLock")
+ boolean removeSharedLibraryLPw(@NonNull String libName, long version) {
+ WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(libName);
+ if (versionedLib == null) {
+ return false;
+ }
+ final int libIdx = versionedLib.indexOfKey(version);
+ if (libIdx < 0) {
+ return false;
+ }
+ SharedLibraryInfo libraryInfo = versionedLib.valueAt(libIdx);
+
+ // Remove the shared library overlays from its dependent packages.
+ for (int currentUserId : mPm.mUserManager.getUserIds()) {
+ final List<VersionedPackage> dependents = mPm.getPackagesUsingSharedLibrary(
+ libraryInfo, 0, Process.SYSTEM_UID, currentUserId);
+ if (dependents == null) {
+ continue;
+ }
+ for (VersionedPackage dependentPackage : dependents) {
+ final PackageSetting ps = mPm.mSettings.getPackageLPr(
+ dependentPackage.getPackageName());
+ if (ps != null) {
+ ps.setOverlayPathsForLibrary(libraryInfo.getName(), null, currentUserId);
+ }
+ }
+ }
+
+ versionedLib.remove(version);
+ if (versionedLib.size() <= 0) {
+ mSharedLibraries.remove(libName);
+ if (libraryInfo.getType() == SharedLibraryInfo.TYPE_STATIC) {
+ mStaticLibsByDeclaringPackage.remove(libraryInfo.getDeclaringPackage()
+ .getPackageName());
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Dump all shared libraries.
+ */
+ @GuardedBy("mPm.mLock")
+ @Override
+ public void dump(@NonNull PrintWriter pw, @NonNull DumpState dumpState) {
+ final boolean checkin = dumpState.isCheckIn();
+ boolean printedHeader = false;
+ final int numSharedLibraries = mSharedLibraries.size();
+ for (int index = 0; index < numSharedLibraries; index++) {
+ final String libName = mSharedLibraries.keyAt(index);
+ final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
+ mSharedLibraries.get(libName);
+ if (versionedLib == null) {
+ continue;
+ }
+ final int versionCount = versionedLib.size();
+ for (int i = 0; i < versionCount; i++) {
+ SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
+ if (!checkin) {
+ if (!printedHeader) {
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
+ pw.println("Libraries:");
+ printedHeader = true;
+ }
+ pw.print(" ");
+ } else {
+ pw.print("lib,");
+ }
+ pw.print(libraryInfo.getName());
+ if (libraryInfo.isStatic()) {
+ pw.print(" version=" + libraryInfo.getLongVersion());
+ }
+ if (!checkin) {
+ pw.print(" -> ");
+ }
+ if (libraryInfo.getPath() != null) {
+ if (libraryInfo.isNative()) {
+ pw.print(" (so) ");
+ } else {
+ pw.print(" (jar) ");
+ }
+ pw.print(libraryInfo.getPath());
+ } else {
+ pw.print(" (apk) ");
+ pw.print(libraryInfo.getPackageName());
+ }
+ pw.println();
+ }
+ }
+ }
+
+ /**
+ * Dump all shared libraries to given proto output stream.
+ */
+ @GuardedBy("mPm.mLock")
+ @Override
+ public void dumpProto(@NonNull ProtoOutputStream proto) {
+ final int count = mSharedLibraries.size();
+ for (int i = 0; i < count; i++) {
+ final String libName = mSharedLibraries.keyAt(i);
+ WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
+ mSharedLibraries.get(libName);
+ if (versionedLib == null) {
+ continue;
+ }
+ final int versionCount = versionedLib.size();
+ for (int j = 0; j < versionCount; j++) {
+ final SharedLibraryInfo libraryInfo = versionedLib.valueAt(j);
+ final long sharedLibraryToken =
+ proto.start(PackageServiceDumpProto.SHARED_LIBRARIES);
+ proto.write(PackageServiceDumpProto.SharedLibraryProto.NAME, libraryInfo.getName());
+ final boolean isJar = (libraryInfo.getPath() != null);
+ proto.write(PackageServiceDumpProto.SharedLibraryProto.IS_JAR, isJar);
+ if (isJar) {
+ proto.write(PackageServiceDumpProto.SharedLibraryProto.PATH,
+ libraryInfo.getPath());
+ } else {
+ proto.write(PackageServiceDumpProto.SharedLibraryProto.APK,
+ libraryInfo.getPackageName());
+ }
+ proto.end(sharedLibraryToken);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesRead.java b/services/core/java/com/android/server/pm/SharedLibrariesRead.java
new file mode 100644
index 0000000..e6f2311
--- /dev/null
+++ b/services/core/java/com/android/server/pm/SharedLibrariesRead.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.SharedLibraryInfo;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.WatchedLongSparseArray;
+
+import java.io.PrintWriter;
+
+/**
+ * An interface implemented by {@link SharedLibrariesImpl} for {@link Computer} to get current
+ * shared libraries on the device.
+ */
+interface SharedLibrariesRead {
+
+ /**
+ * Returns all shared libraries on the device.
+ *
+ * @return A map of library name to a list of {@link SharedLibraryInfo}s with
+ * different versions.
+ */
+ @NonNull
+ WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getAll();
+
+ /**
+ * Given the library name, returns a list of shared libraries on all versions.
+ *
+ * @param libName The library name.
+ * @return A list of shared library info.
+ */
+ @Nullable
+ WatchedLongSparseArray<SharedLibraryInfo> getSharedLibraryInfos(@NonNull String libName);
+
+ /**
+ * Returns the shared library with given library name and version number.
+ *
+ * @param libName The library name.
+ * @param version The library version number.
+ * @return The shared library info.
+ */
+ @Nullable
+ SharedLibraryInfo getSharedLibraryInfo(@NonNull String libName, long version);
+
+ /**
+ * Given the declaring package name, returns a list of static shared libraries on all versions.
+ *
+ * @param declaringPackageName The declaring name of the package.
+ * @return A list of shared library info.
+ */
+ @Nullable
+ WatchedLongSparseArray<SharedLibraryInfo> getStaticLibraryInfos(
+ @NonNull String declaringPackageName);
+
+ /**
+ * Dump all shared libraries.
+ *
+ * @param pw A PrintWriter to dump to.
+ * @param dumpState Including options and states for writing.
+ */
+ void dump(@NonNull PrintWriter pw, @NonNull DumpState dumpState);
+
+ /**
+ * Dump all shared libraries to given proto output stream.
+ * @param proto A proto output stream to dump to.
+ */
+ void dumpProto(@NonNull ProtoOutputStream proto);
+}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 6c1ef2e..a4f8087 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -198,6 +198,7 @@
private static final Set<String> SENSORS_PERMISSIONS = new ArraySet<>();
static {
SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS);
+ SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS_BACKGROUND);
}
private static final Set<String> STORAGE_PERMISSIONS = new ArraySet<>();
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 0958bcb..a3b6b82 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1252,7 +1252,8 @@
if (op < 0) {
// Bg location is one-off runtime modifier permission and has no app op
if (sPlatformPermissions.contains(permission)
- && !Manifest.permission.ACCESS_BACKGROUND_LOCATION.equals(permission)) {
+ && !Manifest.permission.ACCESS_BACKGROUND_LOCATION.equals(permission)
+ && !Manifest.permission.BODY_SENSORS_BACKGROUND.equals(permission)) {
Slog.wtf(LOG_TAG, "Platform runtime permission " + permission
+ " with no app op defined!");
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index d1b9938..c9fd122 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -23,6 +23,7 @@
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME;
@@ -108,6 +109,7 @@
import android.util.EventLog;
import android.util.IntArray;
import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -196,6 +198,9 @@
/** All nearby devices permissions */
private static final List<String> NEARBY_DEVICES_PERMISSIONS = new ArrayList<>();
+ // TODO: This is a placeholder. Replace with actual implementation
+ private static final List<String> NOTIFICATION_PERMISSIONS = new ArrayList<>();
+
/**
* All permissions that should be granted with the REVOKE_WHEN_REQUESTED flag, if they are
* implicitly added to a package
@@ -4636,23 +4641,231 @@
return true;
}
- private void onPackageInstalledInternal(@NonNull AndroidPackage pkg, int previousAppId,
- @NonNull PermissionManagerServiceInternal.PackageInstalledParams params,
- @UserIdInt int[] userIds) {
- // If previousAppId is not Process.INVALID_UID, the package is performing a migration out
- // of a shared user group. Operations we need to do before calling updatePermissions():
- // - Retrieve the original uid permission state and create a copy of it as the new app's
- // uid state. The new permission state will be properly updated in updatePermissions().
- // - Remove the app from the original shared user group. Other apps in the shared
- // user group will perceive as if the original app is uninstalled.
- if (previousAppId != Process.INVALID_UID) {
- final PackageStateInternal ps =
- mPackageManagerInt.getPackageStateInternal(pkg.getPackageName());
+ private boolean isEffectivelyGranted(PermissionState state) {
+ final int flags = state.getFlags();
+ final int denyMask = FLAG_PERMISSION_REVIEW_REQUIRED
+ | FLAG_PERMISSION_REVOKED_COMPAT
+ | FLAG_PERMISSION_ONE_TIME;
+
+ if ((flags & FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
+ return true;
+ } else if ((flags & FLAG_PERMISSION_POLICY_FIXED) != 0) {
+ return (flags & FLAG_PERMISSION_REVOKED_COMPAT) == 0 && state.isGranted();
+ } else if ((flags & denyMask) != 0) {
+ return false;
+ } else {
+ return state.isGranted();
+ }
+ }
+
+ /**
+ * Merge srcState into destState. Return [granted, flags].
+ */
+ private Pair<Boolean, Integer> mergePermissionState(int appId,
+ PermissionState srcState, PermissionState destState) {
+ // This merging logic prioritizes the shared permission state (destState) over
+ // the current package's state (srcState), because an uninstallation of a previously
+ // unrelated app (the updated system app) should not affect the functionality of
+ // existing apps (other apps in the shared UID group).
+
+ final int userSettableMask = FLAG_PERMISSION_USER_SET
+ | FLAG_PERMISSION_USER_FIXED
+ | FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY;
+
+ final int defaultGrantMask = FLAG_PERMISSION_GRANTED_BY_DEFAULT
+ | FLAG_PERMISSION_GRANTED_BY_ROLE;
+
+ final int priorityFixedMask = FLAG_PERMISSION_SYSTEM_FIXED
+ | FLAG_PERMISSION_POLICY_FIXED;
+
+ final int priorityMask = defaultGrantMask | priorityFixedMask;
+
+ final int destFlags = destState.getFlags();
+ final boolean destIsGranted = isEffectivelyGranted(destState);
+
+ final int srcFlags = srcState.getFlags();
+ final boolean srcIsGranted = isEffectivelyGranted(srcState);
+
+ final int combinedFlags = destFlags | srcFlags;
+
+ /* Merge flags */
+
+ int newFlags = 0;
+
+ // Inherit user set flags only from dest as we want to preserve the
+ // user preference of destState, not the one of the current package.
+ newFlags |= (destFlags & userSettableMask);
+
+ // Inherit all exempt flags
+ newFlags |= (combinedFlags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT);
+ // If no exempt flags are set, set APPLY_RESTRICTION
+ if ((newFlags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) {
+ newFlags |= FLAG_PERMISSION_APPLY_RESTRICTION;
+ }
+
+ // Inherit all priority flags
+ newFlags |= (combinedFlags & priorityMask);
+
+ // If no priority flags are set, inherit REVOKE_WHEN_REQUESTED
+ if ((combinedFlags & priorityMask) == 0) {
+ newFlags |= (combinedFlags & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED);
+ }
+
+ // Handle REVIEW_REQUIRED
+ if ((newFlags & priorityFixedMask) == 0) {
+ if (NOTIFICATION_PERMISSIONS.contains(srcState.getName())) {
+ // For notification permissions, inherit from both states
+ // if no priority FIXED flags are set
+ newFlags |= (combinedFlags & FLAG_PERMISSION_REVIEW_REQUIRED);
+ } else if ((newFlags & priorityMask) == 0) {
+ // Else inherit from destState if no priority flags are set
+ newFlags |= (destFlags & FLAG_PERMISSION_REVIEW_REQUIRED);
+ }
+ }
+
+ /* Determine effective grant state */
+
+ final boolean effectivelyGranted;
+ if ((newFlags & FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
+ effectivelyGranted = true;
+ } else if ((destFlags & FLAG_PERMISSION_POLICY_FIXED) != 0) {
+ // If this flag comes from destState, preserve its state
+ effectivelyGranted = destIsGranted;
+ } else if ((srcFlags & FLAG_PERMISSION_POLICY_FIXED) != 0) {
+ effectivelyGranted = destIsGranted || srcIsGranted;
+ // If this flag comes from srcState, preserve flag only if
+ // there is no conflict
+ if (destIsGranted != srcIsGranted) {
+ newFlags &= ~FLAG_PERMISSION_POLICY_FIXED;
+ }
+ } else if ((destFlags & defaultGrantMask) != 0) {
+ // If a permission state has default grant flags and is not
+ // granted, this meant user has overridden the grant state.
+ // Respect the user's preference on destState.
+ // Due to this reason, if this flag comes from destState,
+ // preserve its state
+ effectivelyGranted = destIsGranted;
+ } else if ((srcFlags & defaultGrantMask) != 0) {
+ effectivelyGranted = destIsGranted || srcIsGranted;
+ } else if ((destFlags & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
+ // Similar reason to defaultGrantMask, if this flag comes
+ // from destState, preserve its state
+ effectivelyGranted = destIsGranted;
+ } else if ((srcFlags & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
+ effectivelyGranted = destIsGranted || srcIsGranted;
+ // If this flag comes from srcState, remove this flag if
+ // destState is already granted to prevent revocation.
+ if (destIsGranted) {
+ newFlags &= ~FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+ }
+ } else {
+ // If still not determined, fallback to destState.
+ effectivelyGranted = destIsGranted;
+ }
+
+ /* Post-processing / fix ups */
+
+ if (!effectivelyGranted) {
+ // If not effectively granted, inherit AUTO_REVOKED
+ newFlags |= (combinedFlags & FLAG_PERMISSION_AUTO_REVOKED);
+
+ // REVOKE_WHEN_REQUESTED make no sense when denied
+ newFlags &= ~FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
+ } else {
+ // REVIEW_REQUIRED make no sense when granted
+ newFlags &= ~FLAG_PERMISSION_REVIEW_REQUIRED;
+ }
+
+ if (effectivelyGranted != destIsGranted) {
+ // Remove user set flags if state changes
+ newFlags &= ~userSettableMask;
+ }
+
+ // Fix permission state based on targetSdk of the shared UID
+ final boolean newGrantState;
+ if (!effectivelyGranted && isPermissionSplitFromNonRuntime(
+ srcState.getName(),
+ mPackageManagerInt.getUidTargetSdkVersion(appId))) {
+ // Even though effectively denied, it has to be set to granted
+ // for backwards compatibility
+ newFlags |= FLAG_PERMISSION_REVOKED_COMPAT;
+ newGrantState = true;
+ } else {
+ // Either it's effectively granted, or it targets a high enough API level
+ // to handle this permission properly
+ newGrantState = effectivelyGranted;
+ }
+
+ return new Pair<>(newGrantState, newFlags);
+ }
+
+ /**
+ * This method handles permission migration of packages leaving/joining shared UID
+ */
+ private void handleAppIdMigration(@NonNull AndroidPackage pkg, int previousAppId) {
+ final PackageStateInternal ps =
+ mPackageManagerInt.getPackageStateInternal(pkg.getPackageName());
+
+ if (ps.getSharedUser() != null) {
+ // The package is joining a shared user group. This can only happen when a system
+ // app left shared UID with an update, and then the update is uninstalled.
+ // If no apps remain in its original shared UID group, clone the current
+ // permission state to the shared appId; or else, merge the current permission
+ // state into the shared UID state.
+
+ synchronized (mLock) {
+ for (final int userId : getAllUserIds()) {
+ final UserPermissionState userState = mState.getOrCreateUserState(userId);
+
+ // This is the permission state the package was using
+ final UidPermissionState uidState = userState.getUidState(previousAppId);
+ if (uidState == null) {
+ continue;
+ }
+
+ // This is the shared UID permission state the package wants to join
+ final UidPermissionState sharedUidState = userState.getUidState(ps.getAppId());
+ if (sharedUidState == null) {
+ // No apps remain in the shared UID group, clone permissions
+ userState.createUidStateWithExisting(ps.getAppId(), uidState);
+ } else {
+ final List<PermissionState> states = uidState.getPermissionStates();
+ final int count = states.size();
+ for (int i = 0; i < count; ++i) {
+ final PermissionState srcState = states.get(i);
+ final PermissionState destState =
+ sharedUidState.getPermissionState(srcState.getName());
+ if (destState != null) {
+ // Merge the 2 permission states
+ Pair<Boolean, Integer> newState =
+ mergePermissionState(ps.getAppId(), srcState, destState);
+ sharedUidState.putPermissionState(srcState.getPermission(),
+ newState.first, newState.second);
+ } else {
+ // Simply copy the permission state over
+ sharedUidState.putPermissionState(srcState.getPermission(),
+ srcState.isGranted(), srcState.getFlags());
+ }
+ }
+ }
+
+ // Remove permissions for the previous appId
+ userState.removeUidState(previousAppId);
+ }
+ }
+ } else {
+ // The package is migrating out of a shared user group.
+ // Operations we need to do before calling updatePermissions():
+ // - Retrieve the original uid permission state and create a copy of it as the
+ // new app's uid state. The new permission state will be properly updated in
+ // updatePermissions().
+ // - Remove the app from the original shared user group. Other apps in the shared
+ // user group will perceive as if the original app is uninstalled.
+
final List<AndroidPackage> origSharedUserPackages =
mPackageManagerInt.getPackagesForAppId(previousAppId);
synchronized (mLock) {
- // All users are affected
for (final int userId : getAllUserIds()) {
// Retrieve the original uid state
final UserPermissionState userState = mState.getUserState(userId);
@@ -4679,6 +4892,14 @@
}
}
}
+ }
+
+ private void onPackageInstalledInternal(@NonNull AndroidPackage pkg, int previousAppId,
+ @NonNull PermissionManagerServiceInternal.PackageInstalledParams params,
+ @UserIdInt int[] userIds) {
+ if (previousAppId != Process.INVALID_UID) {
+ handleAppIdMigration(pkg, previousAppId);
+ }
updatePermissions(pkg.getPackageName(), pkg);
for (final int userId : userIds) {
addAllowlistedRestrictedPermissionsInternal(pkg,
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
index 5460afa..56f62ab 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateInternal.java
@@ -23,6 +23,7 @@
import android.util.SparseArray;
import com.android.server.pm.InstallSource;
+import com.android.server.pm.PackageKeySetData;
import com.android.server.pm.SharedUserSetting;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.permission.LegacyPermissionState;
@@ -82,4 +83,7 @@
String getPathString();
float getLoadingProgress();
+
+ @NonNull
+ PackageKeySetData getKeySetData();
}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
index 32a9cf1..6fafb24 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
@@ -28,6 +28,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
import java.util.Objects;
@@ -49,7 +50,6 @@
private boolean mNotLaunched;
private boolean mHidden; // Is the app restricted by owner / admin
private int mDistractionFlags;
- private boolean mSuspended;
private boolean mInstantApp;
private boolean mVirtualPreload;
private int mEnabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@@ -101,7 +101,6 @@
mNotLaunched = other.mNotLaunched;
mHidden = other.mHidden;
mDistractionFlags = other.mDistractionFlags;
- mSuspended = other.mSuspended;
mInstantApp = other.mInstantApp;
mVirtualPreload = other.mVirtualPreload;
mEnabledState = other.mEnabledState;
@@ -256,6 +255,28 @@
return mComponentLabelIconOverrideMap.get(componentName);
}
+ @Override
+ public boolean isSuspended() {
+ return !CollectionUtils.isEmpty(mSuspendParams);
+ }
+
+ public PackageUserStateImpl putSuspendParams(@NonNull String suspendingPackage,
+ @NonNull SuspendParams suspendParams) {
+ if (mSuspendParams == null) {
+ mSuspendParams = new ArrayMap<>();
+ }
+ mSuspendParams.put(suspendingPackage, suspendParams);
+ return this;
+ }
+
+ public PackageUserStateImpl removeSuspension(@NonNull String suspendingPackage) {
+ if (mSuspendParams != null) {
+ mSuspendParams.remove(suspendingPackage);
+ }
+ return this;
+ }
+
+
// Code below generated by codegen v1.0.23.
@@ -312,11 +333,6 @@
}
@DataClass.Generated.Member
- public boolean isSuspended() {
- return mSuspended;
- }
-
- @DataClass.Generated.Member
public boolean isInstantApp() {
return mInstantApp;
}
@@ -433,12 +449,6 @@
}
@DataClass.Generated.Member
- public @NonNull PackageUserStateImpl setSuspended( boolean value) {
- mSuspended = value;
- return this;
- }
-
- @DataClass.Generated.Member
public @NonNull PackageUserStateImpl setInstantApp( boolean value) {
mInstantApp = value;
return this;
@@ -532,7 +542,6 @@
&& mNotLaunched == that.mNotLaunched
&& mHidden == that.mHidden
&& mDistractionFlags == that.mDistractionFlags
- && mSuspended == that.mSuspended
&& mInstantApp == that.mInstantApp
&& mVirtualPreload == that.mVirtualPreload
&& mEnabledState == that.mEnabledState
@@ -563,7 +572,6 @@
_hash = 31 * _hash + Boolean.hashCode(mNotLaunched);
_hash = 31 * _hash + Boolean.hashCode(mHidden);
_hash = 31 * _hash + mDistractionFlags;
- _hash = 31 * _hash + Boolean.hashCode(mSuspended);
_hash = 31 * _hash + Boolean.hashCode(mInstantApp);
_hash = 31 * _hash + Boolean.hashCode(mVirtualPreload);
_hash = 31 * _hash + mEnabledState;
@@ -581,10 +589,10 @@
}
@DataClass.Generated(
- time = 1633983318771L,
+ time = 1636145886996L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java",
- inputSignatures = "protected @android.annotation.Nullable android.util.ArraySet<java.lang.String> mDisabledComponents\nprotected @android.annotation.Nullable android.util.ArraySet<java.lang.String> mEnabledComponents\nprivate long mCeDataInode\nprivate boolean mInstalled\nprivate boolean mStopped\nprivate boolean mNotLaunched\nprivate boolean mHidden\nprivate int mDistractionFlags\nprivate boolean mSuspended\nprivate boolean mInstantApp\nprivate boolean mVirtualPreload\nprivate int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprotected @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.annotation.Nullable android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mCachedOverlayPaths\nprivate @android.annotation.Nullable android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\nclass PackageUserStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageUserStateInternal]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
+ inputSignatures = "protected @android.annotation.Nullable android.util.ArraySet<java.lang.String> mDisabledComponents\nprotected @android.annotation.Nullable android.util.ArraySet<java.lang.String> mEnabledComponents\nprivate long mCeDataInode\nprivate boolean mInstalled\nprivate boolean mStopped\nprivate boolean mNotLaunched\nprivate boolean mHidden\nprivate int mDistractionFlags\nprivate boolean mInstantApp\nprivate boolean mVirtualPreload\nprivate int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprotected @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.annotation.Nullable android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mCachedOverlayPaths\nprivate @android.annotation.Nullable android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\nclass PackageUserStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageUserStateInternal]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
index 6f33312..bd8b3ab 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
@@ -32,6 +32,7 @@
PackageUserStateInternal DEFAULT = new PackageUserStateDefault();
+ // TODO: Make non-null with emptyMap()
@Nullable
ArrayMap<String, SuspendParams> getSuspendParams();
diff --git a/services/core/java/com/android/server/pm/pkg/SuspendParams.java b/services/core/java/com/android/server/pm/pkg/SuspendParams.java
index 71512dc..d24ce96 100644
--- a/services/core/java/com/android/server/pm/pkg/SuspendParams.java
+++ b/services/core/java/com/android/server/pm/pkg/SuspendParams.java
@@ -42,11 +42,15 @@
private static final String TAG_APP_EXTRAS = "app-extras";
private static final String TAG_LAUNCHER_EXTRAS = "launcher-extras";
- public SuspendDialogInfo dialogInfo;
- public PersistableBundle appExtras;
- public PersistableBundle launcherExtras;
+ private final SuspendDialogInfo dialogInfo;
+ private final PersistableBundle appExtras;
+ private final PersistableBundle launcherExtras;
- private SuspendParams() {
+ private SuspendParams(SuspendDialogInfo dialogInfo, PersistableBundle appExtras,
+ PersistableBundle launcherExtras) {
+ this.dialogInfo = dialogInfo;
+ this.appExtras = appExtras;
+ this.launcherExtras = launcherExtras;
}
/**
@@ -60,11 +64,7 @@
if (dialogInfo == null && appExtras == null && launcherExtras == null) {
return null;
}
- final SuspendParams instance = new SuspendParams();
- instance.dialogInfo = dialogInfo;
- instance.appExtras = appExtras;
- instance.launcherExtras = launcherExtras;
- return instance;
+ return new SuspendParams(dialogInfo, appExtras, launcherExtras);
}
@Override
@@ -172,4 +172,16 @@
}
return getInstanceOrNull(readDialogInfo, readAppExtras, readLauncherExtras);
}
+
+ public SuspendDialogInfo getDialogInfo() {
+ return dialogInfo;
+ }
+
+ public PersistableBundle getAppExtras() {
+ return appExtras;
+ }
+
+ public PersistableBundle getLauncherExtras() {
+ return launcherExtras;
+ }
}
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
new file mode 100644
index 0000000..35d4d9e
--- /dev/null
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.pkg.mutate;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.overlay.OverlayPaths;
+import android.util.ArraySet;
+
+import com.android.server.pm.PackageSetting;
+import com.android.server.pm.pkg.PackageUserStateImpl;
+import com.android.server.pm.pkg.SuspendParams;
+
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Function;
+
+public class PackageStateMutator {
+
+ private static final AtomicLong sStateChangeSequence = new AtomicLong();
+
+ private final StateWriteWrapper mStateWrite = new StateWriteWrapper();
+
+ private final Function<String, PackageSetting> mActiveStateFunction;
+ private final Function<String, PackageSetting> mDisabledStateFunction;
+
+ public PackageStateMutator(@NonNull Function<String, PackageSetting> activeStateFunction,
+ @NonNull Function<String, PackageSetting> disabledStateFunction) {
+ mActiveStateFunction = activeStateFunction;
+ mDisabledStateFunction = disabledStateFunction;
+ }
+
+ public static void onPackageStateChanged() {
+ sStateChangeSequence.incrementAndGet();
+ }
+
+ @NonNull
+ public PackageStateWrite forPackage(@NonNull String packageName) {
+ return mStateWrite.setState(mActiveStateFunction.apply(packageName));
+ }
+
+ @Nullable
+ public PackageStateWrite forPackageNullable(@NonNull String packageName) {
+ final PackageSetting packageState = mActiveStateFunction.apply(packageName);
+ mStateWrite.setState(packageState);
+ if (packageState == null) {
+ return null;
+ }
+
+ return mStateWrite.setState(packageState);
+ }
+
+ @NonNull
+ public PackageStateWrite forDisabledSystemPackage(@NonNull String packageName) {
+ return mStateWrite.setState(mDisabledStateFunction.apply(packageName));
+ }
+
+ @Nullable
+ public PackageStateWrite forDisabledSystemPackageNullable(@NonNull String packageName) {
+ final PackageSetting packageState = mDisabledStateFunction.apply(packageName);
+ if (packageState == null) {
+ return null;
+ }
+
+ return mStateWrite.setState(packageState);
+ }
+
+ @NonNull
+ public InitialState initialState(int changedPackagesSequenceNumber) {
+ return new InitialState(changedPackagesSequenceNumber, sStateChangeSequence.get());
+ }
+
+ /**
+ * @return null if initial state is null or if nothing has changed, otherwise return result
+ * with what changed
+ */
+ @Nullable
+ public Result generateResult(@Nullable InitialState state, int changedPackagesSequenceNumber) {
+ if (state == null) {
+ return Result.SUCCESS;
+ }
+
+ boolean packagesChanged = changedPackagesSequenceNumber != state.mPackageSequence;
+ boolean stateChanged = sStateChangeSequence.get() != state.mStateSequence;
+ if (packagesChanged && stateChanged) {
+ return Result.PACKAGES_AND_STATE_CHANGED;
+ } else if (packagesChanged) {
+ return Result.PACKAGES_CHANGED;
+ } else if (stateChanged) {
+ return Result.STATE_CHANGED;
+ } else {
+ return Result.SUCCESS;
+ }
+ }
+
+ public static class InitialState {
+
+ private final int mPackageSequence;
+ private final long mStateSequence;
+
+ public InitialState(int packageSequence, long stateSequence) {
+ mPackageSequence = packageSequence;
+ mStateSequence = stateSequence;
+ }
+ }
+
+ public static class Result {
+
+ public static final Result SUCCESS = new Result(true, false, false, false);
+ public static final Result PACKAGES_CHANGED = new Result(false, true, false, false);
+ public static final Result STATE_CHANGED = new Result(false, false, true, false);
+ public static final Result PACKAGES_AND_STATE_CHANGED = new Result(false, true, true, false);
+ public static final Result SPECIFIC_PACKAGE_NULL = new Result(false, false, true, true);
+
+ private final boolean mCommitted;
+ private final boolean mPackagesChanged;
+ private final boolean mStateChanged;
+ private final boolean mSpecificPackageNull;
+
+ public Result(boolean committed, boolean packagesChanged, boolean stateChanged,
+ boolean specificPackageNull) {
+ mCommitted = committed;
+ mPackagesChanged = packagesChanged;
+ mStateChanged = stateChanged;
+ mSpecificPackageNull = specificPackageNull;
+ }
+
+ public boolean isCommitted() {
+ return mCommitted;
+ }
+
+ public boolean isPackagesChanged() {
+ return mPackagesChanged;
+ }
+
+ public boolean isStateChanged() {
+ return mStateChanged;
+ }
+
+ public boolean isSpecificPackageNull() {
+ return mSpecificPackageNull;
+ }
+ }
+
+ private static class StateWriteWrapper implements PackageStateWrite {
+
+ private final UserStateWriteWrapper mUserStateWrite = new UserStateWriteWrapper();
+
+ @NonNull
+ private PackageSetting mState;
+
+ public StateWriteWrapper setState(PackageSetting state) {
+ this.mState = state;
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public PackageUserStateWrite userState(int userId) {
+ return mUserStateWrite.setStates(
+ mState == null ? null : mState.getOrCreateUserState(userId));
+ }
+
+ @Override
+ public PackageStateWrite setLastPackageUsageTime(int reason, long timeInMillis) {
+ if (mState != null) {
+ mState.getTransientState().setLastPackageUsageTimeInMills(reason, timeInMillis);
+ }
+ return this;
+ }
+
+ @Override
+ public PackageStateWrite setHiddenUntilInstalled(boolean value) {
+ if (mState != null) {
+ mState.getTransientState().setHiddenUntilInstalled(value);
+ }
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public PackageStateWrite setRequiredForSystemUser(boolean requiredForSystemUser) {
+ if (mState != null) {
+ if (requiredForSystemUser) {
+ mState.setPrivateFlags(mState.getPrivateFlags()
+ | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER);
+ } else {
+ mState.setPrivateFlags(mState.getPrivateFlags()
+ & ~ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER);
+ }
+ }
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public PackageStateWrite setMimeGroup(@NonNull String mimeGroup,
+ @NonNull ArraySet<String> mimeTypes) {
+ if (mState != null) {
+ mState.setMimeGroup(mimeGroup, mimeTypes);
+ }
+ return this;
+ }
+
+ private static class UserStateWriteWrapper implements PackageUserStateWrite {
+
+ @Nullable
+ private PackageUserStateImpl mUserState;
+
+ public UserStateWriteWrapper setStates(@Nullable PackageUserStateImpl userState) {
+ mUserState = userState;
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public PackageUserStateWrite setInstalled(boolean installed) {
+ if (mUserState != null) {
+ mUserState.setInstalled(installed);
+ }
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public PackageUserStateWrite setUninstallReason(int reason) {
+ if (mUserState != null) {
+ mUserState.setUninstallReason(reason);
+ }
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public PackageUserStateWrite setDistractionFlags(
+ @PackageManager.DistractionRestriction int restrictionFlags) {
+ if (mUserState != null) {
+ mUserState.setDistractionFlags(restrictionFlags);
+ }
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public PackageUserStateWrite putSuspendParams(@NonNull String suspendingPackage,
+ @Nullable SuspendParams suspendParams) {
+ if (mUserState != null) {
+ mUserState.putSuspendParams(suspendingPackage, suspendParams);
+ }
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public PackageUserStateWrite removeSuspension(@NonNull String suspendingPackage) {
+ if (mUserState != null) {
+ mUserState.removeSuspension(suspendingPackage);
+ }
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public PackageUserStateWrite setHidden(boolean hidden) {
+ if (mUserState != null) {
+ mUserState.setHidden(hidden);
+ }
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public PackageUserStateWrite setStopped(boolean stopped) {
+ if (mUserState != null) {
+ mUserState.setStopped(stopped);
+ }
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public PackageUserStateWrite setNotLaunched(boolean notLaunched) {
+ if (mUserState != null) {
+ mUserState.setNotLaunched(notLaunched);
+ }
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public PackageUserStateWrite setOverlayPaths(@NonNull OverlayPaths overlayPaths) {
+ if (mUserState != null) {
+ mUserState.setOverlayPaths(overlayPaths);
+ }
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public PackageUserStateWrite setOverlayPathsForLibrary(@NonNull String libraryName,
+ @Nullable OverlayPaths overlayPaths) {
+ if (mUserState != null) {
+ mUserState.setSharedLibraryOverlayPaths(libraryName, overlayPaths);
+ }
+ return this;
+ }
+
+ @NonNull
+ @Override
+ public PackageUserStateWrite setHarmfulAppWarning(@Nullable String warning) {
+ if (mUserState != null) {
+ mUserState.setHarmfulAppWarning(warning);
+ }
+ return this;
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java
new file mode 100644
index 0000000..585bece
--- /dev/null
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateWrite.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.pkg.mutate;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.content.pm.PackageManager;
+import android.util.ArraySet;
+
+public interface PackageStateWrite {
+
+ @NonNull
+ PackageUserStateWrite userState(@UserIdInt int userId);
+
+ @NonNull
+ PackageStateWrite setLastPackageUsageTime(@PackageManager.NotifyReason int reason,
+ long timeInMillis);
+
+ @NonNull
+ PackageStateWrite setHiddenUntilInstalled(boolean hiddenUntilInstalled);
+
+ @NonNull
+ PackageStateWrite setRequiredForSystemUser(boolean requiredForSystemUser);
+
+ @NonNull
+ PackageStateWrite setMimeGroup(@NonNull String mimeGroup, @NonNull ArraySet<String> mimeTypes);
+}
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java
new file mode 100644
index 0000000..e23a1b6
--- /dev/null
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.pkg.mutate;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageManager;
+import android.content.pm.overlay.OverlayPaths;
+
+import com.android.server.pm.pkg.SuspendParams;
+
+public interface PackageUserStateWrite {
+
+ @NonNull
+ PackageUserStateWrite setInstalled(boolean installed);
+
+ @NonNull
+ PackageUserStateWrite setUninstallReason(@PackageManager.UninstallReason int reason);
+
+ @NonNull
+ PackageUserStateWrite setDistractionFlags(
+ @PackageManager.DistractionRestriction int restrictionFlags);
+
+ @NonNull
+ PackageUserStateWrite putSuspendParams(@NonNull String suspendingPackage,
+ @Nullable SuspendParams suspendParams);
+
+ @NonNull
+ PackageUserStateWrite removeSuspension(@NonNull String suspendingPackage);
+
+ @NonNull
+ PackageUserStateWrite setHidden(boolean hidden);
+
+ @NonNull
+ PackageUserStateWrite setStopped(boolean stopped);
+
+ @NonNull
+ PackageUserStateWrite setNotLaunched(boolean notLaunched);
+
+ @NonNull
+ PackageUserStateWrite setOverlayPaths(@Nullable OverlayPaths overlayPaths);
+
+ @NonNull
+ PackageUserStateWrite setOverlayPathsForLibrary(@NonNull String libraryName,
+ @Nullable OverlayPaths overlayPaths);
+
+ @NonNull
+ PackageUserStateWrite setHarmfulAppWarning(@Nullable String warning);
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 298f102..4cced17 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -363,6 +363,12 @@
public static final int TOAST_WINDOW_TIMEOUT = 3500 + TOAST_WINDOW_ANIM_BUFFER;
/**
+ * Action for launching assistant in retail mode
+ */
+ private static final String ACTION_VOICE_ASSIST_RETAIL =
+ "android.intent.action.VOICE_ASSIST_RETAIL";
+
+ /**
* Lock protecting internal state. Must not call out into window
* manager with lock held. (This lock will be acquired in places
* where the window manager is calling in with its own lock held.)
@@ -1090,29 +1096,35 @@
mPowerManager.boostScreenBrightness(eventTime);
break;
case MULTI_PRESS_POWER_LAUNCH_TARGET_ACTIVITY:
- if (DEBUG_INPUT) {
- Slog.d(TAG, "Executing the double press power action.");
- }
+ launchTargetActivityOnMultiPressPower();
+ break;
+ }
+ }
+
+ private void launchTargetActivityOnMultiPressPower() {
+ if (DEBUG_INPUT) {
+ Slog.d(TAG, "Executing the double press power action.");
+ }
+ if (mPowerDoublePressTargetActivity != null) {
+ Intent intent = new Intent();
+ intent.setComponent(mPowerDoublePressTargetActivity);
+ ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(
+ intent, /* flags= */0);
+ if (resolveInfo != null) {
final boolean keyguardActive =
mKeyguardDelegate != null && mKeyguardDelegate.isShowing();
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
if (!keyguardActive) {
- Intent intent = new Intent();
- if (mPowerDoublePressTargetActivity != null) {
- intent.setComponent(mPowerDoublePressTargetActivity);
- ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(
- intent, /* flags= */0);
- if (resolveInfo != null) {
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
- } else {
- Slog.e(TAG, "Could not resolve activity with : "
- + mPowerDoublePressTargetActivity.flattenToString()
- + " name.");
- }
- }
+ startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+ } else {
+ mKeyguardDelegate.dismissKeyguardToLaunch(intent);
}
- break;
+ } else {
+ Slog.e(TAG, "Could not resolve activity with : "
+ + mPowerDoublePressTargetActivity.flattenToString()
+ + " name.");
+ }
}
}
@@ -1242,6 +1254,12 @@
return LONG_PRESS_POWER_GLOBAL_ACTIONS;
}
+ // If long press to launch assistant is disabled in settings, do nothing.
+ if (mLongPressOnPowerBehavior == LONG_PRESS_POWER_GO_TO_VOICE_ASSIST
+ && !isLongPressToAssistantEnabled(mContext)) {
+ return LONG_PRESS_POWER_NOTHING;
+ }
+
return mLongPressOnPowerBehavior;
}
@@ -1273,6 +1291,9 @@
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+ } else {
+ // If keyguarded then notify the keyguard.
+ mKeyguardDelegate.onSystemKeyPressed(KeyEvent.KEYCODE_STEM_PRIMARY);
}
break;
}
@@ -3218,17 +3239,50 @@
.getSystemService(Context.SEARCH_SERVICE)).launchAssist(args);
}
- /** Launches ACTION_VOICE_ASSIST. Does nothing on keyguard. */
+ /**
+ * Launches ACTION_VOICE_ASSIST_RETAIL if in retail mode, or ACTION_VOICE_ASSIST otherwise
+ * Does nothing on keyguard except for watches. Delegates it to keyguard if present on watch.
+ */
private void launchVoiceAssist(boolean allowDuringSetup) {
- final boolean keyguardActive = mKeyguardDelegate == null
- ? false
- : mKeyguardDelegate.isShowing();
+ final boolean keyguardActive =
+ mKeyguardDelegate != null && mKeyguardDelegate.isShowing();
if (!keyguardActive) {
- Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
- startActivityAsUser(intent, null, UserHandle.CURRENT_OR_SELF,
- allowDuringSetup);
+ if (mHasFeatureWatch && isInRetailMode()) {
+ launchRetailVoiceAssist(allowDuringSetup);
+ } else {
+ startVoiceAssistIntent(allowDuringSetup);
+ }
+ } else {
+ mKeyguardDelegate.dismissKeyguardToLaunch(new Intent(Intent.ACTION_VOICE_ASSIST));
}
+ }
+ private void launchRetailVoiceAssist(boolean allowDuringSetup) {
+ Intent retailIntent = new Intent(ACTION_VOICE_ASSIST_RETAIL);
+ ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(
+ retailIntent, /* flags= */0);
+ if (resolveInfo != null) {
+ retailIntent.setComponent(
+ new ComponentName(resolveInfo.activityInfo.packageName,
+ resolveInfo.activityInfo.name));
+ startActivityAsUser(retailIntent, null, UserHandle.CURRENT_OR_SELF,
+ allowDuringSetup);
+ } else {
+ Slog.w(TAG, "Couldn't find an app to process " + ACTION_VOICE_ASSIST_RETAIL
+ + ". Fall back to start " + Intent.ACTION_VOICE_ASSIST);
+ startVoiceAssistIntent(allowDuringSetup);
+ }
+ }
+
+ private void startVoiceAssistIntent(boolean allowDuringSetup) {
+ Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
+ startActivityAsUser(intent, null, UserHandle.CURRENT_OR_SELF,
+ allowDuringSetup);
+ }
+
+ private boolean isInRetailMode() {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.DEVICE_DEMO_MODE, 0) == 1;
}
private void startActivityAsUser(Intent intent, UserHandle handle) {
@@ -5824,6 +5878,18 @@
}
}
+ public static boolean isLongPressToAssistantEnabled(Context context) {
+ ContentResolver resolver = context.getContentResolver();
+ int longPressToAssistant = Settings.System.getIntForUser(resolver,
+ Settings.Global.Wearable.CLOCKWORK_LONG_PRESS_TO_ASSISTANT_ENABLED,
+ /* def= */ 1,
+ UserHandle.USER_CURRENT);
+ if(Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "longPressToAssistant = " + longPressToAssistant);
+ }
+ return (longPressToAssistant == 1);
+ }
+
private class HdmiVideoExtconUEventObserver extends ExtconStateObserver<Boolean> {
private static final String HDMI_EXIST = "HDMI=1";
private static final String NAME = "hdmi";
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 0080ec6..97a57e0 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -415,6 +415,17 @@
}
}
+ public void dismissKeyguardToLaunch(Intent intentToLaunch) {
+ if (mKeyguardService != null) {
+ mKeyguardService.dismissKeyguardToLaunch(intentToLaunch);
+ }
+ }
+ public void onSystemKeyPressed(int keycode) {
+ if (mKeyguardService != null) {
+ mKeyguardService.onSystemKeyPressed(keycode);
+ }
+ }
+
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(SHOWING, mKeyguardState.showing);
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index 2029f86..774e261 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -17,6 +17,7 @@
package com.android.server.policy.keyguard;
import android.content.Context;
+import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
@@ -254,6 +255,24 @@
}
}
+ @Override
+ public void dismissKeyguardToLaunch(Intent intentToLaunch) {
+ try {
+ mService.dismissKeyguardToLaunch(intentToLaunch);
+ } catch (RemoteException e) {
+ Slog.w(TAG , "Remote Exception", e);
+ }
+ }
+
+ @Override
+ public void onSystemKeyPressed(int keycode) {
+ try {
+ mService.onSystemKeyPressed(keycode);
+ } catch (RemoteException e) {
+ Slog.w(TAG , "Remote Exception", e);
+ }
+ }
+
@Override // Binder interface
public IBinder asBinder() {
return mService.asBinder();
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java b/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java
index 7f047f8..fba0fb4 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java
@@ -20,8 +20,6 @@
import android.annotation.Nullable;
import java.lang.reflect.Array;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Map;
@@ -33,67 +31,28 @@
static public final int kDefaultMaxCollectionLength = 16;
/**
- * Simple version of {@link #print(Object, boolean, int)} that prints an object, without
- * recursing into sub-objects.
- *
- * @param obj The object to print.
- * @return A string representing the object.
- */
- static String print(@Nullable Object obj) {
- return print(obj, false, kDefaultMaxCollectionLength);
- }
-
- /**
* Pretty-prints an object.
*
* @param obj The object to print.
- * @param deep Whether to pretty-print sub-objects (if false, just prints them
- * with {@link Object#toString()}).
* @param maxCollectionLength Whenever encountering collections, maximum number of elements to
* print.
* @return A string representing the object.
*/
- static String print(@Nullable Object obj, boolean deep, int maxCollectionLength) {
+ static String print(@Nullable Object obj, int maxCollectionLength) {
StringBuilder builder = new StringBuilder();
- print(builder, obj, deep, maxCollectionLength);
+ print(builder, obj, maxCollectionLength);
return builder.toString();
}
/**
- * This version is suitable for use inside a toString() override of an object, e.g.:
- * <pre><code>
- * class MyObject {
- * ...
- * @Override
- * String toString() {
- * return ObjectPrinter.printPublicFields(this, ...);
- * }
- * }
- * </code></pre>
- *
- * @param obj The object to print.
- * @param deep Whether to pretty-print sub-objects (if false, just prints them
- * with {@link Object#toString()}).
- * @param maxCollectionLength Whenever encountering collections, maximum number of elements to
- * print.
- */
- static String printPublicFields(@Nullable Object obj, boolean deep, int maxCollectionLength) {
- StringBuilder builder = new StringBuilder();
- printPublicFields(builder, obj, deep, maxCollectionLength);
- return builder.toString();
- }
-
- /**
- * A version of {@link #print(Object, boolean, int)} that uses a {@link StringBuilder}.
+ * A version of {@link #print(Object, int)} that uses a {@link StringBuilder}.
*
* @param builder StringBuilder to print into.
* @param obj The object to print.
- * @param deep Whether to pretty-print sub-objects (if false, just prints them
- * with {@link Object#toString()}).
* @param maxCollectionLength Whenever encountering collections, maximum number of elements to
* print.
*/
- static void print(@NonNull StringBuilder builder, @Nullable Object obj, boolean deep,
+ static void print(@NonNull StringBuilder builder, @Nullable Object obj,
int maxCollectionLength) {
try {
if (obj == null) {
@@ -101,16 +60,16 @@
return;
}
if (obj instanceof Boolean) {
- builder.append(obj.toString());
+ builder.append(obj);
return;
}
if (obj instanceof Number) {
- builder.append(obj.toString());
+ builder.append(obj);
return;
}
if (obj instanceof Character) {
builder.append('\'');
- builder.append(obj.toString());
+ builder.append(obj);
builder.append('\'');
return;
}
@@ -137,7 +96,7 @@
isLong = true;
break;
}
- print(builder, child, deep, maxCollectionLength);
+ print(builder, child, maxCollectionLength);
++i;
}
if (isLong) {
@@ -163,9 +122,9 @@
isLong = true;
break;
}
- print(builder, child.getKey(), deep, maxCollectionLength);
+ print(builder, child.getKey(), maxCollectionLength);
builder.append(": ");
- print(builder, child.getValue(), deep, maxCollectionLength);
+ print(builder, child.getValue(), maxCollectionLength);
++i;
}
if (isLong) {
@@ -189,7 +148,7 @@
isLong = true;
break;
}
- print(builder, Array.get(obj, i), deep, maxCollectionLength);
+ print(builder, Array.get(obj, i), maxCollectionLength);
}
if (isLong) {
builder.append("... (+");
@@ -200,48 +159,7 @@
return;
}
- if (!deep) {
- builder.append(obj.toString());
- return;
- }
- printPublicFields(builder, obj, deep, maxCollectionLength);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * A version of {@link #printPublicFields(Object, boolean, int)} that uses a {@link
- * StringBuilder}.
- *
- * @param obj The object to print.
- * @param deep Whether to pretty-print sub-objects (if false, just prints them
- * with {@link Object#toString()}).
- * @param maxCollectionLength Whenever encountering collections, maximum number of elements to
- * print.
- */
- static void printPublicFields(@NonNull StringBuilder builder, @Nullable Object obj,
- boolean deep,
- int maxCollectionLength) {
- try {
- Class cls = obj.getClass();
- builder.append("{ ");
-
- boolean first = true;
- for (Field fld : cls.getDeclaredFields()) {
- int mod = fld.getModifiers();
- if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.STATIC) == 0) {
- if (first) {
- first = false;
- } else {
- builder.append(", ");
- }
- builder.append(fld.getName());
- builder.append(": ");
- print(builder, fld.get(obj), deep, maxCollectionLength);
- }
- }
- builder.append(" }");
+ builder.append(obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
index 559e777..dc4bdaa 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
@@ -18,14 +18,14 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.media.permission.Identity;
+import android.media.permission.IdentityContext;
import android.media.soundtrigger.ModelParameterRange;
import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.RecognitionConfig;
import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.SoundModel;
-import android.media.permission.Identity;
-import android.media.permission.IdentityContext;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
@@ -387,7 +387,7 @@
}
private static void printObject(@NonNull StringBuilder builder, @Nullable Object obj) {
- ObjectPrinter.print(builder, obj, true, 16);
+ ObjectPrinter.print(builder, obj, 16);
}
private static String printObject(@Nullable Object obj) {
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
index 76927e1..f3d151f 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
@@ -21,9 +21,11 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.AppOpsManager;
import android.content.Context;
import android.content.PermissionChecker;
+import android.media.permission.Identity;
+import android.media.permission.IdentityContext;
+import android.media.permission.PermissionUtil;
import android.media.soundtrigger.ModelParameterRange;
import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
@@ -31,9 +33,6 @@
import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.Status;
-import android.media.permission.Identity;
-import android.media.permission.IdentityContext;
-import android.media.permission.PermissionUtil;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
@@ -144,7 +143,7 @@
if (status != PermissionChecker.PERMISSION_GRANTED) {
throw new SecurityException(
String.format("Failed to obtain permission %s for identity %s", permission,
- ObjectPrinter.print(identity, true, 16)));
+ ObjectPrinter.print(identity, 16)));
}
}
@@ -168,7 +167,7 @@
case PermissionChecker.PERMISSION_HARD_DENIED:
throw new SecurityException(
String.format("Failed to obtain permission %s for identity %s", permission,
- ObjectPrinter.print(identity, true, 16)));
+ ObjectPrinter.print(identity, 16)));
default:
throw new RuntimeException("Unexpected perimission check result.");
}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
index 4243fc7..09035cd 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -18,6 +18,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.media.permission.Identity;
+import android.media.permission.IdentityContext;
import android.media.soundtrigger.ModelParameterRange;
import android.media.soundtrigger.PhraseRecognitionEvent;
import android.media.soundtrigger.PhraseSoundModel;
@@ -27,8 +29,6 @@
import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.Status;
-import android.media.permission.Identity;
-import android.media.permission.IdentityContext;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
@@ -230,7 +230,7 @@
final ModuleState module = mModules.get(handle);
pw.println("=========================================");
pw.printf("Module %d\n%s\n", handle,
- ObjectPrinter.print(module.properties, true, 16));
+ ObjectPrinter.print(module.properties, 16));
pw.println("=========================================");
for (Session session : module.sessions) {
session.dump(pw);
@@ -250,11 +250,11 @@
/** State of a sound model. */
static class ModelState {
ModelState(SoundModel model) {
- this.description = ObjectPrinter.print(model, true, 16);
+ this.description = ObjectPrinter.print(model, 16);
}
ModelState(PhraseSoundModel model) {
- this.description = ObjectPrinter.print(model, true, 16);
+ this.description = ObjectPrinter.print(model, 16);
}
/** Activity state of a sound model. */
@@ -690,8 +690,8 @@
if (mState == ModuleStatus.ALIVE) {
pw.println("-------------------------------");
pw.printf("Session %s, client: %s\n", toString(),
- ObjectPrinter.print(mOriginatorIdentity, true, 16));
- pw.printf("Loaded models (handle, active, description):", toString());
+ ObjectPrinter.print(mOriginatorIdentity, 16));
+ pw.println("Loaded models (handle, active, description):");
pw.println();
pw.println("-------------------------------");
for (Map.Entry<Integer, ModelState> entry : mLoadedModels.entrySet()) {
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index da56824..3093509 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -75,10 +75,12 @@
*/
public static final String EXTRA_SEQUENCE = "seq";
- private static final int MSG_CHECK = 1;
+ private static final int MSG_CHECK_LOW = 1;
+ private static final int MSG_CHECK_HIGH = 2;
private static final long DEFAULT_LOG_DELTA_BYTES = DataUnit.MEBIBYTES.toBytes(64);
- private static final long DEFAULT_CHECK_INTERVAL = DateUtils.MINUTE_IN_MILLIS;
+ private static final long LOW_CHECK_INTERVAL = DateUtils.MINUTE_IN_MILLIS;
+ private static final long HIGH_CHECK_INTERVAL = 10 * DateUtils.HOUR_IN_MILLIS;
// com.android.internal.R.string.low_internal_storage_view_text_no_boot
// hard codes 250MB in the message as the storage space required for the
@@ -165,12 +167,12 @@
}
/**
- * Core logic that checks the storage state of every mounted private volume.
- * Since this can do heavy I/O, callers should invoke indirectly using
- * {@link #MSG_CHECK}.
+ * Core logic that checks the storage state of every mounted private volume and clears cache
+ * under low storage state. Since this can do heavy I/O, callers should invoke indirectly using
+ * {@link #MSG_CHECK_LOW}.
*/
@WorkerThread
- private void check() {
+ private void checkLow() {
final StorageManager storage = getContext().getSystemService(StorageManager.class);
final int seq = mSeq.get();
@@ -234,9 +236,45 @@
// Loop around to check again in future; we don't remove messages since
// there might be an immediate request pending.
- if (!mHandler.hasMessages(MSG_CHECK)) {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK),
- DEFAULT_CHECK_INTERVAL);
+ if (!mHandler.hasMessages(MSG_CHECK_LOW)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_LOW),
+ LOW_CHECK_INTERVAL);
+ }
+ if (!mHandler.hasMessages(MSG_CHECK_HIGH)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_HIGH),
+ HIGH_CHECK_INTERVAL);
+ }
+ }
+
+ /**
+ * Core logic that checks the storage state of every mounted private volume and clears cache if
+ * free space is under 20% of total space. Since this can do heavy I/O, callers should invoke
+ * indirectly using {@link #MSG_CHECK_HIGH}.
+ */
+ @WorkerThread
+ private void checkHigh() {
+ final StorageManager storage = getContext().getSystemService(StorageManager.class);
+ // Check every mounted private volume to see if they're under the high storage threshold
+ // which is StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH of total space
+ for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
+ final File file = vol.getPath();
+ if (file.getUsableSpace() < file.getTotalSpace()
+ * StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH / 100) {
+ final PackageManagerService pms = (PackageManagerService) ServiceManager
+ .getService("package");
+ try {
+ pms.freeAllAppCacheAboveQuota(vol.getFsUuid());
+ } catch (IOException e) {
+ Slog.w(TAG, e);
+ }
+ }
+ }
+
+ // Loop around to check again in future; we don't remove messages since
+ // there might be an immediate request pending
+ if (!mHandler.hasMessages(MSG_CHECK_HIGH)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_HIGH),
+ HIGH_CHECK_INTERVAL);
}
}
@@ -250,8 +288,11 @@
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_CHECK:
- check();
+ case MSG_CHECK_LOW:
+ checkLow();
+ return;
+ case MSG_CHECK_HIGH:
+ checkHigh();
return;
}
}
@@ -282,16 +323,16 @@
publishLocalService(DeviceStorageMonitorInternal.class, mLocalService);
// Kick off pass to examine storage state
- mHandler.removeMessages(MSG_CHECK);
- mHandler.obtainMessage(MSG_CHECK).sendToTarget();
+ mHandler.removeMessages(MSG_CHECK_LOW);
+ mHandler.obtainMessage(MSG_CHECK_LOW).sendToTarget();
}
private final DeviceStorageMonitorInternal mLocalService = new DeviceStorageMonitorInternal() {
@Override
public void checkMemory() {
// Kick off pass to examine storage state
- mHandler.removeMessages(MSG_CHECK);
- mHandler.obtainMessage(MSG_CHECK).sendToTarget();
+ mHandler.removeMessages(MSG_CHECK_LOW);
+ mHandler.obtainMessage(MSG_CHECK_LOW).sendToTarget();
}
@Override
@@ -360,8 +401,8 @@
mForceLevel = State.LEVEL_LOW;
int seq = mSeq.incrementAndGet();
if ((opts & OPTION_FORCE_UPDATE) != 0) {
- mHandler.removeMessages(MSG_CHECK);
- mHandler.obtainMessage(MSG_CHECK).sendToTarget();
+ mHandler.removeMessages(MSG_CHECK_LOW);
+ mHandler.obtainMessage(MSG_CHECK_LOW).sendToTarget();
pw.println(seq);
}
} break;
@@ -372,8 +413,8 @@
mForceLevel = State.LEVEL_NORMAL;
int seq = mSeq.incrementAndGet();
if ((opts & OPTION_FORCE_UPDATE) != 0) {
- mHandler.removeMessages(MSG_CHECK);
- mHandler.obtainMessage(MSG_CHECK).sendToTarget();
+ mHandler.removeMessages(MSG_CHECK_LOW);
+ mHandler.obtainMessage(MSG_CHECK_LOW).sendToTarget();
pw.println(seq);
}
} break;
@@ -384,8 +425,8 @@
mForceLevel = State.LEVEL_UNKNOWN;
int seq = mSeq.incrementAndGet();
if ((opts & OPTION_FORCE_UPDATE) != 0) {
- mHandler.removeMessages(MSG_CHECK);
- mHandler.obtainMessage(MSG_CHECK).sendToTarget();
+ mHandler.removeMessages(MSG_CHECK_LOW);
+ mHandler.obtainMessage(MSG_CHECK_LOW).sendToTarget();
pw.println(seq);
}
} break;
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 7e36f89..568e4b8 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -44,6 +44,8 @@
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.media.PlaybackParams;
+import android.media.tv.AdRequest;
+import android.media.tv.AdResponse;
import android.media.tv.AitInfo;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.BroadcastInfoResponse;
@@ -92,6 +94,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
@@ -1178,6 +1181,91 @@
}
@Override
+ public List<String> getAvailableExtensionInterfaceNames(String inputId, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int resolvedUserId = resolveCallingUserId(callingPid, callingUid,
+ userId, "getAvailableExtensionInterfaceNames");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ ITvInputService service = null;
+ synchronized (mLock) {
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
+ TvInputState inputState = userState.inputMap.get(inputId);
+ if (inputState != null) {
+ ServiceState serviceState =
+ userState.serviceStateMap.get(inputState.info.getComponent());
+ if (serviceState != null && serviceState.isHardware
+ && serviceState.service != null) {
+ service = serviceState.service;
+ }
+ }
+ }
+ try {
+ if (service != null) {
+ List<String> interfaces = new ArrayList<>();
+ for (final String name : CollectionUtils.emptyIfNull(
+ service.getAvailableExtensionInterfaceNames())) {
+ String permission = service.getExtensionInterfacePermission(name);
+ if (permission == null
+ || mContext.checkPermission(permission, callingPid, callingUid)
+ == PackageManager.PERMISSION_GRANTED) {
+ interfaces.add(name);
+ }
+ }
+ return interfaces;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in getAvailableExtensionInterfaceNames "
+ + "or getExtensionInterfacePermission", e);
+ }
+ return new ArrayList<>();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public IBinder getExtensionInterface(String inputId, String name, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int resolvedUserId = resolveCallingUserId(callingPid, callingUid,
+ userId, "getExtensionInterface");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ ITvInputService service = null;
+ synchronized (mLock) {
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
+ TvInputState inputState = userState.inputMap.get(inputId);
+ if (inputState != null) {
+ ServiceState serviceState =
+ userState.serviceStateMap.get(inputState.info.getComponent());
+ if (serviceState != null && serviceState.isHardware
+ && serviceState.service != null) {
+ service = serviceState.service;
+ }
+ }
+ }
+ try {
+ if (service != null) {
+ String permission = service.getExtensionInterfacePermission(name);
+ if (permission == null
+ || mContext.checkPermission(permission, callingPid, callingUid)
+ == PackageManager.PERMISSION_GRANTED) {
+ return service.getExtensionInterface(name);
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in getExtensionInterfacePermission "
+ + "or getExtensionInterface", e);
+ }
+ return null;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public List<TvContentRatingSystemInfo> getTvContentRatingSystemList(int userId) {
if (mContext.checkCallingPermission(
android.Manifest.permission.READ_CONTENT_RATING_SYSTEMS)
@@ -2382,6 +2470,50 @@
}
} finally {
Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void removeBroadcastInfo(IBinder sessionToken, int requestId, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int resolvedUserId = resolveCallingUserId(callingPid, callingUid,
+ userId, "removeBroadcastInfo");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
+ resolvedUserId);
+ getSessionLocked(sessionState).removeBroadcastInfo(requestId);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slog.e(TAG, "error in removeBroadcastInfo", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void requestAd(IBinder sessionToken, AdRequest request, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int resolvedUserId = resolveCallingUserId(callingPid, callingUid,
+ userId, "requestAd");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
+ resolvedUserId);
+ getSessionLocked(sessionState).requestAd(request);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slog.e(TAG, "error in requestAd", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
};
}
@@ -3449,6 +3581,23 @@
}
}
}
+
+ @Override
+ public void onAdResponse (AdResponse response) {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slog.d(TAG, "onAdResponse()");
+ }
+ if (mSessionState.session == null || mSessionState.client == null) {
+ return;
+ }
+ try {
+ mSessionState.client.onAdResponse(response, mSessionState.seq);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in onAdResponse", e);
+ }
+ }
+ }
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
index d70f970..a2bf2fe 100644
--- a/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
@@ -29,8 +29,11 @@
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.graphics.Rect;
+import android.media.tv.AdRequest;
+import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.BroadcastInfoResponse;
+import android.media.tv.TvTrackInfo;
import android.media.tv.interactive.ITvIAppClient;
import android.media.tv.interactive.ITvIAppManager;
import android.media.tv.interactive.ITvIAppManagerCallback;
@@ -157,6 +160,7 @@
}
iAppState.mInfo = info;
iAppState.mUid = getIAppUid(info);
+ iAppState.mComponentName = info.getComponent();
iAppMap.put(iAppServiceId, iAppState);
iAppState.mIAppNumber = count;
}
@@ -652,11 +656,13 @@
serviceState = new ServiceState(
componentName, tiasId, resolvedUserId, true, type);
userState.mServiceStateMap.put(componentName, serviceState);
+ updateServiceConnectionLocked(componentName, resolvedUserId);
} else if (serviceState.mService != null) {
serviceState.mService.prepare(type);
} else {
serviceState.mPendingPrepare = true;
serviceState.mPendingPrepareType = type;
+ updateServiceConnectionLocked(componentName, resolvedUserId);
}
}
} catch (RemoteException e) {
@@ -687,10 +693,12 @@
componentName, tiasId, resolvedUserId);
serviceState.addPendingAppLink(appLinkInfo);
userState.mServiceStateMap.put(componentName, serviceState);
+ updateServiceConnectionLocked(componentName, resolvedUserId);
} else if (serviceState.mService != null) {
serviceState.mService.notifyAppLinkInfo(appLinkInfo);
} else {
serviceState.addPendingAppLink(appLinkInfo);
+ updateServiceConnectionLocked(componentName, resolvedUserId);
}
}
} catch (RemoteException e) {
@@ -844,13 +852,67 @@
}
@Override
+ public void notifyTrackSelected(IBinder sessionToken, int type, String trackId,
+ int userId) {
+ if (DEBUG) {
+ Slogf.d(TAG, "notifyTrackSelected(sessionToken=" + sessionToken
+ + ", type=" + type + ", trackId=" + trackId + ")");
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "notifyTrackSelected");
+ SessionState sessionState = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ sessionState = getSessionStateLocked(sessionToken, callingUid,
+ resolvedUserId);
+ getSessionLocked(sessionState).notifyTrackSelected(type, trackId);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in notifyTrackSelected", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void notifyTracksChanged(IBinder sessionToken, List<TvTrackInfo> tracks,
+ int userId) {
+ if (DEBUG) {
+ Slogf.d(TAG, "notifyTracksChanged(sessionToken=" + sessionToken
+ + ", tracks=" + tracks + ")");
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "notifyTracksChanged");
+ SessionState sessionState = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ sessionState = getSessionStateLocked(sessionToken, callingUid,
+ resolvedUserId);
+ getSessionLocked(sessionState).notifyTracksChanged(tracks);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in notifyTracksChanged", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void startIApp(IBinder sessionToken, int userId) {
if (DEBUG) {
Slogf.d(TAG, "BinderService#start(userId=%d)", userId);
}
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
- userId, "notifyTuned");
+ userId, "startIApp");
SessionState sessionState = null;
final long identity = Binder.clearCallingIdentity();
try {
@@ -869,6 +931,183 @@
}
@Override
+ public void stopIApp(IBinder sessionToken, int userId) {
+ if (DEBUG) {
+ Slogf.d(TAG, "BinderService#stop(userId=%d)", userId);
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "stopIApp");
+ SessionState sessionState = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ sessionState = getSessionStateLocked(sessionToken, callingUid,
+ resolvedUserId);
+ getSessionLocked(sessionState).stopIApp();
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in stop", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void createBiInteractiveApp(
+ IBinder sessionToken, Uri biIAppUri, Bundle params, int userId) {
+ if (DEBUG) {
+ Slogf.d(TAG, "createBiInteractiveApp(biIAppUri=%s,params=%s)", biIAppUri, params);
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "createBiInteractiveApp");
+ SessionState sessionState = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ sessionState = getSessionStateLocked(sessionToken, callingUid,
+ resolvedUserId);
+ getSessionLocked(sessionState).createBiInteractiveApp(
+ biIAppUri, params);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in createBiInteractiveApp", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void destroyBiInteractiveApp(IBinder sessionToken, String biIAppId, int userId) {
+ if (DEBUG) {
+ Slogf.d(TAG, "destroyBiInteractiveApp(biIAppId=%s)", biIAppId);
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "destroyBiInteractiveApp");
+ SessionState sessionState = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ sessionState = getSessionStateLocked(sessionToken, callingUid,
+ resolvedUserId);
+ getSessionLocked(sessionState).destroyBiInteractiveApp(biIAppId);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in destroyBiInteractiveApp", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void sendCurrentChannelUri(IBinder sessionToken, Uri channelUri, int userId) {
+ if (DEBUG) {
+ Slogf.d(TAG, "sendCurrentChannelUri(channelUri=%s)", channelUri.toString());
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "sendCurrentChannelUri");
+ SessionState sessionState = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ sessionState = getSessionStateLocked(sessionToken, callingUid,
+ resolvedUserId);
+ getSessionLocked(sessionState).sendCurrentChannelUri(channelUri);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in sendCurrentChannelUri", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void sendCurrentChannelLcn(IBinder sessionToken, int lcn, int userId) {
+ if (DEBUG) {
+ Slogf.d(TAG, "sendCurrentChannelLcn(lcn=%d)", lcn);
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "sendCurrentChannelLcn");
+ SessionState sessionState = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ sessionState = getSessionStateLocked(sessionToken, callingUid,
+ resolvedUserId);
+ getSessionLocked(sessionState).sendCurrentChannelLcn(lcn);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in sendCurrentChannelLcn", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void sendStreamVolume(IBinder sessionToken, float volume, int userId) {
+ if (DEBUG) {
+ Slogf.d(TAG, "sendStreamVolume(volume=%f)", volume);
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "sendStreamVolume");
+ SessionState sessionState = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ sessionState = getSessionStateLocked(sessionToken, callingUid,
+ resolvedUserId);
+ getSessionLocked(sessionState).sendStreamVolume(volume);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in sendStreamVolume", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void sendTrackInfoList(IBinder sessionToken, List<TvTrackInfo> tracks, int userId) {
+ if (DEBUG) {
+ Slogf.d(TAG, "sendTrackInfoList(tracks=%s)", tracks.toString());
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "sendTrackInfoList");
+ SessionState sessionState = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ sessionState = getSessionStateLocked(sessionToken, callingUid,
+ resolvedUserId);
+ getSessionLocked(sessionState).sendTrackInfoList(tracks);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in sendTrackInfoList", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void setSurface(IBinder sessionToken, Surface surface, int userId) {
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
@@ -941,6 +1180,28 @@
}
@Override
+ public void notifyAdResponse(IBinder sessionToken, AdResponse response, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
+ "notifyAdResponse");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
+ resolvedUserId);
+ getSessionLocked(sessionState).notifyAdResponse(response);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in notifyAdResponse", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void registerCallback(final ITvIAppManagerCallback callback, int userId) {
int callingPid = Binder.getCallingPid();
int callingUid = Binder.getCallingUid();
@@ -1164,7 +1425,8 @@
serviceState.mReconnecting = false;
}
- boolean shouldBind = !serviceState.mSessionTokens.isEmpty();
+ boolean shouldBind = (!serviceState.mSessionTokens.isEmpty())
+ || (serviceState.mPendingPrepare) || (!serviceState.mPendingAppLinkInfo.isEmpty());
if (serviceState.mService == null && shouldBind) {
// This means that the service is not yet connected but its state indicates that we
@@ -1549,6 +1811,23 @@
}
@Override
+ public void onRemoveBroadcastInfo(int requestId) {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slogf.d(TAG, "onRemoveBroadcastInfo (requestId=" + requestId + ")");
+ }
+ if (mSessionState.mSession == null || mSessionState.mClient == null) {
+ return;
+ }
+ try {
+ mSessionState.mClient.onRemoveBroadcastInfo(requestId, mSessionState.mSeq);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, "error in onRemoveBroadcastInfo", e);
+ }
+ }
+ }
+
+ @Override
public void onCommandRequest(@TvIAppService.IAppServiceCommandType String cmdType,
Bundle parameters) {
synchronized (mLock) {
@@ -1568,6 +1847,108 @@
}
@Override
+ public void onSetVideoBounds(Rect rect) {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slogf.d(TAG, "onSetVideoBounds(rect=" + rect + ")");
+ }
+ if (mSessionState.mSession == null || mSessionState.mClient == null) {
+ return;
+ }
+ try {
+ mSessionState.mClient.onSetVideoBounds(rect, mSessionState.mSeq);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, "error in onSetVideoBounds", e);
+ }
+ }
+ }
+
+ @Override
+ public void onRequestCurrentChannelUri() {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slogf.d(TAG, "onRequestCurrentChannelUri");
+ }
+ if (mSessionState.mSession == null || mSessionState.mClient == null) {
+ return;
+ }
+ try {
+ mSessionState.mClient.onRequestCurrentChannelUri(mSessionState.mSeq);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, "error in onRequestCurrentChannelUri", e);
+ }
+ }
+ }
+
+ @Override
+ public void onRequestCurrentChannelLcn() {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slogf.d(TAG, "onRequestCurrentChannelLcn");
+ }
+ if (mSessionState.mSession == null || mSessionState.mClient == null) {
+ return;
+ }
+ try {
+ mSessionState.mClient.onRequestCurrentChannelLcn(mSessionState.mSeq);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, "error in onRequestCurrentChannelLcn", e);
+ }
+ }
+ }
+
+ @Override
+ public void onRequestStreamVolume() {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slogf.d(TAG, "onRequestStreamVolume");
+ }
+ if (mSessionState.mSession == null || mSessionState.mClient == null) {
+ return;
+ }
+ try {
+ mSessionState.mClient.onRequestStreamVolume(mSessionState.mSeq);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, "error in onRequestStreamVolume", e);
+ }
+ }
+ }
+
+ @Override
+ public void onRequestTrackInfoList() {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slogf.d(TAG, "onRequestTrackInfoList");
+ }
+ if (mSessionState.mSession == null || mSessionState.mClient == null) {
+ return;
+ }
+ try {
+ mSessionState.mClient.onRequestTrackInfoList(mSessionState.mSeq);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, "error in onRequestTrackInfoList", e);
+ }
+ }
+ }
+
+ @Override
+ public void onAdRequest(AdRequest request) {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slogf.d(TAG, "onAdRequest (id=" + request.getId() + ")");
+ }
+ if (mSessionState.mSession == null || mSessionState.mClient == null) {
+ return;
+ }
+ try {
+ mSessionState.mClient.onAdRequest(request, mSessionState.mSeq);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, "error in onAdRequest", e);
+ }
+ }
+ }
+
+ @Override
public void onSessionStateChanged(int state) {
synchronized (mLock) {
if (DEBUG) {
@@ -1584,6 +1965,25 @@
}
}
+ @Override
+ public void onBiInteractiveAppCreated(Uri biIAppUri, String biIAppId) {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slogf.d(TAG, "onBiInteractiveAppCreated (biIAppUri=" + biIAppUri
+ + ", biIAppId=" + biIAppId + ")");
+ }
+ if (mSessionState.mSession == null || mSessionState.mClient == null) {
+ return;
+ }
+ try {
+ mSessionState.mClient.onBiInteractiveAppCreated(
+ biIAppUri, biIAppId, mSessionState.mSeq);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, "error in onBiInteractiveAppCreated", e);
+ }
+ }
+ }
+
@GuardedBy("mLock")
private boolean addSessionTokenToClientStateLocked(ITvIAppSession session) {
try {
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 2f9c138..4b33f0e 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -60,6 +60,11 @@
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH;
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
+import static com.android.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__APPEARED_APPLY_TREATMENT;
+import static com.android.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__APPEARED_REVERT_TREATMENT;
+import static com.android.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_APPLY_TREATMENT;
+import static com.android.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_DISMISS;
+import static com.android.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_REVERT_TREATMENT;
import static com.android.server.am.MemoryStatUtil.MemoryStat;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_METRICS;
@@ -72,6 +77,8 @@
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.ActivityOptions.SourceInfo;
+import android.app.TaskInfo;
+import android.app.TaskInfo.CameraCompatControlState;
import android.app.WaitResult;
import android.app.WindowConfiguration.WindowingMode;
import android.content.ComponentName;
@@ -1374,6 +1381,71 @@
}
}
+ /**
+ * Logs the Camera Compat Control appeared event that corresponds to the given {@code state}
+ * with the given {@code packageUid}.
+ */
+ void logCameraCompatControlAppearedEventReported(@CameraCompatControlState int state,
+ int packageUid) {
+ switch (state) {
+ case TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED:
+ logCameraCompatControlEventReported(
+ CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__APPEARED_APPLY_TREATMENT,
+ packageUid);
+ break;
+ case TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED:
+ logCameraCompatControlEventReported(
+ CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__APPEARED_REVERT_TREATMENT,
+ packageUid);
+ break;
+ case TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN:
+ // Nothing to log.
+ break;
+ default:
+ Slog.w(TAG, "Unexpected state in logCameraCompatControlAppearedEventReported: "
+ + state);
+ break;
+ }
+ }
+
+ /**
+ * Logs the Camera Compat Control clicked event that corresponds to the given {@code state}
+ * with the given {@code packageUid}.
+ */
+ void logCameraCompatControlClickedEventReported(@CameraCompatControlState int state,
+ int packageUid) {
+ switch (state) {
+ case TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED:
+ logCameraCompatControlEventReported(
+ CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_APPLY_TREATMENT,
+ packageUid);
+ break;
+ case TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED:
+ logCameraCompatControlEventReported(
+ CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_REVERT_TREATMENT,
+ packageUid);
+ break;
+ case TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED:
+ logCameraCompatControlEventReported(
+ CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_DISMISS,
+ packageUid);
+ break;
+ default:
+ Slog.w(TAG, "Unexpected state in logCameraCompatControlAppearedEventReported: "
+ + state);
+ break;
+ }
+ }
+
+ private void logCameraCompatControlEventReported(int event, int packageUid) {
+ FrameworkStatsLog.write(FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED, packageUid,
+ event);
+ if (DEBUG_METRICS) {
+ Slog.i(TAG, String.format("CAMERA_COMPAT_CONTROL_EVENT_REPORTED(%s, %s)", packageUid,
+ event));
+ }
+ }
+
private ArtManagerInternal getArtManagerInternal() {
if (mArtManagerInternal == null) {
// Note that this may be null.
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index cde5273..30465af 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1615,6 +1615,8 @@
if (!changed) {
return;
}
+ mTaskSupervisor.getActivityMetricsLogger().logCameraCompatControlAppearedEventReported(
+ newCameraCompatControlState, info.applicationInfo.uid);
if (newCameraCompatControlState == TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN) {
mCameraCompatControlClickedByUser = false;
mCompatCameraControlCallback = null;
@@ -1637,6 +1639,8 @@
if (!changed) {
return;
}
+ mTaskSupervisor.getActivityMetricsLogger().logCameraCompatControlClickedEventReported(
+ state, info.applicationInfo.uid);
if (state == TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED) {
mCompatCameraControlCallback = null;
return;
@@ -4003,6 +4007,13 @@
private boolean transferStartingWindow(@NonNull ActivityRecord fromActivity) {
final WindowState tStartingWindow = fromActivity.mStartingWindow;
if (tStartingWindow != null && fromActivity.mStartingSurface != null) {
+ if (tStartingWindow.getParent() == null) {
+ // The window has been detached from the parent, so the window cannot be transfer
+ // to another activity because it may be in the remove process.
+ // Don't need to remove the starting window at this point because that will happen
+ // at #postWindowRemoveCleanupLocked
+ return false;
+ }
// In this case, the starting icon has already been displayed, so start
// letting windows get shown immediately without any more transitions.
if (fromActivity.mVisible) {
@@ -4121,8 +4132,7 @@
final boolean containsShowWhenLocked = containsShowWhenLockedWindow();
if (containsDismissKeyguard != mLastContainsDismissKeyguardWindow
|| containsShowWhenLocked != mLastContainsShowWhenLockedWindow) {
- mWmService.notifyKeyguardFlagsChanged(null /* callback */,
- getDisplayContent().getDisplayId());
+ mDisplayContent.notifyKeyguardFlagsChanged();
}
mLastContainsDismissKeyguardWindow = containsDismissKeyguard;
mLastContainsShowWhenLockedWindow = containsShowWhenLocked;
@@ -6327,7 +6337,6 @@
}
} else if (w.isDrawn()) {
// The starting window for this container is drawn.
- mTaskSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(this);
startingDisplayed = true;
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
index b183281..bce2883 100644
--- a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
+++ b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
@@ -55,12 +55,12 @@
private final ActivityRecord mActivityRecord;
private final boolean mIsCompatEnabled;
+ private final String mName;
// Hold on to InputEventReceiver to prevent it from getting GCd.
private InputEventReceiver mInputEventReceiver;
private InputWindowHandleWrapper mInputWindowHandleWrapper;
- private final String mName = Integer.toHexString(System.identityHashCode(this))
- + " ActivityRecordInputSink";
+
private int mRapidTouchCount = 0;
private IBinder mToken;
private boolean mDisabled = false;
@@ -69,6 +69,8 @@
mActivityRecord = activityRecord;
mIsCompatEnabled = CompatChanges.isChangeEnabled(ENABLE_TOUCH_OPAQUE_ACTIVITIES,
mActivityRecord.getUid());
+ mName = Integer.toHexString(System.identityHashCode(this)) + " ActivityRecordInputSink "
+ + mActivityRecord.mActivityComponent.getShortClassName();
}
public void applyChangesToSurfaceIfChanged(
@@ -91,11 +93,6 @@
ANIMATION_TYPE_APP_TRANSITION)) {
// TODO(b/208662670): Investigate if we can have feature active during animations.
mInputWindowHandleWrapper.setToken(null);
- } else if (mActivityRecord.mStartingData != null) {
- // TODO(b/208659130): Remove this special case
- // Don't block touches during splash screen. This is done to not show toasts for
- // touches passing through splash screens. b/171772640
- mInputWindowHandleWrapper.setToken(null);
} else {
mInputWindowHandleWrapper.setToken(mToken);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 7fa9861..a9142ef 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -243,21 +243,6 @@
int startFlags, @Nullable Bundle options, int userId);
/**
- * Called when Keyguard flags might have changed.
- *
- * @param callback Callback to run after activity visibilities have been reevaluated. This can
- * be used from window manager so that when the callback is called, it's
- * guaranteed that all apps have their visibility updated accordingly.
- * @param displayId The id of the display where the keyguard flags changed.
- */
- public abstract void notifyKeyguardFlagsChanged(@Nullable Runnable callback, int displayId);
-
- /**
- * Called when the trusted state of Keyguard has changed.
- */
- public abstract void notifyKeyguardTrustedChanged();
-
- /**
* Called after virtual display Id is updated by
* {@link com.android.server.vr.Vr2dDisplay} with a specific
* {@param vr2dDisplayId}.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 173545c..15ebe28 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -63,7 +63,6 @@
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
-import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_WAKE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
@@ -5415,42 +5414,6 @@
false /*validateIncomingUser*/);
}
- @Override
- public void notifyKeyguardFlagsChanged(@Nullable Runnable callback, int displayId) {
- synchronized (mGlobalLock) {
-
- // We might change the visibilities here, so prepare an empty app transition which
- // might be overridden later if we actually change visibilities.
- final DisplayContent dc = mRootWindowContainer.getDisplayContent(displayId);
- if (dc == null) {
- return;
- }
- final boolean wasTransitionSet = dc.mAppTransition.isTransitionSet();
- if (!wasTransitionSet) {
- dc.prepareAppTransition(TRANSIT_NONE);
- }
- mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
-
- // If there was a transition set already we don't want to interfere with it as we
- // might be starting it too early.
- if (!wasTransitionSet) {
- dc.executeAppTransition();
- }
- }
- if (callback != null) {
- callback.run();
- }
- }
-
- @Override
- public void notifyKeyguardTrustedChanged() {
- synchronized (mGlobalLock) {
- if (mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)) {
- mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
- }
- }
- }
-
/**
* Called after virtual display Id is updated by
* {@link com.android.server.vr.Vr2dDisplay} with a specific
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 51c8daf..3cecce2 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -641,22 +641,35 @@
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName, aInfo.name));
- // Don't debug things in the system process
- if (!aInfo.processName.equals("system")) {
- if ((startFlags & (START_FLAG_DEBUG | START_FLAG_NATIVE_DEBUGGING
- | START_FLAG_TRACK_ALLOCATION)) != 0 || profilerInfo != null) {
-
+ final boolean requestDebug = (startFlags & (START_FLAG_DEBUG
+ | START_FLAG_NATIVE_DEBUGGING | START_FLAG_TRACK_ALLOCATION)) != 0;
+ final boolean requestProfile = profilerInfo != null;
+ if (requestDebug || requestProfile) {
+ final boolean debuggable = (Build.IS_DEBUGGABLE
+ || (aInfo.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0)
+ && !aInfo.processName.equals("system");
+ if ((requestDebug && !debuggable) || (requestProfile
+ && (!debuggable && !aInfo.applicationInfo.isProfileableByShell()))) {
+ Slog.w(TAG, "Ignore debugging for non-debuggable app: " + aInfo.packageName);
+ } else {
// Mimic an AMS synchronous call by passing a message to AMS and wait for AMS
// to notify us that the task has completed.
// TODO(b/80414790) look into further untangling for the situation where the
// caller is on the same thread as the handler we are posting to.
synchronized (mService.mGlobalLock) {
// Post message to AMS.
- final Message msg = PooledLambda.obtainMessage(
- ActivityManagerInternal::setDebugFlagsForStartingActivity,
- mService.mAmInternal, aInfo, startFlags, profilerInfo,
- mService.mGlobalLock);
- mService.mH.sendMessage(msg);
+ mService.mH.post(() -> {
+ try {
+ mService.mAmInternal.setDebugFlagsForStartingActivity(aInfo,
+ startFlags, profilerInfo, mService.mGlobalLock);
+ } catch (Throwable e) {
+ // Simply ignore it because the debugging doesn't take effect.
+ Slog.w(TAG, e);
+ synchronized (mService.mGlobalLockWithoutBoost) {
+ mService.mGlobalLockWithoutBoost.notifyAll();
+ }
+ }
+ });
try {
mService.mGlobalLock.wait();
} catch (InterruptedException ignore) {
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index 2a8ac39e..bb4519c 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -16,9 +16,12 @@
package com.android.server.wm;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SYNC_ENGINE;
import android.annotation.NonNull;
+import android.os.Trace;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
@@ -71,8 +74,9 @@
boolean mReady = false;
final ArraySet<WindowContainer> mRootMembers = new ArraySet<>();
private SurfaceControl.Transaction mOrphanTransaction = null;
+ private String mTraceName;
- private SyncGroup(TransactionReadyListener listener, int id) {
+ private SyncGroup(TransactionReadyListener listener, int id, String name) {
mSyncId = id;
mListener = listener;
mOnTimeout = () -> {
@@ -81,6 +85,10 @@
onTimeout();
}
};
+ if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
+ mTraceName = name + "SyncGroupReady";
+ Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, mTraceName, id);
+ }
}
/**
@@ -113,6 +121,9 @@
}
private void finishNow() {
+ if (mTraceName != null) {
+ Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, mTraceName, mSyncId);
+ }
ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Finished!", mSyncId);
SurfaceControl.Transaction merged = mWm.mTransactionFactory.get();
if (mOrphanTransaction != null) {
@@ -121,7 +132,9 @@
for (WindowContainer wc : mRootMembers) {
wc.finishSync(merged, false /* cancel */);
}
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "onTransactionReady");
mListener.onTransactionReady(mSyncId, merged);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
mActiveSyncs.remove(mSyncId);
mWm.mH.removeCallbacks(mOnTimeout);
}
@@ -168,12 +181,12 @@
}
int startSyncSet(TransactionReadyListener listener) {
- return startSyncSet(listener, WindowState.BLAST_TIMEOUT_DURATION);
+ return startSyncSet(listener, WindowState.BLAST_TIMEOUT_DURATION, "");
}
- int startSyncSet(TransactionReadyListener listener, long timeoutMs) {
+ int startSyncSet(TransactionReadyListener listener, long timeoutMs, String name) {
final int id = mNextSyncId++;
- final SyncGroup s = new SyncGroup(listener, id);
+ final SyncGroup s = new SyncGroup(listener, id, name);
mActiveSyncs.put(id, s);
ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Started for listener: %s", id, listener);
scheduleTimeout(s, timeoutMs);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e80a9b9..c740f7b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -80,6 +80,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.DisplayAreaOrganizer.FEATURE_IME;
@@ -1466,7 +1467,7 @@
@Override
boolean onDescendantOrientationChanged(WindowContainer requestingContainer) {
final Configuration config = updateOrientation(
- getRequestedOverrideConfiguration(), requestingContainer, false /* forceUpdate */);
+ requestingContainer, false /* forceUpdate */);
// If display rotation class tells us that it doesn't consider app requested orientation,
// this display won't rotate just because of an app changes its requested orientation. Thus
// it indicates that this display chooses not to handle this request.
@@ -1515,14 +1516,10 @@
* DisplayContent)} to tell the window manager it can unfreeze the screen. This will typically
* be done by calling {@link #sendNewConfiguration}.
*
- * @param currentConfig The current requested override configuration (it is usually set from
- * the last {@link #sendNewConfiguration}) of the display. It is used to
- * check if the configuration container has the latest state.
* @param freezeDisplayWindow Freeze the app window if the orientation is changed.
* @param forceUpdate See {@link DisplayRotation#updateRotationUnchecked(boolean)}
*/
- Configuration updateOrientation(Configuration currentConfig,
- WindowContainer freezeDisplayWindow, boolean forceUpdate) {
+ Configuration updateOrientation(WindowContainer<?> freezeDisplayWindow, boolean forceUpdate) {
if (!mDisplayReady) {
return null;
}
@@ -1539,15 +1536,15 @@
}
config = new Configuration();
computeScreenConfiguration(config);
- } else if (currentConfig != null
+ } else if (!(mTransitionController.isCollecting(this)
// If waiting for a remote rotation, don't prematurely update configuration.
- && !(mDisplayRotation.isWaitingForRemoteRotation()
- || mTransitionController.isCollecting(this))) {
+ || mDisplayRotation.isWaitingForRemoteRotation())) {
// No obvious action we need to take, but if our current state mismatches the
// activity manager's, update it, disregarding font scale, which should remain set
// to the value of the previous configuration.
// Here we're calling Configuration#unset() instead of setToDefaults() because we
// need to keep override configs clear of non-empty values (e.g. fontSize).
+ final Configuration currentConfig = getRequestedOverrideConfiguration();
mTmpConfiguration.unset();
mTmpConfiguration.updateFrom(currentConfig);
computeScreenConfiguration(mTmpConfiguration);
@@ -1597,6 +1594,9 @@
*/
@Rotation
int rotationForActivityInDifferentOrientation(@NonNull ActivityRecord r) {
+ if (mTransitionController.isShellTransitionsEnabled()) {
+ return ROTATION_UNDEFINED;
+ }
if (!WindowManagerService.ENABLE_FIXED_ROTATION_TRANSFORM) {
return ROTATION_UNDEFINED;
}
@@ -5914,6 +5914,30 @@
}
/**
+ * Notifies that some Keyguard flags have changed and the visibilities of the activities may
+ * need to be reevaluated.
+ */
+ void notifyKeyguardFlagsChanged() {
+ if (!isKeyguardLocked()) {
+ // If keyguard is not locked, the change of flags won't affect activity visibility.
+ return;
+ }
+ // We might change the visibilities here, so prepare an empty app transition which might be
+ // overridden later if we actually change visibilities.
+ final boolean wasTransitionSet = mAppTransition.isTransitionSet();
+ if (!wasTransitionSet) {
+ prepareAppTransition(TRANSIT_NONE);
+ }
+ mRootWindowContainer.ensureActivitiesVisible(null, 0, false /* preserveWindows */);
+
+ // If there was a transition set already we don't want to interfere with it as we might be
+ // starting it too early.
+ if (!wasTransitionSet) {
+ executeAppTransition();
+ }
+ }
+
+ /**
* Check if the display has {@link Display#FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD} applied.
*/
boolean canShowWithInsecureKeyguard() {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 4768b27..49a51d5 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1447,7 +1447,7 @@
final InsetsStateController controller = mDisplayContent.getInsetsStateController();
for (int i = mInsetsSourceWindowsExceptIme.size() - 1; i >= 0; i--) {
final WindowState win = mInsetsSourceWindowsExceptIme.valueAt(i);
- mWindowLayout.computeWindowFrames(win.getLayoutingAttrs(displayFrames.mRotation),
+ mWindowLayout.computeFrames(win.getLayoutingAttrs(displayFrames.mRotation),
displayFrames.mInsetsState, displayFrames.mDisplayCutoutSafe,
displayFrames.mUnrestricted, win.getWindowingMode(), UNSPECIFIED_LENGTH,
UNSPECIFIED_LENGTH, win.getRequestedVisibilities(),
@@ -1496,7 +1496,7 @@
sTmpLastParentFrame.set(pf);
- final boolean clippedByDisplayCutout = mWindowLayout.computeWindowFrames(attrs,
+ final boolean clippedByDisplayCutout = mWindowLayout.computeFrames(attrs,
win.getInsetsState(), displayFrames.mDisplayCutoutSafe,
win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight,
win.getRequestedVisibilities(), attachedWindowFrame, win.mGlobalScale,
@@ -1710,7 +1710,8 @@
if (mShowingDream != mLastShowingDream) {
mLastShowingDream = mShowingDream;
- mService.notifyShowingDreamChanged();
+ // Notify that isShowingDreamLw (which is checked in KeyguardController) has changed.
+ mDisplayContent.notifyKeyguardFlagsChanged();
}
mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
@@ -2377,8 +2378,7 @@
@VisibleForTesting
int updateLightNavigationBarLw(int appearance, WindowState navColorWin) {
- if (navColorWin == null || navColorWin.isDimming()
- || !isLightBarAllowed(navColorWin, Type.navigationBars())) {
+ if (navColorWin == null || !isLightBarAllowed(navColorWin, Type.navigationBars())) {
// Clear the light flag while not allowed.
appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS;
return appearance;
diff --git a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
index bbda577..c85e04d 100644
--- a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
+++ b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
@@ -59,8 +59,13 @@
/** The list to store the drawn tokens before the rotation animation starts. */
private ArrayList<WindowToken> mPendingShowTokens;
- /** It is used when the display has rotated, but some windows fade out in old rotation. */
- private SeamlessRotator mRotator;
+ /**
+ * The sync transactions of the target windows. It is used when the display has rotated but
+ * the windows need to fade out in previous rotation. These transactions will be applied with
+ * fade-in animation, so there won't be a flickering such as the windows have redrawn during
+ * fading out.
+ */
+ private ArrayMap<WindowState, SurfaceControl.Transaction> mCapturedDrawTransactions;
private final int mOriginalRotation;
private final boolean mHasScreenRotationAnimation;
@@ -110,16 +115,36 @@
mTargetWindowTokens.put(w.mToken, null);
}
}, true /* traverseTopToBottom */);
+
+ // The transition sync group may be finished earlier because it doesn't wait for these
+ // target windows. But the windows still need to use sync transaction to keep the appearance
+ // in previous rotation, so request a no-op sync to keep the state.
+ if (!mIsChangeTransition && transitionType != WindowManager.TRANSIT_NONE) {
+ for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
+ final WindowToken token = mTargetWindowTokens.keyAt(i);
+ for (int j = token.getChildCount() - 1; j >= 0; j--) {
+ token.getChildAt(j).applyWithNextDraw(t -> {});
+ }
+ }
+ }
}
@Override
public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) {
if (show) {
- final SurfaceControl leash = mTargetWindowTokens.remove(windowToken);
- if (leash != null && mRotator != null) {
- // The leash was unrotated by start transaction of transition. Clear the transform
- // to reshow the window in current rotation.
- mRotator.setIdentityMatrix(mDisplayContent.getPendingTransaction(), leash);
+ // The previous animation leash will be dropped when preparing fade-in animation, so
+ // simply remove it without restoring the transformation.
+ mTargetWindowTokens.remove(windowToken);
+ if (mCapturedDrawTransactions != null) {
+ // Unblock the window to draw its latest content with fade-in animation.
+ final SurfaceControl.Transaction t = mDisplayContent.getPendingTransaction();
+ for (int i = windowToken.getChildCount() - 1; i >= 0; i--) {
+ final SurfaceControl.Transaction drawT =
+ mCapturedDrawTransactions.remove(windowToken.getChildAt(i));
+ if (drawT != null) {
+ t.merge(drawT);
+ }
+ }
}
}
super.fadeWindowToken(show, windowToken, animationType);
@@ -225,14 +250,14 @@
// Take OPEN/CLOSE transition type as the example, the non-activity windows need to
// fade out in previous rotation while display has rotated to the new rotation, so
// their leashes are unrotated with the start transaction.
- mRotator = new SeamlessRotator(mOriginalRotation,
+ final SeamlessRotator rotator = new SeamlessRotator(mOriginalRotation,
mDisplayContent.getWindowConfiguration().getRotation(),
mDisplayContent.getDisplayInfo(),
false /* applyFixedTransformationHint */);
for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
final SurfaceControl leash = mTargetWindowTokens.valueAt(i);
if (leash != null) {
- mRotator.applyTransform(t, leash);
+ rotator.applyTransform(t, leash);
}
}
return;
@@ -280,6 +305,25 @@
}
}
+ /** Captures the post draw transaction if the window should update with fade-in animation. */
+ boolean handleFinishDrawing(WindowState w, SurfaceControl.Transaction postDrawTransaction) {
+ if (mIsChangeTransition || !isTargetToken(w.mToken)) return false;
+ if (postDrawTransaction != null && w.mTransitionController.inTransition()) {
+ if (mCapturedDrawTransactions == null) {
+ mCapturedDrawTransactions = new ArrayMap<>();
+ }
+ final SurfaceControl.Transaction t = mCapturedDrawTransactions.get(w);
+ if (t == null) {
+ mCapturedDrawTransactions.put(w, postDrawTransaction);
+ } else {
+ t.merge(postDrawTransaction);
+ }
+ return true;
+ }
+ mDisplayContent.finishFadeRotationAnimation(w.mToken);
+ return false;
+ }
+
@Override
public Animation getFadeInAnimation() {
if (mHasScreenRotationAnimation) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index c7b13eb..535bbb7 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1817,8 +1817,7 @@
final DisplayContent displayContent = getDisplayContent(displayId);
Configuration config = null;
if (displayContent != null) {
- config = displayContent.updateOrientation(
- getDisplayOverrideConfiguration(displayId), starting, true /* forceUpdate */);
+ config = displayContent.updateOrientation(starting, true /* forceUpdate */);
}
// Visibilities may change so let the starting activity have a chance to report. Can't do it
// when visibility is changed in each AppWindowToken because it may trigger wrong
@@ -2555,24 +2554,6 @@
mDisplayManagerInternal.setDisplayAccessUIDs(mDisplayAccessUIDs);
}
- Configuration getDisplayOverrideConfiguration(int displayId) {
- final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
- if (displayContent == null) {
- throw new IllegalArgumentException("No display found with id: " + displayId);
- }
-
- return displayContent.getRequestedOverrideConfiguration();
- }
-
- void setDisplayOverrideConfiguration(Configuration overrideConfiguration, int displayId) {
- final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
- if (displayContent == null) {
- throw new IllegalArgumentException("No display found with id: " + displayId);
- }
-
- displayContent.onRequestedOverrideConfigurationChanged(overrideConfiguration);
- }
-
void prepareForShutdown() {
for (int i = 0; i < getChildCount(); i++) {
createSleepToken("shutdown", getChildAt(i).mDisplayId);
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 1533245..d31b007 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -58,6 +58,7 @@
private boolean mAllowed;
private boolean mFilterOnlyVisibleRecents;
private Task mTopDisplayFocusRootTask;
+ private Task mTopDisplayAdjacentTask;
private RecentTasks mRecentTasks;
private boolean mKeepIntentExtra;
@@ -81,6 +82,12 @@
mRecentTasks = root.mService.getRecentTasks();
mKeepIntentExtra = (flags & FLAG_KEEP_INTENT_EXTRA) == FLAG_KEEP_INTENT_EXTRA;
+ if (mTopDisplayFocusRootTask.getAdjacentTaskFragment() != null) {
+ mTopDisplayAdjacentTask = mTopDisplayFocusRootTask.getAdjacentTaskFragment().asTask();
+ } else {
+ mTopDisplayAdjacentTask = null;
+ }
+
final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this,
PooledLambda.__(Task.class));
root.forAllLeafTasks(c, false);
@@ -130,6 +137,12 @@
// can be used to determine the order of the tasks (it may not be set for newly
// created tasks)
task.touchActiveTime();
+ } else if (rootTask == mTopDisplayAdjacentTask && rootTask.getTopMostTask() == task) {
+ // The short-term workaround for launcher could get suitable running task info in
+ // split screen.
+ task.touchActiveTime();
+ // TreeSet doesn't allow same value and make sure this task is lower than focus one.
+ task.lastActiveTime--;
}
mTmpSortedSet.add(task);
diff --git a/services/core/java/com/android/server/wm/SplashScreenExceptionList.java b/services/core/java/com/android/server/wm/SplashScreenExceptionList.java
index e815a0e..9ca49fe 100644
--- a/services/core/java/com/android/server/wm/SplashScreenExceptionList.java
+++ b/services/core/java/com/android/server/wm/SplashScreenExceptionList.java
@@ -64,7 +64,8 @@
mOnPropertiesChangedListener);
}
- private void updateDeviceConfig(String values) {
+ @VisibleForTesting
+ void updateDeviceConfig(String values) {
parseDeviceConfigPackageList(values);
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index c6948ee..a477108 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -20,11 +20,13 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
@@ -66,10 +68,12 @@
import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.Trace;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import android.view.SurfaceControl;
+import android.view.WindowManager;
import android.view.animation.Animation;
import android.window.RemoteTransition;
import android.window.TransitionInfo;
@@ -82,6 +86,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Predicate;
/**
* Represents a logical transition.
@@ -89,6 +95,10 @@
*/
class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListener {
private static final String TAG = "Transition";
+ private static final String TRACE_NAME_PLAY_TRANSITION = "PlayTransition";
+
+ /** The default package for resources */
+ private static final String DEFAULT_PACKAGE = "android";
/** The transition has been created and is collecting, but hasn't formally started. */
private static final int STATE_COLLECTING = 0;
@@ -174,7 +184,7 @@
mFlags = flags;
mController = controller;
mSyncEngine = syncEngine;
- mSyncId = mSyncEngine.startSyncSet(this, timeoutMs);
+ mSyncId = mSyncEngine.startSyncSet(this, timeoutMs, TAG);
}
void addFlag(int flag) {
@@ -395,6 +405,10 @@
* be called directly; use {@link TransitionController#finishTransition} instead.
*/
void finishTransition() {
+ if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
+ Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, TRACE_NAME_PLAY_TRANSITION,
+ System.identityHashCode(this));
+ }
mStartTransaction = mFinishTransaction = null;
if (mState < STATE_PLAYING) {
throw new IllegalStateException("Can't finish a non-playing transition " + mSyncId);
@@ -483,6 +497,11 @@
if (fadeRotationController != null) {
fadeRotationController.onTransitionFinished();
}
+ // Transient-launch activities cannot be IME target (WindowState#canBeImeTarget),
+ // so re-compute in case the IME target is changed after transition.
+ if (mTransientLaunches != null) {
+ mTargetDisplay.computeImeTarget(true /* updateImeTarget */);
+ }
}
void abort() {
@@ -548,7 +567,9 @@
// Resolve the animating targets from the participants
mTargets = calculateTargets(mParticipants, mChanges);
final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, mChanges);
- info.setAnimationOptions(mOverrideOptions);
+ if (mOverrideOptions != null) {
+ info.setAnimationOptions(mOverrideOptions);
+ }
// TODO(b/188669821): Move to animation impl in shell.
handleLegacyRecentsStartBehavior(dc, info);
@@ -630,6 +651,10 @@
"Calling onTransitionReady: %s", info);
mController.getTransitionPlayer().onTransitionReady(
this, info, transaction, mFinishTransaction);
+ if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
+ Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, TRACE_NAME_PLAY_TRANSITION,
+ System.identityHashCode(this));
+ }
} catch (RemoteException e) {
// If there's an exception when trying to send the mergedTransaction to the
// client, we should finish and apply it here so the transactions aren't lost.
@@ -1249,9 +1274,80 @@
out.addChange(change);
}
+ final WindowManager.LayoutParams animLp =
+ getLayoutParamsForAnimationsStyle(type, sortedTargets);
+ if (animLp != null && animLp.type != TYPE_APPLICATION_STARTING
+ && animLp.windowAnimations != 0) {
+ // Don't send animation options if no windowAnimations have been set or if the we are
+ // running an app starting animation, in which case we don't want the app to be able to
+ // change its animation directly.
+ TransitionInfo.AnimationOptions animOptions =
+ TransitionInfo.AnimationOptions.makeAnimOptionsFromLayoutParameters(animLp);
+ out.setAnimationOptions(animOptions);
+ }
+
return out;
}
+ private static WindowManager.LayoutParams getLayoutParamsForAnimationsStyle(int type,
+ ArrayList<WindowContainer> sortedTargets) {
+ // Find the layout params of the top-most application window that is part of the
+ // transition, which is what will control the animation theme.
+ final ArraySet<Integer> activityTypes = new ArraySet<>();
+ for (WindowContainer target : sortedTargets) {
+ if (target.asActivityRecord() != null) {
+ activityTypes.add(target.getActivityType());
+ } else if (target.asWindowToken() == null && target.asWindowState() == null) {
+ // We don't want app to customize animations that are not activity to activity.
+ // Activity-level transitions can only include activities, wallpaper and subwindows.
+ // Anything else is not a WindowToken nor a WindowState and is "higher" in the
+ // hierarchy which means we are no longer in an activity transition.
+ return null;
+ }
+ }
+ if (activityTypes.isEmpty()) {
+ // We don't want app to be able to customize transitions that are not activity to
+ // activity through the layout parameter animation style.
+ return null;
+ }
+ final ActivityRecord animLpActivity =
+ findAnimLayoutParamsActivityRecord(sortedTargets, type, activityTypes);
+ final WindowState mainWindow = animLpActivity != null
+ ? animLpActivity.findMainWindow() : null;
+ return mainWindow != null ? mainWindow.mAttrs : null;
+ }
+
+ private static ActivityRecord findAnimLayoutParamsActivityRecord(
+ List<WindowContainer> sortedTargets,
+ @TransitionType int transit, ArraySet<Integer> activityTypes) {
+ // Remote animations always win, but fullscreen windows override non-fullscreen windows.
+ ActivityRecord result = lookForTopWindowWithFilter(sortedTargets,
+ w -> w.getRemoteAnimationDefinition() != null
+ && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
+ if (result != null) {
+ return result;
+ }
+ result = lookForTopWindowWithFilter(sortedTargets,
+ w -> w.fillsParent() && w.findMainWindow() != null);
+ if (result != null) {
+ return result;
+ }
+ return lookForTopWindowWithFilter(sortedTargets, w -> w.findMainWindow() != null);
+ }
+
+ private static ActivityRecord lookForTopWindowWithFilter(List<WindowContainer> sortedTargets,
+ Predicate<ActivityRecord> filter) {
+ for (WindowContainer target : sortedTargets) {
+ final ActivityRecord activityRecord = target.asTaskFragment() != null
+ ? target.asTaskFragment().getTopNonFinishingActivity()
+ : target.asActivityRecord();
+ if (activityRecord != null && filter.test(activityRecord)) {
+ return activityRecord;
+ }
+ }
+ return null;
+ }
+
private static int getTaskRotationAnimation(@NonNull Task task) {
final ActivityRecord top = task.getTopVisibleActivity();
if (top == null) return ROTATION_ANIMATION_UNSPECIFIED;
diff --git a/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
index 4007661..5e963cc 100644
--- a/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
+++ b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
@@ -135,8 +135,8 @@
int state = mUnknownApps.get(activity);
if (state == UNKNOWN_STATE_WAITING_RELAYOUT || activity.mStartingWindow != null) {
mUnknownApps.put(activity, UNKNOWN_STATE_WAITING_VISIBILITY_UPDATE);
- mService.notifyKeyguardFlagsChanged(this::notifyVisibilitiesUpdated,
- activity.getDisplayContent().getDisplayId());
+ mDisplayContent.notifyKeyguardFlagsChanged();
+ notifyVisibilitiesUpdated();
}
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 7e84dbb..61acb97 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3181,6 +3181,11 @@
}
/** Cheap way of doing cast and instanceof. */
+ WindowState asWindowState() {
+ return null;
+ }
+
+ /** Cheap way of doing cast and instanceof. */
ActivityRecord asActivityRecord() {
return null;
}
@@ -3349,8 +3354,12 @@
for (int i = mChildren.size() - 1; i >= 0; --i) {
mChildren.get(i).finishSync(outMergedTransaction, cancel);
}
- mSyncState = SYNC_STATE_NONE;
if (cancel && mSyncGroup != null) mSyncGroup.onCancelSync(this);
+ clearSyncState();
+ }
+
+ void clearSyncState() {
+ mSyncState = SYNC_STATE_NONE;
mSyncGroup = null;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 86775f6..7be128b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -60,6 +60,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
+import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_SPY;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
@@ -1653,6 +1654,8 @@
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
displayPolicy.adjustWindowParamsLw(win, win.mAttrs);
attrs.flags = sanitizeFlagSlippery(attrs.flags, win.getName(), callingUid, callingPid);
+ attrs.inputFeatures = sanitizeSpyWindow(attrs.inputFeatures, win.getName(), callingUid,
+ callingPid);
win.setRequestedVisibilities(requestedVisibilities);
res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
@@ -2211,6 +2214,8 @@
displayPolicy.adjustWindowParamsLw(win, attrs);
win.mToken.adjustWindowParams(win, attrs);
attrs.flags = sanitizeFlagSlippery(attrs.flags, win.getName(), uid, pid);
+ attrs.inputFeatures = sanitizeSpyWindow(attrs.inputFeatures, win.getName(), uid,
+ pid);
int disableFlags =
(attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility) & DISABLE_MASK;
if (disableFlags != 0 && !hasStatusBarPermission(pid, uid)) {
@@ -2543,10 +2548,8 @@
if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
}
- if (win.inTransition()) {
- focusMayChange = true;
- win.mAnimatingExit = true;
- } else if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
+
+ if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
focusMayChange = true;
win.mAnimatingExit = true;
} else if (win.mDisplayContent.okToAnimate() && win.isAnimating(TRANSITION | PARENTS,
@@ -3026,17 +3029,13 @@
aspectRatio);
}
- /**
- * Notifies window manager that {@link DisplayPolicy#isShowingDreamLw} has changed.
- */
- public void notifyShowingDreamChanged() {
- // TODO(multi-display): support show dream in multi-display.
- notifyKeyguardFlagsChanged(null /* callback */, DEFAULT_DISPLAY);
- }
-
@Override
public void notifyKeyguardTrustedChanged() {
- mAtmInternal.notifyKeyguardTrustedChanged();
+ synchronized (mGlobalLock) {
+ if (mAtmService.mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)) {
+ mRoot.ensureActivitiesVisible(null, 0, false /* preserveWindows */);
+ }
+ }
}
@Override
@@ -3088,15 +3087,6 @@
return getDefaultDisplayContentLocked().mAppTransition.isIdle();
}
- /**
- * Notifies activity manager that some Keyguard flags have changed and that it needs to
- * reevaluate the visibilities of the activities.
- * @param callback Runnable to be called when activity manager is done reevaluating visibilities
- */
- void notifyKeyguardFlagsChanged(@Nullable Runnable callback, int displayId) {
- mAtmInternal.notifyKeyguardFlagsChanged(callback, displayId);
- }
-
// -------------------------------------------------------------
// Misc IWindowSession methods
@@ -8241,6 +8231,23 @@
}
/**
+ * You need MONITOR_INPUT permission to be able to set INPUT_FEATURE_SPY.
+ */
+ private int sanitizeSpyWindow(int inputFeatures, String windowName, int callingUid,
+ int callingPid) {
+ if ((inputFeatures & INPUT_FEATURE_SPY) == 0) {
+ return inputFeatures;
+ }
+ final int permissionResult = mContext.checkPermission(
+ permission.MONITOR_INPUT, callingPid, callingUid);
+ if (permissionResult != PackageManager.PERMISSION_GRANTED) {
+ throw new IllegalArgumentException("Cannot use INPUT_FEATURE_SPY from '" + windowName
+ + "' because it doesn't the have MONITOR_INPUT permission");
+ }
+ return inputFeatures;
+ }
+
+ /**
* Assigns an InputChannel to a SurfaceControl and configures it to receive
* touch input according to it's on-screen geometry.
*
@@ -8293,6 +8300,7 @@
h.ownerUid = callingUid;
h.ownerPid = callingPid;
+ // Do not allow any input features to be set without sanitizing them first.
h.inputFeatures = 0;
if (region == null) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8b026bf..863e3ca 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -844,6 +844,11 @@
}
};
+ @Override
+ WindowState asWindowState() {
+ return this;
+ }
+
/**
* @see #setSurfaceTranslationY(int)
*/
@@ -5422,7 +5427,7 @@
@Override
void assignLayer(Transaction t, int layer) {
- if (isStartingWindowAssociatedToTask()) {
+ if (mStartingData != null) {
// The starting window should cover the task.
t.setLayer(mSurfaceControl, Integer.MAX_VALUE);
return;
@@ -5742,29 +5747,36 @@
Slog.i(TAG, "finishDrawing of relaunch: " + this + " " + duration + "ms");
mActivityRecord.mRelaunchStartTime = 0;
}
-
- executeDrawHandlers(postDrawTransaction);
-
- final boolean applyPostDrawNow = mClientWasDrawingForSync && postDrawTransaction != null;
- mClientWasDrawingForSync = false;
- if (!onSyncFinishedDrawing()) {
- return mWinAnimator.finishDrawingLocked(postDrawTransaction, applyPostDrawNow);
- }
-
- if (mActivityRecord != null
- && mTransitionController.isShellTransitionsEnabled()
- && mAttrs.type == TYPE_APPLICATION_STARTING) {
+ if (mActivityRecord != null && mAttrs.type == TYPE_APPLICATION_STARTING) {
mWmService.mAtmService.mTaskSupervisor.getActivityMetricsLogger()
.notifyStartingWindowDrawn(mActivityRecord);
}
- if (postDrawTransaction != null) {
+ final boolean hasSyncHandlers = executeDrawHandlers(postDrawTransaction);
+
+ boolean skipLayout = false;
+ // Control the timing to switch the appearance of window with different rotations.
+ final FadeRotationAnimationController fadeRotationController =
+ mDisplayContent.getFadeRotationAnimationController();
+ if (fadeRotationController != null
+ && fadeRotationController.handleFinishDrawing(this, postDrawTransaction)) {
+ // Consume the transaction because the controller will apply it with fade animation.
+ // Layout is not needed because the window will be hidden by the fade leash. Clear
+ // sync state because its sync transaction doesn't need to be merged to sync group.
+ postDrawTransaction = null;
+ skipLayout = true;
+ clearSyncState();
+ } else if (onSyncFinishedDrawing() && postDrawTransaction != null) {
mSyncTransaction.merge(postDrawTransaction);
+ // Consume the transaction because the sync group will merge it.
+ postDrawTransaction = null;
}
- mWinAnimator.finishDrawingLocked(null, false /* forceApplyNow */);
+ final boolean layoutNeeded =
+ mWinAnimator.finishDrawingLocked(postDrawTransaction, mClientWasDrawingForSync);
+ mClientWasDrawingForSync = false;
// We always want to force a traversal after a finish draw for blast sync.
- return true;
+ return !skipLayout && (hasSyncHandlers || layoutNeeded);
}
void immediatelyNotifyBlastSync() {
diff --git a/services/core/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp
index 2ca348b..63daa35 100644
--- a/services/core/jni/com_android_server_ConsumerIrService.cpp
+++ b/services/core/jni/com_android_server_ConsumerIrService.cpp
@@ -34,7 +34,7 @@
static sp<IConsumerIr> mHal;
-static jboolean halOpen(JNIEnv* /* env */, jobject /* obj */) {
+static jboolean getHidlHalService(JNIEnv * /* env */, jobject /* obj */) {
// TODO(b/31632518)
mHal = IConsumerIr::getService();
return mHal != nullptr;
@@ -84,9 +84,9 @@
}
static const JNINativeMethod method_table[] = {
- { "halOpen", "()Z", (void *)halOpen },
- { "halTransmit", "(I[I)I", (void *)halTransmit },
- { "halGetCarrierFrequencies", "()[I", (void *)halGetCarrierFrequencies},
+ {"getHidlHalService", "()Z", (void *)getHidlHalService},
+ {"halTransmit", "(I[I)I", (void *)halTransmit},
+ {"halGetCarrierFrequencies", "()[I", (void *)halGetCarrierFrequencies},
};
int register_android_server_ConsumerIrService(JNIEnv *env) {
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index f0f779d..826171a 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -29,6 +29,7 @@
#include <android/hardware/gnss/2.1/IGnssMeasurement.h>
#include <android/hardware/gnss/BnGnss.h>
#include <android/hardware/gnss/BnGnssCallback.h>
+#include <android/hardware/gnss/BnGnssDebug.h>
#include <android/hardware/gnss/BnGnssGeofence.h>
#include <android/hardware/gnss/BnGnssGeofenceCallback.h>
#include <android/hardware/gnss/BnGnssMeasurementCallback.h>
@@ -53,6 +54,7 @@
#include "gnss/GnssAntennaInfoCallback.h"
#include "gnss/GnssBatching.h"
#include "gnss/GnssConfiguration.h"
+#include "gnss/GnssDebug.h"
#include "gnss/GnssGeofence.h"
#include "gnss/GnssMeasurement.h"
#include "gnss/GnssNavigationMessage.h"
@@ -155,8 +157,6 @@
using IGnssCallback_V1_0 = android::hardware::gnss::V1_0::IGnssCallback;
using IGnssCallback_V2_0 = android::hardware::gnss::V2_0::IGnssCallback;
using IGnssCallback_V2_1 = android::hardware::gnss::V2_1::IGnssCallback;
-using IGnssDebug_V1_0 = android::hardware::gnss::V1_0::IGnssDebug;
-using IGnssDebug_V2_0 = android::hardware::gnss::V2_0::IGnssDebug;
using IGnssAntennaInfo = android::hardware::gnss::V2_1::IGnssAntennaInfo;
using IAGnssRil_V1_0 = android::hardware::gnss::V1_0::IAGnssRil;
using IAGnssRil_V2_0 = android::hardware::gnss::V2_0::IAGnssRil;
@@ -179,6 +179,7 @@
using IGnssAidl = android::hardware::gnss::IGnss;
using IGnssCallbackAidl = android::hardware::gnss::IGnssCallback;
using IGnssBatchingAidl = android::hardware::gnss::IGnssBatching;
+using IGnssDebugAidl = android::hardware::gnss::IGnssDebug;
using IGnssPsdsAidl = android::hardware::gnss::IGnssPsds;
using IGnssPsdsCallbackAidl = android::hardware::gnss::IGnssPsdsCallback;
using IGnssConfigurationAidl = android::hardware::gnss::IGnssConfiguration;
@@ -209,8 +210,6 @@
sp<IGnssXtra> gnssXtraIface = nullptr;
sp<IAGnssRil_V1_0> agnssRilIface = nullptr;
sp<IAGnssRil_V2_0> agnssRilIface_V2_0 = nullptr;
-sp<IGnssDebug_V1_0> gnssDebugIface = nullptr;
-sp<IGnssDebug_V2_0> gnssDebugIface_V2_0 = nullptr;
sp<IGnssNi> gnssNiIface = nullptr;
sp<IGnssPowerIndication> gnssPowerIndicationIface = nullptr;
sp<IMeasurementCorrections_V1_0> gnssCorrectionsIface_V1_0 = nullptr;
@@ -224,6 +223,7 @@
std::unique_ptr<android::gnss::GnssBatchingInterface> gnssBatchingIface = nullptr;
std::unique_ptr<android::gnss::GnssGeofenceInterface> gnssGeofencingIface = nullptr;
std::unique_ptr<android::gnss::AGnssInterface> agnssIface = nullptr;
+std::unique_ptr<android::gnss::GnssDebugInterface> gnssDebugIface = nullptr;
#define WAKE_LOCK_NAME "GPS"
@@ -1104,22 +1104,24 @@
// Allow all causal combinations between IGnss.hal and IGnssDebug.hal. That means,
// 2.0@IGnss can be paired with {1.0, 2.0}@IGnssDebug
// 1.0@IGnss is paired with 1.0@IGnssDebug
- gnssDebugIface = nullptr;
- if (gnssHal_V2_0 != nullptr) {
- auto gnssDebug = gnssHal_V2_0->getExtensionGnssDebug_2_0();
- if (!gnssDebug.isOk()) {
- ALOGD("Unable to get a handle to GnssDebug_V2_0");
- } else {
- gnssDebugIface_V2_0 = gnssDebug;
- gnssDebugIface = gnssDebugIface_V2_0;
+
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<IGnssDebugAidl> gnssDebugAidl;
+ auto status = gnssHalAidl->getExtensionGnssDebug(&gnssDebugAidl);
+ if (checkAidlStatus(status, "Unable to get a handle to GnssDebug interface.")) {
+ gnssDebugIface = std::make_unique<gnss::GnssDebug>(gnssDebugAidl);
+ }
+ }
+ if (gnssHal_V2_0 != nullptr && gnssDebugIface == nullptr) {
+ auto gnssDebug_V2_0 = gnssHal_V2_0->getExtensionGnssDebug_2_0();
+ if (checkHidlReturn(gnssDebug_V2_0, "Unable to get a handle to GnssDebug_V2_0.")) {
+ gnssDebugIface = std::make_unique<gnss::GnssDebug_V2_0>(gnssDebug_V2_0);
}
}
if (gnssHal != nullptr && gnssDebugIface == nullptr) {
- auto gnssDebug = gnssHal->getExtensionGnssDebug();
- if (!gnssDebug.isOk()) {
- ALOGD("Unable to get a handle to GnssDebug");
- } else {
- gnssDebugIface = gnssDebug;
+ auto gnssDebug_V1_0 = gnssHal->getExtensionGnssDebug();
+ if (checkHidlReturn(gnssDebug_V1_0, "Unable to get a handle to GnssDebug_V1_0.")) {
+ gnssDebugIface = std::make_unique<gnss::GnssDebug_V1_0>(gnssDebug_V1_0);
}
}
@@ -1639,108 +1641,16 @@
checkHidlReturn(result, "IGnssNi respond() failed.");
}
-const IGnssDebug_V1_0::SatelliteData& getSatelliteData(
- const hidl_vec<IGnssDebug_V1_0::SatelliteData>& satelliteDataArray, size_t i) {
- return satelliteDataArray[i];
-}
-
-const IGnssDebug_V1_0::SatelliteData& getSatelliteData(
- const hidl_vec<IGnssDebug_V2_0::SatelliteData>& satelliteDataArray, size_t i) {
- return satelliteDataArray[i].v1_0;
-}
-
-template<class T>
-uint32_t getConstellationType(const hidl_vec<T>& satelliteDataArray, size_t i) {
- return static_cast<uint32_t>(satelliteDataArray[i].constellation);
-}
-
-template<class T>
-static jstring parseDebugData(JNIEnv* env, std::stringstream& internalState, const T& data) {
- internalState << "Gnss Location Data:: ";
- if (!data.position.valid) {
- internalState << "not valid";
- } else {
- internalState << "LatitudeDegrees: " << data.position.latitudeDegrees
- << ", LongitudeDegrees: " << data.position.longitudeDegrees
- << ", altitudeMeters: " << data.position.altitudeMeters
- << ", speedMetersPerSecond: " << data.position.speedMetersPerSec
- << ", bearingDegrees: " << data.position.bearingDegrees
- << ", horizontalAccuracyMeters: "
- << data.position.horizontalAccuracyMeters
- << ", verticalAccuracyMeters: " << data.position.verticalAccuracyMeters
- << ", speedAccuracyMetersPerSecond: "
- << data.position.speedAccuracyMetersPerSecond
- << ", bearingAccuracyDegrees: " << data.position.bearingAccuracyDegrees
- << ", ageSeconds: " << data.position.ageSeconds;
- }
- internalState << std::endl;
-
- internalState << "Gnss Time Data:: timeEstimate: " << data.time.timeEstimate
- << ", timeUncertaintyNs: " << data.time.timeUncertaintyNs
- << ", frequencyUncertaintyNsPerSec: "
- << data.time.frequencyUncertaintyNsPerSec << std::endl;
-
- if (data.satelliteDataArray.size() != 0) {
- internalState << "Satellite Data for " << data.satelliteDataArray.size()
- << " satellites:: " << std::endl;
- }
-
- internalState << "constell: 1=GPS, 2=SBAS, 3=GLO, 4=QZSS, 5=BDS, 6=GAL, 7=IRNSS; "
- << "ephType: 0=Eph, 1=Alm, 2=Unk; "
- << "ephSource: 0=Demod, 1=Supl, 2=Server, 3=Unk; "
- << "ephHealth: 0=Good, 1=Bad, 2=Unk" << std::endl;
- for (size_t i = 0; i < data.satelliteDataArray.size(); i++) {
- IGnssDebug_V1_0::SatelliteData satelliteData =
- getSatelliteData(data.satelliteDataArray, i);
- internalState << "constell: "
- << getConstellationType(data.satelliteDataArray, i)
- << ", svid: " << std::setw(3) << satelliteData.svid
- << ", serverPredAvail: "
- << satelliteData.serverPredictionIsAvailable
- << ", serverPredAgeSec: " << std::setw(7)
- << satelliteData.serverPredictionAgeSeconds
- << ", ephType: "
- << static_cast<uint32_t>(satelliteData.ephemerisType)
- << ", ephSource: "
- << static_cast<uint32_t>(satelliteData.ephemerisSource)
- << ", ephHealth: "
- << static_cast<uint32_t>(satelliteData.ephemerisHealth)
- << ", ephAgeSec: " << std::setw(7)
- << satelliteData.ephemerisAgeSeconds << std::endl;
- }
- return (jstring) env->NewStringUTF(internalState.str().c_str());
-}
-
static jstring android_location_gnss_hal_GnssNative_get_internal_state(JNIEnv* env, jclass) {
- jstring internalStateStr = nullptr;
/*
* TODO: Create a jobject to represent GnssDebug.
*/
- std::stringstream internalState;
-
if (gnssDebugIface == nullptr) {
ALOGE("%s: IGnssDebug interface not available.", __func__);
- } else if (gnssDebugIface_V2_0 != nullptr) {
- IGnssDebug_V2_0::DebugData data;
- auto result = gnssDebugIface_V2_0->getDebugData_2_0(
- [&data](const IGnssDebug_V2_0::DebugData& debugData) {
- data = debugData;
- });
- if (checkHidlReturn(result, "IGnssDebug getDebugData_2_0() failed.")) {
- internalStateStr = parseDebugData(env, internalState, data);
- }
- } else {
- IGnssDebug_V1_0::DebugData data;
- auto result = gnssDebugIface->getDebugData(
- [&data](const IGnssDebug_V1_0::DebugData& debugData) {
- data = debugData;
- });
- if (checkHidlReturn(result, "IGnssDebug getDebugData() failed.")) {
- internalStateStr = parseDebugData(env, internalState, data);
- }
+ return nullptr;
}
- return internalStateStr;
+ return gnssDebugIface->getDebugData(env);
}
static void android_location_gnss_hal_GnssNative_request_power_stats(JNIEnv* env) {
diff --git a/services/core/jni/gnss/Android.bp b/services/core/jni/gnss/Android.bp
index e49e81c..63f5f52 100644
--- a/services/core/jni/gnss/Android.bp
+++ b/services/core/jni/gnss/Android.bp
@@ -29,6 +29,7 @@
"GnssBatching.cpp",
"GnssBatchingCallback.cpp",
"GnssConfiguration.cpp",
+ "GnssDebug.cpp",
"GnssGeofence.cpp",
"GnssGeofenceCallback.cpp",
"GnssMeasurement.cpp",
diff --git a/services/core/jni/gnss/GnssDebug.cpp b/services/core/jni/gnss/GnssDebug.cpp
new file mode 100644
index 0000000..da53317
--- /dev/null
+++ b/services/core/jni/gnss/GnssDebug.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Define LOG_TAG before <log/log.h> to overwrite the default value.
+#define LOG_TAG "GnssDebugJni"
+
+#include "GnssDebug.h"
+
+#include "Utils.h"
+
+using android::hardware::gnss::IGnssDebug;
+using IGnssDebug_V1_0 = android::hardware::gnss::V1_0::IGnssDebug;
+using IGnssDebug_V2_0 = android::hardware::gnss::V2_0::IGnssDebug;
+
+namespace android::gnss {
+
+// Implementation of GnssDebug (AIDL HAL)
+
+GnssDebug::GnssDebug(const sp<IGnssDebug>& iGnssDebug) : mIGnssDebug(iGnssDebug) {
+ assert(mIGnssDebug != nullptr);
+}
+
+jstring GnssDebug::getDebugData(JNIEnv* env) {
+ std::stringstream internalState;
+ IGnssDebug::DebugData data;
+ auto status = mIGnssDebug->getDebugData(&data);
+ if (checkAidlStatus(status, "IGnssDebug getDebugData() failed.")) {
+ return GnssDebugUtil::parseDebugData<IGnssDebug::DebugData,
+ IGnssDebug::SatelliteData>(env, internalState, data);
+ }
+ return nullptr;
+}
+
+// Implementation of GnssDebug_V1_0
+
+GnssDebug_V1_0::GnssDebug_V1_0(const sp<IGnssDebug_V1_0>& iGnssDebug)
+ : mIGnssDebug_V1_0(iGnssDebug) {
+ assert(mIGnssDebug_V1_0 != nullptr);
+}
+
+jstring GnssDebug_V1_0::getDebugData(JNIEnv* env) {
+ std::stringstream internalState;
+ IGnssDebug_V1_0::DebugData data;
+ auto result = mIGnssDebug_V1_0->getDebugData(
+ [&data](const IGnssDebug_V1_0::DebugData& debugData) { data = debugData; });
+ if (checkHidlReturn(result, "IGnssDebug getDebugData_1_0() failed.")) {
+ return GnssDebugUtil::parseDebugData<IGnssDebug_V1_0::DebugData,
+ IGnssDebug_V1_0::SatelliteData>(env, internalState,
+ data);
+ }
+ return nullptr;
+}
+
+// Implementation of GnssDebug_V2_0
+
+GnssDebug_V2_0::GnssDebug_V2_0(const sp<IGnssDebug_V2_0>& iGnssDebug)
+ : mIGnssDebug_V2_0{iGnssDebug} {
+ assert(mIGnssDebug_V2_0 != nullptr);
+}
+
+jstring GnssDebug_V2_0::getDebugData(JNIEnv* env) {
+ std::stringstream internalState;
+ IGnssDebug_V2_0::DebugData data;
+ auto result = mIGnssDebug_V2_0->getDebugData_2_0(
+ [&data](const IGnssDebug_V2_0::DebugData& debugData) { data = debugData; });
+ if (checkHidlReturn(result, "IGnssDebug getDebugData_2_0() failed.")) {
+ return GnssDebugUtil::parseDebugData<IGnssDebug_V2_0::DebugData,
+ IGnssDebug_V1_0::SatelliteData>(env, internalState,
+ data);
+ }
+ return nullptr;
+}
+
+const android::hardware::gnss::V1_0::IGnssDebug::SatelliteData& GnssDebugUtil::getSatelliteData(
+ const hardware::hidl_vec<android::hardware::gnss::V1_0::IGnssDebug::SatelliteData>&
+ satelliteDataArray,
+ size_t i) {
+ return satelliteDataArray[i];
+}
+
+const android::hardware::gnss::V1_0::IGnssDebug::SatelliteData& GnssDebugUtil::getSatelliteData(
+ const hardware::hidl_vec<android::hardware::gnss::V2_0::IGnssDebug::SatelliteData>&
+ satelliteDataArray,
+ size_t i) {
+ return satelliteDataArray[i].v1_0;
+}
+
+const android::hardware::gnss::IGnssDebug::SatelliteData& GnssDebugUtil::getSatelliteData(
+ const std::vector<android::hardware::gnss::IGnssDebug::SatelliteData>& satelliteDataArray,
+ size_t i) {
+ return satelliteDataArray[i];
+}
+
+} // namespace android::gnss
diff --git a/services/core/jni/gnss/GnssDebug.h b/services/core/jni/gnss/GnssDebug.h
new file mode 100644
index 0000000..9f5ff21
--- /dev/null
+++ b/services/core/jni/gnss/GnssDebug.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_SERVER_GNSS_GNSSDEBUG_H
+#define _ANDROID_SERVER_GNSS_GNSSDEBUG_H
+
+#pragma once
+
+#ifndef LOG_TAG
+#error LOG_TAG must be defined before including this file.
+#endif
+
+#include <android/hardware/gnss/1.0/IGnssDebug.h>
+#include <android/hardware/gnss/2.0/IGnssDebug.h>
+#include <android/hardware/gnss/BnGnssDebug.h>
+#include <log/log.h>
+
+#include <iomanip>
+
+#include "jni.h"
+
+namespace android::gnss {
+
+class GnssDebugInterface {
+public:
+ virtual ~GnssDebugInterface() {}
+ virtual jstring getDebugData(JNIEnv* env) = 0;
+};
+
+class GnssDebug : public GnssDebugInterface {
+public:
+ GnssDebug(const sp<android::hardware::gnss::IGnssDebug>& iGnssDebug);
+ jstring getDebugData(JNIEnv* env) override;
+
+private:
+ const sp<android::hardware::gnss::IGnssDebug> mIGnssDebug;
+};
+
+class GnssDebug_V1_0 : public GnssDebugInterface {
+public:
+ GnssDebug_V1_0(const sp<android::hardware::gnss::V1_0::IGnssDebug>& iGnssDebug);
+ jstring getDebugData(JNIEnv* env) override;
+
+private:
+ const sp<android::hardware::gnss::V1_0::IGnssDebug> mIGnssDebug_V1_0;
+};
+
+class GnssDebug_V2_0 : public GnssDebugInterface {
+public:
+ GnssDebug_V2_0(const sp<android::hardware::gnss::V2_0::IGnssDebug>& iGnssDebug);
+ jstring getDebugData(JNIEnv* env) override;
+
+private:
+ const sp<android::hardware::gnss::V2_0::IGnssDebug> mIGnssDebug_V2_0;
+};
+
+struct GnssDebugUtil {
+ template <class T>
+ static uint32_t getConstellationType(const hardware::hidl_vec<T>& satelliteDataArray, size_t i);
+
+ template <class T>
+ static uint32_t getConstellationType(const std::vector<T>& satelliteDataArray, size_t i);
+
+ template <class T>
+ static uint32_t getTimeEstimateMs(const T& data);
+
+ template <class T_DebugData, class T_SatelliteData>
+ static jstring parseDebugData(JNIEnv* env, std::stringstream& internalState,
+ const T_DebugData& data);
+
+ const static android::hardware::gnss::V1_0::IGnssDebug::SatelliteData& getSatelliteData(
+ const hardware::hidl_vec<android::hardware::gnss::V1_0::IGnssDebug::SatelliteData>&
+ satelliteDataArray,
+ size_t i);
+
+ const static android::hardware::gnss::V1_0::IGnssDebug::SatelliteData& getSatelliteData(
+ const hardware::hidl_vec<android::hardware::gnss::V2_0::IGnssDebug::SatelliteData>&
+ satelliteDataArray,
+ size_t i);
+
+ const static android::hardware::gnss::IGnssDebug::SatelliteData& getSatelliteData(
+ const std::vector<android::hardware::gnss::IGnssDebug::SatelliteData>&
+ satelliteDataArray,
+ size_t i);
+};
+
+template <class T>
+uint32_t GnssDebugUtil::getConstellationType(const hardware::hidl_vec<T>& satelliteDataArray,
+ size_t i) {
+ return static_cast<uint32_t>(satelliteDataArray[i].constellation);
+}
+
+template <class T>
+uint32_t GnssDebugUtil::getConstellationType(const std::vector<T>& satelliteDataArray, size_t i) {
+ return static_cast<uint32_t>(satelliteDataArray[i].constellation);
+}
+
+template <class T>
+uint32_t GnssDebugUtil::getTimeEstimateMs(const T& data) {
+ return data.time.timeEstimate;
+}
+
+template <>
+uint32_t GnssDebugUtil::getTimeEstimateMs(
+ const android::hardware::gnss::IGnssDebug::DebugData& data) {
+ return data.time.timeEstimateMs;
+}
+
+template <class T_DebugData, class T_SatelliteData>
+jstring GnssDebugUtil::parseDebugData(JNIEnv* env, std::stringstream& internalState,
+ const T_DebugData& data) {
+ internalState << "Gnss Location Data:: ";
+ if (!data.position.valid) {
+ internalState << "not valid";
+ } else {
+ internalState << "LatitudeDegrees: " << data.position.latitudeDegrees
+ << ", LongitudeDegrees: " << data.position.longitudeDegrees
+ << ", altitudeMeters: " << data.position.altitudeMeters
+ << ", speedMetersPerSecond: " << data.position.speedMetersPerSec
+ << ", bearingDegrees: " << data.position.bearingDegrees
+ << ", horizontalAccuracyMeters: " << data.position.horizontalAccuracyMeters
+ << ", verticalAccuracyMeters: " << data.position.verticalAccuracyMeters
+ << ", speedAccuracyMetersPerSecond: "
+ << data.position.speedAccuracyMetersPerSecond
+ << ", bearingAccuracyDegrees: " << data.position.bearingAccuracyDegrees
+ << ", ageSeconds: " << data.position.ageSeconds;
+ }
+ internalState << std::endl;
+
+ internalState << "Gnss Time Data:: timeEstimate: " << GnssDebugUtil::getTimeEstimateMs(data)
+ << ", timeUncertaintyNs: " << data.time.timeUncertaintyNs
+ << ", frequencyUncertaintyNsPerSec: " << data.time.frequencyUncertaintyNsPerSec
+ << std::endl;
+
+ if (data.satelliteDataArray.size() != 0) {
+ internalState << "Satellite Data for " << data.satelliteDataArray.size()
+ << " satellites:: " << std::endl;
+ }
+
+ internalState << "constell: 1=GPS, 2=SBAS, 3=GLO, 4=QZSS, 5=BDS, 6=GAL, 7=IRNSS; "
+ << "ephType: 0=Eph, 1=Alm, 2=Unk; "
+ << "ephSource: 0=Demod, 1=Supl, 2=Server, 3=Unk; "
+ << "ephHealth: 0=Good, 1=Bad, 2=Unk" << std::endl;
+ for (size_t i = 0; i < data.satelliteDataArray.size(); i++) {
+ T_SatelliteData satelliteData = getSatelliteData(data.satelliteDataArray, i);
+ internalState << "constell: "
+ << GnssDebugUtil::getConstellationType(data.satelliteDataArray, i)
+ << ", svid: " << std::setw(3) << satelliteData.svid
+ << ", serverPredAvail: " << satelliteData.serverPredictionIsAvailable
+ << ", serverPredAgeSec: " << std::setw(7)
+ << satelliteData.serverPredictionAgeSeconds
+ << ", ephType: " << static_cast<uint32_t>(satelliteData.ephemerisType)
+ << ", ephSource: " << static_cast<uint32_t>(satelliteData.ephemerisSource)
+ << ", ephHealth: " << static_cast<uint32_t>(satelliteData.ephemerisHealth)
+ << ", ephAgeSec: " << std::setw(7) << satelliteData.ephemerisAgeSeconds
+ << std::endl;
+ }
+ return (jstring)env->NewStringUTF(internalState.str().c_str());
+}
+
+} // namespace android::gnss
+
+#endif // _ANDROID_SERVER_GNSS_GNSSDEBUG_H
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 266b656..df8953c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -7459,7 +7459,8 @@
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
final CallerIdentity caller = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
+ Preconditions.checkCallAuthorization(
+ hasFullCrossUsersPermission(caller, userHandle) && canQueryAdminPolicy(caller));
synchronized (getLockObject()) {
DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 663e17b..29797a5 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1392,7 +1392,6 @@
VcnManagementService vcnManagement = null;
NetworkStatsService networkStats = null;
NetworkPolicyManagerService networkPolicy = null;
- NsdService serviceDiscovery = null;
WindowManagerService wm = null;
SerialService serial = null;
NetworkTimeUpdateService networkTimeUpdater = null;
@@ -2008,16 +2007,6 @@
}
t.traceEnd();
- t.traceBegin("StartNsdService");
- try {
- serviceDiscovery = NsdService.create(context);
- ServiceManager.addService(
- Context.NSD_SERVICE, serviceDiscovery);
- } catch (Throwable e) {
- reportWtf("starting Service Discovery Service", e);
- }
- t.traceEnd();
-
t.traceBegin("StartSystemUpdateManagerService");
try {
ServiceManager.addService(Context.SYSTEM_UPDATE_SERVICE,
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index d0205ae..ca31efc 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -340,6 +340,11 @@
IBinder binder = server.asBinder();
mDevicesByServer.remove(binder);
+ // Clearing mDeviceStatus is needed because setDeviceStatus()
+ // relies on finding the device in mDevicesByServer.
+ // So the status can no longer be updated after we remove it.
+ // Then we can end up with input ports that are stuck open.
+ mDeviceStatus = null;
try {
server.closeDevice();
diff --git a/services/proguard.flags b/services/proguard.flags
index 30dd6cf..5d01d3e 100644
--- a/services/proguard.flags
+++ b/services/proguard.flags
@@ -1,11 +1,21 @@
# TODO(b/196084106): Refine and optimize this configuration. Note that this
# configuration is only used when `SOONG_CONFIG_ANDROID_SYSTEM_OPTIMIZE_JAVA=true`.
-keep,allowoptimization,allowaccessmodification class ** {
- *;
+ !synthetic *;
}
# Various classes subclassed in ethernet-service (avoid marking final).
-keep public class android.net.** { *; }
# Referenced via CarServiceHelperService in car-frameworks-service (avoid removing).
--keep public class com.android.server.utils.Slogf { *; }
\ No newline at end of file
+-keep public class com.android.server.utils.Slogf { *; }
+
+# Allows making private and protected methods/fields public as part of
+# optimization. This enables inlining of trivial getter/setter methods.
+-allowaccessmodification
+
+# Disallow accessmodification for soundtrigger classes. Logging via reflective
+# public member traversal can cause infinite loops. See b/210901706.
+-keep,allowoptimization class com.android.server.soundtrigger_middleware.** {
+ !synthetic *;
+}
diff --git a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
index 4b12fd4..8203c1b 100644
--- a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
+++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
@@ -354,6 +354,7 @@
PackageManager.PERMISSION_GRANTED
}
}
+ val mockSharedLibrariesImpl: SharedLibrariesImpl = mock()
val mockInjector: PackageManagerServiceInjector = mock {
whenever(this.lock) { PackageManagerTracedLock() }
whenever(this.componentResolver) { mockComponentResolver }
@@ -366,6 +367,7 @@
whenever(this.appsFilter) { mockAppsFilter }
whenever(this.context) { mockContext }
whenever(this.getHandler()) { testHandler }
+ whenever(this.sharedLibrariesImpl) { mockSharedLibrariesImpl }
}
val testParams = PackageManagerServiceTestParams().apply {
this.pendingPackageBroadcasts = mockPendingBroadcasts
diff --git a/services/tests/apexsystemservices/Android.bp b/services/tests/apexsystemservices/Android.bp
new file mode 100644
index 0000000..01e90a8
--- /dev/null
+++ b/services/tests/apexsystemservices/Android.bp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_test_host {
+ name: "ApexSystemServicesTestCases",
+ srcs: ["src/**/*.java"],
+ libs: ["tradefed"],
+ java_resources: [
+ ":test_com.android.server",
+ ],
+ static_libs: [
+ "compatibility-host-util",
+ "cts-install-lib-host",
+ "frameworks-base-hostutils",
+ "truth-prebuilt",
+ "modules-utils-build-testing",
+ ],
+ test_suites: ["device-tests"],
+}
diff --git a/services/tests/apexsystemservices/AndroidTest.xml b/services/tests/apexsystemservices/AndroidTest.xml
new file mode 100644
index 0000000..edfefea
--- /dev/null
+++ b/services/tests/apexsystemservices/AndroidTest.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<configuration description="Tests for apex-system-service support">
+ <option name="config-descriptor:metadata" key="component" value="misc" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="ApexSystemServicesTestCases.jar" />
+ </test>
+</configuration>
diff --git a/services/tests/apexsystemservices/OWNERS b/services/tests/apexsystemservices/OWNERS
new file mode 100644
index 0000000..0295b9e
--- /dev/null
+++ b/services/tests/apexsystemservices/OWNERS
@@ -0,0 +1,4 @@
+omakoto@google.com
+satayev@google.com
+
+include platform/packages/modules/common:/OWNERS
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/Android.bp b/services/tests/apexsystemservices/apexes/test_com.android.server/Android.bp
new file mode 100644
index 0000000..16d6241
--- /dev/null
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/Android.bp
@@ -0,0 +1,40 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+apex_key {
+ name: "test_com.android.server.key",
+ public_key: "test_com.android.server.avbpubkey",
+ private_key: "test_com.android.server.pem",
+ installable: false,
+}
+
+android_app_certificate {
+ name: "test_com.android.server.certificate",
+ certificate: "test_com.android.server",
+}
+
+apex_test {
+ name: "test_com.android.server",
+ manifest: "manifest.json",
+ androidManifest: "AndroidManifest.xml",
+ java_libs: ["FakeApexSystemService"],
+ file_contexts: ":apex.test-file_contexts",
+ key: "test_com.android.server.key",
+ updatable: false,
+ installable: false,
+}
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/AndroidManifest.xml b/services/tests/apexsystemservices/apexes/test_com.android.server/AndroidManifest.xml
new file mode 100644
index 0000000..48cee7e
--- /dev/null
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="test_com.android.server">
+ <!-- APEX does not have classes.dex -->
+ <application android:hasCode="false">
+ <apex-system-service
+ android:name="com.android.server.testing.FakeApexSystemService"
+ android:path="/apex/test_com.android.server/javalib/FakeApexSystemService.jar"
+ android:minSdkVersion="30"/>
+
+ <!-- Always inactive system service, since maxSdkVersion is low -->
+ <apex-system-service
+ android:name="com.android.apex.test.OldApexSystemService"
+ android:path="/apex/com.android.apex.test/javalib/fake.jar"
+ android:minSdkVersion="1"
+ android:maxSdkVersion="1"
+ />
+
+ <!-- Always inactive system service, since minSdkVersion is high -->
+ <apex-system-service
+ android:name="com.android.apex.test.NewApexSystemService"
+ android:path="/apex/com.android.apex.test/javalib/fake.jar"
+ android:minSdkVersion="999999"
+ />
+ </application>
+</manifest>
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/manifest.json b/services/tests/apexsystemservices/apexes/test_com.android.server/manifest.json
new file mode 100644
index 0000000..5e48532
--- /dev/null
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "test_com.android.server",
+ "version": 1
+}
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.avbpubkey b/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.avbpubkey
new file mode 100644
index 0000000..4f4acd6
--- /dev/null
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.avbpubkey
Binary files differ
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.pem b/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.pem
new file mode 100644
index 0000000..f391ef0
--- /dev/null
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAur/sf1yom0DzYXRG4HaigR2qjUwPOtxr+cfVem0OxZeSTc5X
+W8cueEFcYvE3G3FOpxfv5FBtSFvAJaV+N8v8pWRoTgIxA0Squf0oH+PPqT11GQ6r
+Nhw78Wvw8+CdWJDE0ATK6Jlvail65KbcjgwkQyLhBXLNV2mX4BW7QimVbma49B6V
+P0NDW3ymbG7iO8CiuAVsN4SIpGa12W0Dwh/UBBXPkBcybo/tRQL9tcpismI46/Qj
+t6VvWwNn7M97zpGtvLLUqB+tinamo+cYJtNmkgIP3w3pvritYYuILIFBgzSx3MMb
+VtfQ/0fgtNJJkfHS5qb7kd1PRzcehVX9Ej6UCQN/iP+fv7vtP9l9cJZ4nxHDzkBg
+/oxqzdCWks1SU3Kq2+OGKg6B/4+H64Igf5B48/mmZ8Ss3xHPS2bq5lGE998hVtUL
+D7KhnX8F5J9X+yE0hME6Biekpo/w/8JHATl5iidRDfhYWwawkjuHExtdY4TibfuC
+y4ol7mv3UQEdzfsNKSUIEWurVbKfqDmj29MiyF0F7VCak3NlB3ZZyIvEiglQTqoh
+uNKkfFYHccZQhihk1CpQ6cv31H+QcEAN+osGk0dKm5h6kf1hUfn02KMFSnv7u/yk
+QOhLmNpPekbLrqvYvNAwYU/lQ6qZIuyIXudZaJ3MoWq5YtCEeexBQPP5sa0CAwEA
+AQKCAgAHyasmIIoTd2Du5ndyMuBR/Be5rrtP3BNQpkm7wkKEcO6z+e/gruy8LRWa
+Nq7yoQYDp9bkMYptIw5fQ4iA8SvHBennnuXGWh24hdsfgVOOnjZ85gSzy/ef+L1i
+njJRmC/s8NY5XvSre7FZSbAW6GC2wAScQo5Xn9qqiJ13g95sbTI3U/MrYTW04fza
+tsEOdtkSTX+WzRsZqALbX1VxyfwAc5xlSOJcg/oED7ze0OLOx5PSGytGJEsBg6HY
+2UozchXJsbd2j2OgS5Rlb2StcdFsM1PQHHdr8a2hTL1QBc/ildb4+tXwCC36B1hS
+khZpVKlT3xDMo2sD8EOAkfZsxVlM+K5Yq98nZx92AxSYC+tmHf87YHPvV1fDyKv9
+w/fG77mR1EqaQCMsWeYZFSa7KDKRaKFt8MlGCQYYzQyHxXf+DFq9z375TMLQB1NX
+RZp5aDjlzLQYD75N6nyo5uboE+YG40WEgWoc96j1nnVG37DO6jxpHipEJB9yAYiS
+m4jzsl1msMmnUDqswCZgiTOtdxsgjbQqwLlS/t6cycnjrcPQo0Fz1AxBQ2BIKTCQ
+wBn1CE+S/2grTnM8vWXVbZSOg4gulrcaLd1ec8gWme0Vz0JTUBtwslAK14s2wTTE
+PlI5ZqsnXy3rVbGkh4gNTZdi/4xvtJodi4dItp6azsJDd4V/jQKCAQEA4e4Dlpwz
+/TgBNn+htMsGgtAXTXEGn3WSkyei0QYkDwWkrL+EOyNJXKcBl8IMK4yy7vumy6fn
+PmRc9+gu52mzm7pqpmqzW5xgJMfvW57wKDTrhxbRSThXf4wBLiuMz9VutZWwY2kA
+zsfroOmERSxWba8tdFlgP6hSjlSP0wolg71ba9n8oFJIN7m6sDadOUtH+xFGkX4T
+QSC1o0ofq0mx+Q8mXI1LDgZofaJacaBcI1FeoaR1tzPU2OoOXz7XkSG5X7osu+e9
+afW1c5dQH2FU3by7JGZv+z3rlsWsUI0OHnsDm4k6om7HGdF0oUqxnXlT4zYa1y7j
+MIDHsp1p7wonewKCAQEA05ry49TfXcW3y35ns+zp06xNmYwKui3L01OLe0NjnCy0
+RsDKGa0pT/fFXGH7OOx6cVgtVCPlWFKv8S5KMgU0rnyLfhQn6NqjuIh2oMLIls3D
+mnCxjwzkHMx2nF4+Sih7nYgOJ/BY1afmErXJkh+SYPtMRsZJoIS3OCkQaikWN7Ne
+nPP/EumuU+tj4aTSbrK4mbcpPS8S3YhDLKPNQNHrWlbJjkxGFico+HSlXZ068vDd
+sldVlJL9z8+dCe6B2wLobtpBP1gR0mjb8CXrBdQ9VC0hdwlYsUlpCGI71BrfCkUV
+oHCWRlWWZvLg0L/qpgF/UlmgXnI3Ii+WXwH1A4iu9wKCAQBdy7qhpGfREJcwUPyJ
+WmBxnoKOHAZr3RvlC+eEb9A4jFc5gKkdBCFI3ezDXERBMEB5BvDQS/ys4m3WXgZa
+/H8cf+AXBuU/e0RPANJWbz2084N0qfxpMYLh6PX0fRAQmMNFj8eS/dzf/A/O1iOb
+tDSNhNSSISjcRL1BacnsC6JXdx2lQPKofICO4gSnc4UCbEaN7TYm4PiNaU7/Y56S
+Nh41EB0U/3PRdseaoPR7h9+4qednpCdaz6HmDAW7dRN5pU6Yd2pq+GKiwud5/a+9
+12KsS9ZF3mFPJP3Rsm8/YdAix19QC0DUfrkZ9uM8sw3aGqzA/41VGJopYM2HUeLQ
+4p5RAoIBAQDOWvH5GrQFN3aIXSn2fdh9ky9NyRMBAv4dhQCl4U73k2TvBr1QEt0R
+3he6gtbCaWLyu8HgpuzWmDR6J+E1LHx2mIBUIIXW/7jfkTzWg32oCttw9etCDJk8
+OGyHCyUFnrsGIhNkAXAwU377ygnblSxjpU16S46rmiEvBGS8knrXMPXYa93Y7MgT
+kJ8kAl8wktuRE9yEjS6BmYugsdDNIKm6vJ3sRhenLOM4gFBvnZBKMHiSnbaYoEwi
+Z13GvLAoC4rt56vvgQxIO/gYFnI+if6Q4z4aXqP+qA9knJ+ptdbCpiJ0BreVuYtl
+s/9ns3C6GQW4Ii1RTWLU1MF4v2jX3Gh7AoIBAQCDoeQeJFpoU7yF34RN8reZjxZ4
+nF2Yj2B4vpdeT28iMPhl01Ctay7m0FQcc2CdtRcogtYIvxT+6sMeXvIM1hAEjaTn
+ps3GusyAFrn58oZzxhoKPmQfNVVqFM9BDeixhKv0HjOvc/sJaWnMWtYkUil8NoOk
+o/Py8a3tcGDv/a2rPn4ZBOAiGe0oO9ed/lNKqmxcGaEEhRuboZcvwPgq6eY6UV4r
+IJ9CB3zV8nPXKQXLAatg5xaS25YrLofL02wnUtm/k3fWyIxX2pFg19KiKuG7ywpY
+OnaWweSoDhPOeYVQjP9U9CzcaofffsNP/1dvqJRDm6fRBE3qaGhIcTFMC3xy
+-----END RSA PRIVATE KEY-----
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.pk8 b/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.pk8
new file mode 100644
index 0000000..ca45333
--- /dev/null
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.pk8
Binary files differ
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.x509.pem b/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.x509.pem
new file mode 100644
index 0000000..13a3058
--- /dev/null
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/test_com.android.server.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF3TCCA8UCFBYj125aAL6TlF+vGODQhEUq6/AXMA0GCSqGSIb3DQEBCwUAMIGp
+MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
+bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi
+MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTElMCMGA1UEAwwcdGVz
+dF9jb20uYW5kcm9pZC5zZXJ2ZXIuYXBleDAgFw0yMTEyMTQxNTUyMjBaGA80NzU5
+MTExMDE1NTIyMFowgakxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlh
+MRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYD
+VQQLDAdBbmRyb2lkMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQuY29t
+MSUwIwYDVQQDDBx0ZXN0X2NvbS5hbmRyb2lkLnNlcnZlci5hcGV4MIICIjANBgkq
+hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsiWlZYCPg2ZyOQbxwwH9F2SCM5h7KIQS
+RIsHkbTiXWmrIV3SS4LX6u3Phf/Uo275aFgLX+BqBPx4FPdN2FQYpqiS7BZ1dQm6
+vGFYSCPPVt8HIs5eEswwPt3cJUe+7jaeAW5n+kuV2lmv/K5Xr4HWhG6ywAvMzK5M
+uHKkz7Q6BgkFyDBAq7iyGNaxBRu0v+RIzZkSq/UDjPsG4o+lBiY+jhcMV37NZvTo
+3xqq2ia0wKK5GUsaZ6OGYP22+RtSu/jIV1LWE9ukucFes8BfnBGKq9DvF+qviPuV
+BsGckuet2Oa2Ty44ffviWmKTEJi4/MZ7o+uiP4bWyh3C1iP7acXNDDEt3nEiceF7
+1wKJkYMay8IZ3VWczQieZWN5oxNBZSE+kMi+ZOolcs2tRi2EO0KsjVN63fhi75WZ
+kGTl4J/G0irWBHOBHvosL4EcEboV1B2QsfDvjvpAIQkhqG0IKrN2czN+xzcMeJRr
+CXRRLLkdTS1DLXKaTTZg/U1MfhRfrqY8OCOKT2IhmqmKajhOIXXrKNt+0VfHjweL
+RbF7mgwb7jyKe3Cy1WlEqQXuZRbHSQ6aSfQ/nbMFaj+MQn3KULBciHGjZB0fQC4Z
+P+CMwZpdbBRA2VdrOZ8cvOxp88MrdSaz6RuSbQIu70THM7hmzXd9iEzjmmJ6bbaJ
+P9/nR38HoxUCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAkSVfES3KoY8z1nb0KEcS
+LCldTE0X+5vZ6n+8Bwy04Tb6Evdhui2dtgtKTwQMSZ4qS6bUnnwJgAcswV2LCeui
+sosUNB4prNdlLZeZmCg+SimNM9AZIpJaMAtlbCiAMRb0yN+I7nAIcNv/HhGLVYte
+JGyoxkm73m82YCyRPG8FPsKMufoDeUo3mOnVXKLYgeq5er2YN1bWYjCE5X6mWV85
+iyGGK/X6h4ANybxqp4sFLOwQzgm7HfYrsm0RadN95PhUiSqlVGJHo/EJixK0sNYS
+VzDtGqo+i3wWww9rVUiMroRRMf6thXY4O1TqU2Sn2H3OMasIUT+w1Y1KONpJyE58
+2Yi+865msa2l8BGH8qPNgHERLlMZcIm5LfFTHw/9QniJdfHo6PEJoSzSmT4yDOMa
+WYmafNdR3FfKdGGGHJZWVUtMSxlGe7DjzVhm0M3vHgEldsEMLnwOjecDQq3ssXsC
+0mOCabaSpAZA0p0c2sQuhzij1mFxNaEEhbEZ93klz2+e1u7Q/xPiGMYCQky/+WsL
+aYBuo0AbCtTEvy92vhTc0KphVoeY7X/VEojkDfmm8wHvAtOBr03t6jLGWmGcGPJp
+/Opxik2IZKAm27HeN1ICJGUTiky5ULj1DmrdiMQhkvz0jNoNJvjJsbeQnOs0te6J
+bR8InfVgdeIr68zrlvC+SfE=
+-----END CERTIFICATE-----
diff --git a/services/tests/apexsystemservices/service/Android.bp b/services/tests/apexsystemservices/service/Android.bp
new file mode 100644
index 0000000..9d04f39
--- /dev/null
+++ b/services/tests/apexsystemservices/service/Android.bp
@@ -0,0 +1,20 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_library {
+ name: "FakeApexSystemService",
+ srcs: ["**/*.java"],
+ sdk_version: "system_server_current",
+ libs: [
+ "framework-annotations-lib",
+ "androidx.annotation_annotation",
+ ],
+ visibility: ["//frameworks/base/services/tests/apexsystemservices:__subpackages__"],
+ apex_available: ["//apex_available:anyapex"],
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java b/services/tests/apexsystemservices/service/src/com/android/server/testing/FakeApexSystemService.java
similarity index 63%
rename from packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java
rename to services/tests/apexsystemservices/service/src/com/android/server/testing/FakeApexSystemService.java
index 09b6fab..4947c34 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.java
+++ b/services/tests/apexsystemservices/service/src/com/android/server/testing/FakeApexSystemService.java
@@ -14,28 +14,28 @@
* limitations under the License.
*/
-package com.android.systemui.biometrics;
+package com.android.server.testing;
import android.content.Context;
-import android.graphics.Canvas;
+import android.util.Log;
import androidx.annotation.NonNull;
-/**
- * Draws udfps fingerprint if sensor isn't illuminating.
- */
-public class UdfpsFpDrawable extends UdfpsDrawable {
+import com.android.server.SystemService;
- UdfpsFpDrawable(@NonNull Context context) {
+/**
+ * A fake system service that just logs when it is started.
+ */
+public class FakeApexSystemService extends SystemService {
+
+ private static final String TAG = "FakeApexSystemService";
+
+ public FakeApexSystemService(@NonNull Context context) {
super(context);
}
@Override
- public void draw(@NonNull Canvas canvas) {
- if (isIlluminationShowing()) {
- return;
- }
-
- mFingerprintDrawable.draw(canvas);
+ public void onStart() {
+ Log.d(TAG, "FakeApexSystemService onStart");
}
}
diff --git a/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java b/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java
new file mode 100644
index 0000000..2b453a9
--- /dev/null
+++ b/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.cts.install.lib.host.InstallUtilsHost;
+
+import com.android.internal.util.test.SystemPreparer;
+import com.android.modules.utils.build.testing.DeviceSdkLevel;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class ApexSystemServicesTestCases extends BaseHostJUnit4Test {
+
+ private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this);
+ private final TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+ private final SystemPreparer mPreparer = new SystemPreparer(mTemporaryFolder, this::getDevice);
+
+ @Rule
+ public final RuleChain ruleChain = RuleChain.outerRule(mTemporaryFolder).around(mPreparer);
+
+ private DeviceSdkLevel mDeviceSdkLevel;
+ private ITestDevice mDevice;
+
+ @Before
+ public void setup() throws Exception {
+ mDevice = getDevice();
+ mDeviceSdkLevel = new DeviceSdkLevel(getDevice());
+
+ assumeTrue(mDeviceSdkLevel.isDeviceAtLeastT());
+
+ assertThat(mDevice.enableAdbRoot()).isTrue();
+ assertThat(mHostUtils.isApexUpdateSupported()).isTrue();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mDevice.disableAdbRoot();
+ }
+
+ @Test
+ public void noApexSystemServerStartsWithoutApex() throws Exception {
+ mPreparer.reboot();
+
+ assertThat(getFakeApexSystemServiceLogcat())
+ .doesNotContain("FakeApexSystemService onStart");
+ }
+
+ @Test
+ public void apexSystemServerStarts() throws Exception {
+ // Pre-install the apex
+ String apex = "test_com.android.server.apex";
+ mPreparer.pushResourceFile(apex, "/system/apex/" + apex);
+ // Reboot activates the apex
+ mPreparer.reboot();
+
+ assertThat(getFakeApexSystemServiceLogcat())
+ .contains("FakeApexSystemService onStart");
+ }
+
+ private String getFakeApexSystemServiceLogcat() throws DeviceNotAvailableException {
+ return mDevice.executeAdbCommand("logcat", "-v", "brief", "-d", "FakeApexSystemService:D",
+ "*:S");
+ }
+
+}
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 48a8b1b..8538603 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -59,6 +59,7 @@
"mockingservicestests-utils-mockito",
"servicestests-core-utils",
"testables",
+ "kotlin-test",
// TODO: remove once Android migrates to JUnit 4.12, which provides assertThrows
"testng",
],
diff --git a/services/tests/mockingservicestests/assets/GameServiceSelectorTest/game_service_metadata_valid.xml b/services/tests/mockingservicestests/assets/GameServiceSelectorTest/game_service_metadata_valid.xml
new file mode 100644
index 0000000..4720085
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/GameServiceSelectorTest/game_service_metadata_valid.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<game-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:sessionService="com.game.service.provider.GameSessionService"/>
diff --git a/services/tests/mockingservicestests/res/xml/game_service_metadata_no_session_service.xml b/services/tests/mockingservicestests/res/xml/game_service_metadata_no_session_service.xml
new file mode 100644
index 0000000..ebd5103
--- /dev/null
+++ b/services/tests/mockingservicestests/res/xml/game_service_metadata_no_session_service.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<game-service/>
diff --git a/services/tests/mockingservicestests/res/xml/game_service_metadata_valid.xml b/services/tests/mockingservicestests/res/xml/game_service_metadata_valid.xml
new file mode 100644
index 0000000..8ee3cce
--- /dev/null
+++ b/services/tests/mockingservicestests/res/xml/game_service_metadata_valid.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<game-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:gameSessionService="com.game.service.provider.GameSessionService"/>
diff --git a/services/tests/mockingservicestests/res/xml/game_service_metadata_wrong_first_tag.xml b/services/tests/mockingservicestests/res/xml/game_service_metadata_wrong_first_tag.xml
new file mode 100644
index 0000000..6bc0eac
--- /dev/null
+++ b/services/tests/mockingservicestests/res/xml/game_service_metadata_wrong_first_tag.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<wrong-tag xmlns:android="http://schemas.android.com/apk/res/android"
+ android:gameSessionService="com.game.service.provider.GameSessionService"/>
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/FakeGameClassifier.java b/services/tests/mockingservicestests/src/com/android/server/app/FakeGameClassifier.java
new file mode 100644
index 0000000..060b773
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/app/FakeGameClassifier.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+import android.annotation.NonNull;
+import android.os.UserHandle;
+
+import java.util.HashSet;
+
+/**
+ * Fake implementation of {@link GameClassifier} used for tests.
+ *
+ * By default, all packages are considers not games. A package may be marked as a game using
+ * {@link #recordGamePackage(String)}.
+ */
+final class FakeGameClassifier implements GameClassifier {
+ private final HashSet<String> mGamePackages = new HashSet<>();
+
+ /**
+ * Marks the given {@code packageName} as a game.
+ */
+ public void recordGamePackage(String packageName) {
+ mGamePackages.add(packageName);
+ }
+
+ @Override
+ public boolean isGame(@NonNull String packageName, UserHandle userHandle) {
+ return mGamePackages.contains(packageName);
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/FakeGameServiceProviderInstance.java b/services/tests/mockingservicestests/src/com/android/server/app/FakeGameServiceProviderInstance.java
new file mode 100644
index 0000000..98142f5
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/app/FakeGameServiceProviderInstance.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+
+/**
+ * Fake implementation of {@link GameServiceProviderInstance} used for tests.
+ */
+final class FakeGameServiceProviderInstance implements GameServiceProviderInstance {
+ private boolean mRunning;
+
+ @Override
+ public void start() {
+ mRunning = true;
+ }
+
+ @Override
+ public void stop() {
+ mRunning = false;
+ }
+
+ /**
+ * Returns {@code true} if the instance is currently running.
+ */
+ public boolean getIsRunning() {
+ return mRunning;
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/FakeServiceConnector.java b/services/tests/mockingservicestests/src/com/android/server/app/FakeServiceConnector.java
new file mode 100644
index 0000000..0ae509e
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/app/FakeServiceConnector.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+
+import android.os.IInterface;
+
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.infra.ServiceConnector;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Fake implementation of {@link ServiceConnector<T>} used for tests.
+ *
+ * Tests provide a service instance via {@link #FakeServiceConnector(IInterface)} that will be
+ * connected to and used to fulfill service jobs.
+ */
+final class FakeServiceConnector<T extends IInterface> implements
+ ServiceConnector<T> {
+ private final T mService;
+ private boolean mIsConnected;
+ private int mConnectCount = 0;
+
+ FakeServiceConnector(T service) {
+ mService = service;
+ }
+
+ @Override
+ public boolean run(VoidJob<T> job) {
+ AndroidFuture<Void> unusedFuture = post(job);
+ return true;
+ }
+
+ @Override
+ public AndroidFuture<Void> post(VoidJob<T> job) {
+ markPossibleConnection();
+
+ return postForResult(job);
+ }
+
+ @Override
+ public <R> AndroidFuture<R> postForResult(Job<T, R> job) {
+ markPossibleConnection();
+
+ AndroidFuture<R> androidFuture = new AndroidFuture();
+ try {
+ androidFuture.complete(job.run(mService));
+ } catch (Exception ex) {
+ androidFuture.completeExceptionally(ex);
+ }
+ return androidFuture;
+ }
+
+ @Override
+ @SuppressWarnings("FutureReturnValueIgnored")
+ public <R> AndroidFuture<R> postAsync(Job<T, CompletableFuture<R>> job) {
+ markPossibleConnection();
+ AndroidFuture<R> androidFuture = new AndroidFuture();
+
+ try {
+ CompletableFuture<R> future = job.run(mService);
+ future.whenComplete((result, exception) -> {
+ if (exception != null) {
+ androidFuture.completeExceptionally(exception);
+ } else {
+ androidFuture.complete(result);
+ }
+ });
+ } catch (Exception ex) {
+ androidFuture.completeExceptionally(ex);
+ }
+
+ return androidFuture;
+ }
+
+ @Override
+ public AndroidFuture<T> connect() {
+ markPossibleConnection();
+ return AndroidFuture.completedFuture(mService);
+ }
+
+ @Override
+ public void unbind() {
+ mIsConnected = false;
+ }
+
+ private void markPossibleConnection() {
+ if (mIsConnected) {
+ return;
+ }
+
+ mConnectCount += 1;
+ mIsConnected = true;
+ }
+
+ /**
+ * Returns {@code true} if the underlying service is connected.
+ */
+ public boolean getIsConnected() {
+ return mIsConnected;
+ }
+
+ /**
+ * Returns the number of times a connection was established with the underlying service.
+ */
+ public int getConnectCount() {
+ return mConnectCount;
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java
new file mode 100644
index 0000000..0545fde
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.ConcurrentUtils;
+import com.android.server.SystemService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+
+/** Unit tests for {@link GameServiceController}. */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public final class GameServiceControllerTest {
+ private static final UserHandle USER_HANDLE_10 = new UserHandle(10);
+ private static final UserHandle USER_HANDLE_11 = new UserHandle(11);
+ private static final SystemService.TargetUser USER_10 = user(10);
+ private static final SystemService.TargetUser USER_11 = user(11);
+ private static final String PROVIDER_A_PACKAGE_NAME = "com.provider.a";
+ private static final ComponentName PROVIDER_A_SERVICE_A =
+ new ComponentName(PROVIDER_A_PACKAGE_NAME, "com.provider.a.ServiceA");
+ private static final ComponentName PROVIDER_A_SERVICE_B =
+ new ComponentName(PROVIDER_A_PACKAGE_NAME, "com.provider.a.ServiceB");
+
+ private MockitoSession mMockingSession;
+ private GameServiceController mGameServiceManager;
+ @Mock
+ private GameServiceProviderSelector mMockGameServiceProviderSelector;
+ @Mock
+ private GameServiceProviderInstanceFactory mMockGameServiceProviderInstanceFactory;
+
+ @Before
+ public void setUp() throws Exception {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ mGameServiceManager = new GameServiceController(
+ ConcurrentUtils.DIRECT_EXECUTOR,
+ mMockGameServiceProviderSelector,
+ mMockGameServiceProviderInstanceFactory);
+ }
+
+ @After
+ public void tearDown() {
+ mMockingSession.finishMocking();
+ }
+
+ @Test
+ public void notifyUserStarted_hasNotCompletedBoot_doesNothing() {
+ mGameServiceManager.notifyUserStarted(USER_10);
+
+ verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
+ }
+
+ @Test
+ public void notifyUserStarted_createsAndStartsNewInstance() {
+ GameServiceProviderConfiguration configurationA =
+ new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
+ PROVIDER_A_SERVICE_B);
+ FakeGameServiceProviderInstance instanceA =
+ seedConfigurationForUser(USER_10, configurationA);
+
+ mGameServiceManager.onBootComplete();
+ mGameServiceManager.notifyUserStarted(USER_10);
+
+ verify(mMockGameServiceProviderInstanceFactory).create(configurationA);
+ verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
+ assertThat(instanceA.getIsRunning()).isTrue();
+ }
+
+ @Test
+ public void notifyUserStarted_sameUser_doesNotCreateNewInstance() {
+ GameServiceProviderConfiguration configurationA =
+ new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
+ PROVIDER_A_SERVICE_B);
+ FakeGameServiceProviderInstance instanceA =
+ seedConfigurationForUser(USER_10, configurationA);
+
+ mGameServiceManager.onBootComplete();
+ mGameServiceManager.notifyUserStarted(USER_10);
+ mGameServiceManager.notifyUserStarted(USER_10);
+
+ verify(mMockGameServiceProviderInstanceFactory).create(configurationA);
+ verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
+ assertThat(instanceA.getIsRunning()).isTrue();
+ }
+
+ @Test
+ public void notifyUserUnlocking_noForegroundUser_ignores() {
+ GameServiceProviderConfiguration configurationA =
+ new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
+ PROVIDER_A_SERVICE_B);
+ FakeGameServiceProviderInstance instanceA =
+ seedConfigurationForUser(USER_10, configurationA);
+
+ mGameServiceManager.onBootComplete();
+ mGameServiceManager.notifyUserUnlocking(USER_10);
+
+ verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
+ assertThat(instanceA.getIsRunning()).isFalse();
+ }
+
+ @Test
+ public void notifyUserUnlocking_sameAsForegroundUser_evaluatesProvider() {
+ GameServiceProviderConfiguration configurationA =
+ new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
+ PROVIDER_A_SERVICE_B);
+ seedNoConfigurationForUser(USER_10);
+
+ mGameServiceManager.onBootComplete();
+ mGameServiceManager.notifyUserStarted(USER_10);
+ FakeGameServiceProviderInstance instanceA =
+ seedConfigurationForUser(USER_10, configurationA);
+ mGameServiceManager.notifyUserUnlocking(USER_10);
+
+ verify(mMockGameServiceProviderInstanceFactory).create(configurationA);
+ verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
+ assertThat(instanceA.getIsRunning()).isTrue();
+ }
+
+ @Test
+ public void notifyUserUnlocking_differentFromForegroundUser_ignores() {
+ GameServiceProviderConfiguration configurationA =
+ new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
+ PROVIDER_A_SERVICE_B);
+ seedNoConfigurationForUser(USER_10);
+
+ mGameServiceManager.onBootComplete();
+ mGameServiceManager.notifyUserStarted(USER_10);
+ FakeGameServiceProviderInstance instanceA =
+ seedConfigurationForUser(USER_11, configurationA);
+ mGameServiceManager.notifyUserUnlocking(USER_11);
+
+ verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
+ assertThat(instanceA.getIsRunning()).isFalse();
+ }
+
+ @Test
+ public void
+ notifyNewForegroundUser_differentUser_stopsPreviousInstanceAndThenStartsNewInstance() {
+ GameServiceProviderConfiguration configurationA =
+ new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
+ PROVIDER_A_SERVICE_B);
+ FakeGameServiceProviderInstance instanceA =
+ seedConfigurationForUser(USER_10, configurationA);
+ GameServiceProviderConfiguration configurationB =
+ new GameServiceProviderConfiguration(USER_HANDLE_11, PROVIDER_A_SERVICE_A,
+ PROVIDER_A_SERVICE_B);
+ FakeGameServiceProviderInstance instanceB = seedConfigurationForUser(USER_11,
+ configurationB);
+ InOrder instancesInOrder = Mockito.inOrder(instanceA, instanceB);
+
+ mGameServiceManager.onBootComplete();
+ mGameServiceManager.notifyUserStarted(USER_10);
+ mGameServiceManager.notifyNewForegroundUser(USER_11);
+
+ verify(mMockGameServiceProviderInstanceFactory).create(configurationA);
+ verify(mMockGameServiceProviderInstanceFactory).create(configurationB);
+ instancesInOrder.verify(instanceA).start();
+ instancesInOrder.verify(instanceA).stop();
+ instancesInOrder.verify(instanceB).start();
+ verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
+ assertThat(instanceA.getIsRunning()).isFalse();
+ assertThat(instanceB.getIsRunning()).isTrue();
+ }
+
+ private void seedNoConfigurationForUser(SystemService.TargetUser user) {
+ when(mMockGameServiceProviderSelector.get(user)).thenReturn(null);
+ }
+
+ private FakeGameServiceProviderInstance seedConfigurationForUser(SystemService.TargetUser user,
+ GameServiceProviderConfiguration configuration) {
+ when(mMockGameServiceProviderSelector.get(user)).thenReturn(configuration);
+ FakeGameServiceProviderInstance instanceForConfiguration =
+ spy(new FakeGameServiceProviderInstance());
+ when(mMockGameServiceProviderInstanceFactory.create(configuration))
+ .thenReturn(instanceForConfiguration);
+
+ return instanceForConfiguration;
+ }
+
+ private static SystemService.TargetUser user(int userId) {
+ UserInfo userInfo = new UserInfo(userId, "", "", UserInfo.FLAG_FULL);
+ return new SystemService.TargetUser(userInfo);
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTests.java
deleted file mode 100644
index 8973a89..0000000
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTests.java
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.app;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.platform.test.annotations.Presubmit;
-import android.service.games.GameService;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.SystemService;
-
-import com.google.common.collect.ImmutableList;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoSession;
-
-import java.util.List;
-
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-@Presubmit
-public final class GameServiceControllerTests {
- @Mock
- private PackageManager mMockPackageManager;
- @Mock
- private Resources mMockResources;
- @Mock
- private Context mMockContext;
- private MockitoSession mMockingSession;
-
- private static UserInfo eligibleUserInfo(int uid) {
- return new UserInfo(uid, "", "", UserInfo.FLAG_FULL);
- }
-
- private static UserInfo managedUserInfo(int uid) {
- UserInfo userInfo = eligibleUserInfo(uid);
- userInfo.userType = UserManager.USER_TYPE_PROFILE_MANAGED;
- return userInfo;
- }
-
- private static ResolveInfo resolveInfo(ServiceInfo serviceInfo) {
- ResolveInfo resolveInfo = new ResolveInfo();
- resolveInfo.serviceInfo = serviceInfo;
- return resolveInfo;
- }
-
- private static ServiceInfo serviceInfo(String packageName, String name, boolean isEnabled) {
- ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.packageName = packageName;
- applicationInfo.enabled = true;
-
- ServiceInfo serviceInfo = new ServiceInfo();
- serviceInfo.applicationInfo = applicationInfo;
- serviceInfo.packageName = packageName;
- serviceInfo.name = name;
- serviceInfo.enabled = isEnabled;
- return serviceInfo;
- }
-
- private static SystemService.TargetUser managedTargetUser(int ineligibleUserId) {
- return new SystemService.TargetUser(managedUserInfo(ineligibleUserId));
- }
-
- private static SystemService.TargetUser eligibleTargetUser(int userId) {
- return new SystemService.TargetUser(eligibleUserInfo(userId));
- }
-
- private static UserHandle userWithId(int userId) {
- return argThat(userInfo -> userInfo.getIdentifier() == userId);
- }
-
- @Before
- public void setUp() {
- mMockingSession = mockitoSession()
- .initMocks(this)
- .startMocking();
- }
-
- @After
- public void tearDown() {
- mMockingSession.finishMocking();
- }
-
- @Test
- public void testStartConnectionOnBootWithNoUser() {
- GameServiceController gameServiceController =
- new GameServiceController(mMockContext);
-
- gameServiceController.onBootComplete();
-
- verifyNoServiceBound();
- }
-
- @Test
- public void testStartConnectionOnBootWithManagedUser() {
- int userId = 12345;
- GameServiceController gameServiceController =
- new GameServiceController(mMockContext);
-
- gameServiceController.notifyUserStarted(managedTargetUser(userId));
- gameServiceController.onBootComplete();
-
- verifyNoServiceBound();
- }
-
- @Test
- public void testStartConnectionOnBootWithUserAndNoSystemGamesServiceSet() {
- seedSystemGameServicePackageName("");
-
- GameServiceController gameServiceController =
- new GameServiceController(mMockContext);
-
- gameServiceController.notifyUserStarted(eligibleTargetUser(1000));
- gameServiceController.onBootComplete();
-
- verifyNoServiceBound();
- }
-
- @Test
- public void testStartConnectionOnBootWithUserAndSystemGamesServiceDoesNotExist() {
- int userId = 12345;
- String gameServicePackageName = "game.service.package";
- seedSystemGameServicePackageName(gameServicePackageName);
- seedGameServiceResolveInfos(gameServicePackageName, userId, ImmutableList.of());
-
- GameServiceController gameServiceController =
- new GameServiceController(mMockContext);
-
- gameServiceController.notifyUserStarted(eligibleTargetUser(userId));
- gameServiceController.onBootComplete();
-
- verifyNoServiceBound();
- }
-
- @Test
- public void testStartConnectionOnBootWithUserAndSystemGamesServiceSet() {
- int userId = 12345;
- String gameServicePackageName = "game.service.package";
- String gameServiceComponent = "game.service.package.example.GameService";
- seedSystemGameServicePackageName(gameServicePackageName);
- seedGameServiceResolveInfos(gameServicePackageName, userId, ImmutableList.of(
- resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
-
- GameServiceController gameServiceController =
- new GameServiceController(mMockContext);
-
- gameServiceController.notifyUserStarted(eligibleTargetUser(userId));
- gameServiceController.onBootComplete();
-
- verifyServiceBoundForUserAndComponent(userId, gameServicePackageName, gameServiceComponent);
- }
-
- @Test
- public void testStartConnectionOnBootWithUserAndSystemGamesServiceNotEnabled() {
- int userId = 12345;
- String gameServicePackageName = "game.service.package";
- String gameServiceComponent = "game.service.package.example.GameService";
- seedSystemGameServicePackageName(gameServicePackageName);
- seedGameServiceResolveInfos(gameServicePackageName, userId, ImmutableList.of(
- resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, false))));
-
- GameServiceController gameServiceController =
- new GameServiceController(mMockContext);
-
- gameServiceController.notifyUserStarted(eligibleTargetUser(userId));
- gameServiceController.onBootComplete();
-
- verifyNoServiceBound();
- }
-
- @Test
- public void testStartConnectionOnBootWithUserAndSystemGamesServiceHasMultipleComponents() {
- int userId = 12345;
- String gameServicePackageName = "game.service.package";
- String gameServiceComponent1 = "game.service.package.example.GameService1";
- String gameServiceComponent2 = "game.service.package.example.GameService2";
- seedSystemGameServicePackageName(gameServicePackageName);
- seedGameServiceResolveInfos(gameServicePackageName, userId, ImmutableList.of(
- resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent1, true)),
- resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent2, true))));
-
- GameServiceController gameServiceController =
- new GameServiceController(mMockContext);
-
- gameServiceController.notifyUserStarted(eligibleTargetUser(userId));
- gameServiceController.onBootComplete();
-
- verifyServiceBoundForUserAndComponent(userId, gameServicePackageName,
- gameServiceComponent1);
- }
-
- @Test
- public void testStartConnectionOnBootWithUserAndSystemGamesServiceHasDisabledComponent() {
- int userId = 12345;
- String gameServicePackageName = "game.service.package";
- String gameServiceComponent1 = "game.service.package.example.GameService1";
- String gameServiceComponent2 = "game.service.package.example.GameService2";
- seedSystemGameServicePackageName(gameServicePackageName);
- seedGameServiceResolveInfos(gameServicePackageName, userId, ImmutableList.of(
- resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent1, false)),
- resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent2, true))));
-
- GameServiceController gameServiceController =
- new GameServiceController(mMockContext);
-
- gameServiceController.notifyUserStarted(eligibleTargetUser(userId));
- gameServiceController.onBootComplete();
-
- verifyServiceBoundForUserAndComponent(userId, gameServicePackageName,
- gameServiceComponent2);
- }
-
- @Test
- public void testSwitchFromEligibleUserToEligibleUser() {
- int userId1 = 1;
- int userId2 = 2;
- String gameServicePackageName = "game.service.package";
- String gameServiceComponent = "game.service.package.example.GameService";
- seedSystemGameServicePackageName(gameServicePackageName);
- seedGameServiceResolveInfos(gameServicePackageName, userId1, ImmutableList.of(
- resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
- seedGameServiceResolveInfos(gameServicePackageName, userId2, ImmutableList.of(
- resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
- seedGameServiceToBindSuccessfully();
-
- GameServiceController gameServiceController = new GameServiceController(mMockContext);
-
- gameServiceController.onBootComplete();
- gameServiceController.notifyUserStarted(eligibleTargetUser(userId1));
-
- verifyServiceBoundForUserAndComponent(userId1, gameServicePackageName,
- gameServiceComponent);
-
- gameServiceController.notifyNewForegroundUser(eligibleTargetUser(userId2));
-
- verify(mMockContext).unbindService(any());
- verifyServiceBoundForUserAndComponent(userId2, gameServicePackageName,
- gameServiceComponent);
- }
-
- @Test
- public void testSwitchFromEligibleUserToIneligibleUser() {
- int eligibleUserId = 1;
- int ineligibleUserId = 2;
- String gameServicePackageName = "game.service.package";
- String gameServiceComponent = "game.service.package.example.GameService";
- seedSystemGameServicePackageName(gameServicePackageName);
- seedGameServiceResolveInfos(gameServicePackageName, eligibleUserId, ImmutableList.of(
- resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
- seedGameServiceToBindSuccessfully();
-
- GameServiceController gameServiceController =
- new GameServiceController(mMockContext);
-
- gameServiceController.onBootComplete();
- gameServiceController.notifyUserStarted(eligibleTargetUser(eligibleUserId));
-
- verifyServiceBoundForUserAndComponent(eligibleUserId, gameServicePackageName,
- gameServiceComponent);
-
- gameServiceController.notifyNewForegroundUser(managedTargetUser(ineligibleUserId));
-
- verify(mMockContext).unbindService(any());
- }
-
- @Test
- public void testSwitchFromIneligibleUserToEligibleUser() {
- int eligibleUserId = 1;
- int ineligibleUserId = 2;
- String gameServicePackageName = "game.service.package";
- String gameServiceComponent = "game.service.package.example.GameService";
- seedSystemGameServicePackageName(gameServicePackageName);
- seedGameServiceResolveInfos(gameServicePackageName, eligibleUserId, ImmutableList.of(
- resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
- seedGameServiceToBindSuccessfully();
-
- GameServiceController gameServiceController = new GameServiceController(mMockContext);
-
- gameServiceController.onBootComplete();
- gameServiceController.notifyUserStarted(managedTargetUser(ineligibleUserId));
-
- verifyNoServiceBound();
-
- gameServiceController.notifyNewForegroundUser(eligibleTargetUser(eligibleUserId));
-
- verifyServiceBoundForUserAndComponent(eligibleUserId, gameServicePackageName,
- gameServiceComponent);
- }
-
- @Test
- public void testMultipleRunningUsers() {
- int userId1 = 123;
- int userId2 = 456;
- String gameServicePackageName = "game.service.package";
- String gameServiceComponent = "game.service.package.example.GameService";
- seedSystemGameServicePackageName(gameServicePackageName);
- seedGameServiceResolveInfos(gameServicePackageName, userId1, ImmutableList.of(
- resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
- seedGameServiceToBindSuccessfully();
-
- GameServiceController gameServiceController =
- new GameServiceController(mMockContext);
-
- gameServiceController.onBootComplete();
- gameServiceController.notifyUserStarted(eligibleTargetUser(userId1));
- gameServiceController.notifyUserStarted(eligibleTargetUser(userId2));
-
- verifyServiceBoundForUserAndComponent(userId1, gameServicePackageName,
- gameServiceComponent);
- verifyServiceNotBoundForUser(userId2);
- verify(mMockContext, never()).unbindService(any());
- }
-
- @Test
- public void testForegroundUserStopped() {
- int userId = 123123;
- String gameServicePackageName = "game.service.package";
- String gameServiceComponent = "game.service.package.example.GameService";
- seedSystemGameServicePackageName(gameServicePackageName);
- seedGameServiceResolveInfos(gameServicePackageName, userId, ImmutableList.of(
- resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
- seedGameServiceToBindSuccessfully();
-
- GameServiceController gameServiceController =
- new GameServiceController(mMockContext);
-
- gameServiceController.onBootComplete();
- gameServiceController.notifyUserStarted(eligibleTargetUser(userId));
-
- verifyServiceBoundForUserAndComponent(userId, gameServicePackageName, gameServiceComponent);
-
- gameServiceController.notifyUserStopped(eligibleTargetUser(userId));
-
- verify(mMockContext).unbindService(any());
- }
-
- @Test
- public void testNonForegroundUserStopped() {
- int userId1 = 123;
- int userId2 = 456;
- String gameServicePackageName = "game.service.package";
- String gameServiceComponent = "game.service.package.example.GameService";
- seedSystemGameServicePackageName(gameServicePackageName);
- seedGameServiceResolveInfos(gameServicePackageName, userId1, ImmutableList.of(
- resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
- seedGameServiceResolveInfos(gameServicePackageName, userId2, ImmutableList.of(
- resolveInfo(serviceInfo(gameServicePackageName, gameServiceComponent, true))));
- seedGameServiceToBindSuccessfully();
-
- GameServiceController gameServiceController =
- new GameServiceController(mMockContext);
- InOrder inOrder = Mockito.inOrder(mMockContext);
-
- gameServiceController.onBootComplete();
- gameServiceController.notifyUserStarted(eligibleTargetUser(userId1));
-
- inOrder.verify(mMockContext).bindServiceAsUser(any(), any(), anyInt(), userWithId(userId1));
-
- gameServiceController.notifyNewForegroundUser(eligibleTargetUser(userId2));
-
- inOrder.verify(mMockContext).unbindService(any());
- inOrder.verify(mMockContext).bindServiceAsUser(any(), any(), anyInt(), userWithId(userId2));
-
- gameServiceController.notifyUserStopped(eligibleTargetUser(userId1));
-
- inOrder.verify(mMockContext, never()).unbindService(any());
- }
-
- private void seedSystemGameServicePackageName(String gameServicePackageName) {
- when(mMockContext.getResources()).thenReturn(mMockResources);
- when(mMockResources.getString(com.android.internal.R.string.config_systemGameService))
- .thenReturn(gameServicePackageName);
- }
-
- private void seedGameServiceResolveInfos(String gameServicePackageName, int userId,
- List<ResolveInfo> resolveInfos) {
- when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
- doReturn(resolveInfos)
- .when(mMockPackageManager).queryIntentServicesAsUser(
- argThat(intent ->
- intent != null
- && intent.getAction().equals(GameService.SERVICE_INTERFACE)
- && intent.getPackage().equals(gameServicePackageName)
- ),
- eq(PackageManager.MATCH_SYSTEM_ONLY),
- eq(userId));
- }
-
- private void seedGameServiceToBindSuccessfully() {
- when(mMockContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true);
- }
-
- private void verifyNoServiceBound() {
- verify(mMockContext, never()).bindServiceAsUser(any(), any(), anyInt(), any());
- }
-
- private void verifyServiceBoundForUserAndComponent(int userId, String gameServicePackageName,
- String gameServiceComponent) {
- verify(mMockContext).bindServiceAsUser(
- argThat(intent -> intent.getAction().equals(GameService.SERVICE_INTERFACE)
- && intent.getComponent().getPackageName().equals(gameServicePackageName)
- && intent.getComponent().getClassName().equals(gameServiceComponent)),
- any(),
- anyInt(), argThat(userInfo -> userInfo.getIdentifier() == userId));
- }
-
- private void verifyServiceNotBoundForUser(int userId) {
- verify(mMockContext, never()).bindServiceAsUser(
- any(),
- any(),
- anyInt(), userWithId(userId));
- }
-}
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
new file mode 100644
index 0000000..b6c706e
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
+
+import android.annotation.Nullable;
+import android.app.IActivityTaskManager;
+import android.app.ITaskStackListener;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+import android.service.games.CreateGameSessionRequest;
+import android.service.games.IGameService;
+import android.service.games.IGameSession;
+import android.service.games.IGameSessionService;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.util.ConcurrentUtils;
+import com.android.internal.util.FunctionalUtils.ThrowingConsumer;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
+
+/**
+ * Unit tests for the {@link GameServiceProviderInstanceImpl}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public final class GameServiceProviderInstanceImplTest {
+
+ private static final int USER_ID = 10;
+ private static final String APP_A_PACKAGE = "com.package.app.a";
+ private static final ComponentName APP_A_MAIN_ACTIVITY =
+ new ComponentName(APP_A_PACKAGE, "com.package.app.a.MainActivity");
+
+ private static final String GAME_A_PACKAGE = "com.package.game.a";
+ private static final ComponentName GAME_A_MAIN_ACTIVITY =
+ new ComponentName(GAME_A_PACKAGE, "com.package.game.a.MainActivity");
+
+ private MockitoSession mMockingSession;
+ private GameServiceProviderInstance mGameServiceProviderInstance;
+ @Mock
+ private IActivityTaskManager mMockActivityTaskManager;
+ @Mock
+ private IGameService mMockGameService;
+ @Mock
+ private IGameSessionService mMockGameSessionService;
+ private FakeGameClassifier mFakeGameClassifier;
+ private FakeServiceConnector<IGameService> mFakeGameServiceConnector;
+ private FakeServiceConnector<IGameSessionService> mFakeGameSessionServiceConnector;
+ private ArrayList<ITaskStackListener> mTaskStackListeners;
+ private InOrder mInOrder;
+
+ @Before
+ public void setUp() throws PackageManager.NameNotFoundException, RemoteException {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ mInOrder = inOrder(mMockGameService, mMockGameSessionService);
+
+ mFakeGameClassifier = new FakeGameClassifier();
+ mFakeGameClassifier.recordGamePackage(GAME_A_PACKAGE);
+
+ mFakeGameServiceConnector = new FakeServiceConnector<>(mMockGameService);
+ mFakeGameSessionServiceConnector = new FakeServiceConnector<>(mMockGameSessionService);
+
+ mTaskStackListeners = new ArrayList<>();
+ doAnswer(invocation -> {
+ mTaskStackListeners.add(invocation.getArgument(0));
+ return null;
+ }).when(mMockActivityTaskManager).registerTaskStackListener(any());
+
+ doAnswer(invocation -> {
+ mTaskStackListeners.remove(invocation.getArgument(0));
+ return null;
+ }).when(mMockActivityTaskManager).unregisterTaskStackListener(any());
+
+ mGameServiceProviderInstance = new GameServiceProviderInstanceImpl(
+ new UserHandle(USER_ID),
+ ConcurrentUtils.DIRECT_EXECUTOR,
+ mFakeGameClassifier,
+ mMockActivityTaskManager,
+ mFakeGameServiceConnector,
+ mFakeGameSessionServiceConnector);
+ }
+
+ @After
+ public void tearDown() {
+ mMockingSession.finishMocking();
+ }
+
+ @Test
+ public void start_startsGameSession() throws Exception {
+ mGameServiceProviderInstance.start();
+
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void start_multipleTimes_startsGameSessionOnce() throws Exception {
+ mGameServiceProviderInstance.start();
+
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void stop_neverStarted_doesNothing() throws Exception {
+ mGameServiceProviderInstance.stop();
+
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(0);
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+ mInOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void startAndStop_startsAndStopsGameSession() throws Exception {
+ mGameServiceProviderInstance.start();
+ mGameServiceProviderInstance.stop();
+
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verify(mMockGameService).disconnected();
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void startAndStop_multipleTimes_startsAndStopsGameSessionMultipleTimes()
+ throws Exception {
+ mGameServiceProviderInstance.start();
+ mGameServiceProviderInstance.stop();
+ mGameServiceProviderInstance.start();
+ mGameServiceProviderInstance.stop();
+
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verify(mMockGameService).disconnected();
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verify(mMockGameService).disconnected();
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(2);
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void stop_stopMultipleTimes_stopsGameSessionOnce() throws Exception {
+ mGameServiceProviderInstance.start();
+ mGameServiceProviderInstance.stop();
+ mGameServiceProviderInstance.stop();
+
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verify(mMockGameService).disconnected();
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void gameTaskStarted_neverStarted_doesNothing() throws Exception {
+ dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(0);
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void gameTaskRemoved_neverStarted_doesNothing() throws Exception {
+ dispatchTaskRemoved(10);
+
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(0);
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void gameTaskStarted_afterStopped_doesNothing() throws Exception {
+ mGameServiceProviderInstance.start();
+ mGameServiceProviderInstance.stop();
+ dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verify(mMockGameService).disconnected();
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void appTaskStarted_doesNothing() throws Exception {
+ mGameServiceProviderInstance.start();
+ dispatchTaskCreated(10, APP_A_MAIN_ACTIVITY);
+
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void taskStarted_nullComponentName_ignoresAndDoesNotCrash() throws Exception {
+ mGameServiceProviderInstance.start();
+ dispatchTaskCreated(10, null);
+
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void gameTaskStarted_createsGameSession() throws Exception {
+ CreateGameSessionRequest createGameSessionRequest =
+ new CreateGameSessionRequest(10, GAME_A_PACKAGE);
+ Supplier<AndroidFuture<IBinder>> gameSession10Future =
+ captureCreateGameSessionFuture(createGameSessionRequest);
+
+ mGameServiceProviderInstance.start();
+ dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+ IGameSessionStub gameSession10 = new IGameSessionStub();
+ gameSession10Future.get().complete(gameSession10);
+
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest), any());
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(gameSession10.mIsDestroyed).isFalse();
+ assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+ assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isTrue();
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void gameTaskRemoved_whileAwaitingGameSessionAttached_destroysGameSession()
+ throws Exception {
+ CreateGameSessionRequest createGameSessionRequest =
+ new CreateGameSessionRequest(10, GAME_A_PACKAGE);
+ Supplier<AndroidFuture<IBinder>> gameSession10Future =
+ captureCreateGameSessionFuture(createGameSessionRequest);
+
+ mGameServiceProviderInstance.start();
+ dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+ dispatchTaskRemoved(10);
+ IGameSessionStub gameSession10 = new IGameSessionStub();
+ gameSession10Future.get().complete(gameSession10);
+
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest), any());
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+ assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+ assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isFalse();
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void gameTaskRemoved_destroysGameSession() throws Exception {
+ CreateGameSessionRequest createGameSessionRequest =
+ new CreateGameSessionRequest(10, GAME_A_PACKAGE);
+ Supplier<AndroidFuture<IBinder>> gameSession10Future =
+ captureCreateGameSessionFuture(createGameSessionRequest);
+
+ mGameServiceProviderInstance.start();
+ dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+ IGameSessionStub gameSession10 = new IGameSessionStub();
+ gameSession10Future.get().complete(gameSession10);
+ dispatchTaskRemoved(10);
+
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest), any());
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+ assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+ assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isFalse();
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void gameTaskStarted_multipleTimes_createsMultipleGameSessions() throws Exception {
+ CreateGameSessionRequest createGameSessionRequest10 =
+ new CreateGameSessionRequest(10, GAME_A_PACKAGE);
+ Supplier<AndroidFuture<IBinder>> gameSession10Future =
+ captureCreateGameSessionFuture(createGameSessionRequest10);
+
+ CreateGameSessionRequest createGameSessionRequest11 =
+ new CreateGameSessionRequest(11, GAME_A_PACKAGE);
+ Supplier<AndroidFuture<IBinder>> gameSession11Future =
+ captureCreateGameSessionFuture(createGameSessionRequest11);
+
+ mGameServiceProviderInstance.start();
+ dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+ IGameSessionStub gameSession10 = new IGameSessionStub();
+ gameSession10Future.get().complete(gameSession10);
+
+ dispatchTaskCreated(11, GAME_A_MAIN_ACTIVITY);
+ IGameSessionStub gameSession11 = new IGameSessionStub();
+ gameSession11Future.get().complete(gameSession11);
+
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest10), any());
+ mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest11), any());
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(gameSession10.mIsDestroyed).isFalse();
+ assertThat(gameSession11.mIsDestroyed).isFalse();
+ assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+ assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isTrue();
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void gameTaskRemoved_afterMultipleCreated_destroysOnlyThatGameSession()
+ throws Exception {
+ CreateGameSessionRequest createGameSessionRequest10 =
+ new CreateGameSessionRequest(10, GAME_A_PACKAGE);
+ Supplier<AndroidFuture<IBinder>> gameSession10Future =
+ captureCreateGameSessionFuture(createGameSessionRequest10);
+
+ CreateGameSessionRequest createGameSessionRequest11 =
+ new CreateGameSessionRequest(11, GAME_A_PACKAGE);
+ Supplier<AndroidFuture<IBinder>> gameSession11Future =
+ captureCreateGameSessionFuture(createGameSessionRequest11);
+
+ mGameServiceProviderInstance.start();
+ dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+ IGameSessionStub gameSession10 = new IGameSessionStub();
+ gameSession10Future.get().complete(gameSession10);
+
+ dispatchTaskCreated(11, GAME_A_MAIN_ACTIVITY);
+ IGameSessionStub gameSession11 = new IGameSessionStub();
+ gameSession11Future.get().complete(gameSession11);
+
+ dispatchTaskRemoved(10);
+
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest10), any());
+ mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest11), any());
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+ assertThat(gameSession11.mIsDestroyed).isFalse();
+ assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+ assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isTrue();
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void allGameTasksRemoved_destroysAllGameSessions() throws Exception {
+ CreateGameSessionRequest createGameSessionRequest10 =
+ new CreateGameSessionRequest(10, GAME_A_PACKAGE);
+ Supplier<AndroidFuture<IBinder>> gameSession10Future =
+ captureCreateGameSessionFuture(createGameSessionRequest10);
+
+ CreateGameSessionRequest createGameSessionRequest11 =
+ new CreateGameSessionRequest(11, GAME_A_PACKAGE);
+ Supplier<AndroidFuture<IBinder>> gameSession11Future =
+ captureCreateGameSessionFuture(createGameSessionRequest11);
+
+ mGameServiceProviderInstance.start();
+ dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+ IGameSessionStub gameSession10 = new IGameSessionStub();
+ gameSession10Future.get().complete(gameSession10);
+
+ dispatchTaskCreated(11, GAME_A_MAIN_ACTIVITY);
+ IGameSessionStub gameSession11 = new IGameSessionStub();
+ gameSession11Future.get().complete(gameSession11);
+
+ dispatchTaskRemoved(10);
+ dispatchTaskRemoved(11);
+
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest10), any());
+ mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest11), any());
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+ assertThat(gameSession11.mIsDestroyed).isTrue();
+ assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+ assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isFalse();
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void gameTasksCreated_afterAllPreviousSessionsDestroyed_createsSession()
+ throws Exception {
+ CreateGameSessionRequest createGameSessionRequest10 =
+ new CreateGameSessionRequest(10, GAME_A_PACKAGE);
+ Supplier<AndroidFuture<IBinder>> gameSession10Future =
+ captureCreateGameSessionFuture(createGameSessionRequest10);
+
+ CreateGameSessionRequest createGameSessionRequest11 =
+ new CreateGameSessionRequest(11, GAME_A_PACKAGE);
+ Supplier<AndroidFuture<IBinder>> gameSession11Future =
+ captureCreateGameSessionFuture(createGameSessionRequest11);
+
+ CreateGameSessionRequest createGameSessionRequest12 =
+ new CreateGameSessionRequest(12, GAME_A_PACKAGE);
+ Supplier<AndroidFuture<IBinder>> unusedGameSession12Future =
+ captureCreateGameSessionFuture(createGameSessionRequest12);
+
+ mGameServiceProviderInstance.start();
+ dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+ IGameSessionStub gameSession10 = new IGameSessionStub();
+ gameSession10Future.get().complete(gameSession10);
+
+ dispatchTaskCreated(11, GAME_A_MAIN_ACTIVITY);
+ IGameSessionStub gameSession11 = new IGameSessionStub();
+ gameSession11Future.get().complete(gameSession11);
+
+ dispatchTaskRemoved(10);
+ dispatchTaskRemoved(11);
+
+ dispatchTaskCreated(12, GAME_A_MAIN_ACTIVITY);
+ IGameSessionStub gameSession12 = new IGameSessionStub();
+ gameSession11Future.get().complete(gameSession12);
+
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest10), any());
+ mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest11), any());
+ mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest12), any());
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+ assertThat(gameSession11.mIsDestroyed).isTrue();
+ assertThat(gameSession12.mIsDestroyed).isFalse();
+ assertThat(mFakeGameServiceConnector.getIsConnected()).isTrue();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+ assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isTrue();
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void stop_severalActiveGameSessions_destroysGameSessionsAndUnbinds() throws Exception {
+ CreateGameSessionRequest createGameSessionRequest10 =
+ new CreateGameSessionRequest(10, GAME_A_PACKAGE);
+ Supplier<AndroidFuture<IBinder>> gameSession10Future =
+ captureCreateGameSessionFuture(createGameSessionRequest10);
+
+ CreateGameSessionRequest createGameSessionRequest11 =
+ new CreateGameSessionRequest(11, GAME_A_PACKAGE);
+ Supplier<AndroidFuture<IBinder>> gameSession11Future =
+ captureCreateGameSessionFuture(createGameSessionRequest11);
+
+ mGameServiceProviderInstance.start();
+ dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
+ IGameSessionStub gameSession10 = new IGameSessionStub();
+ gameSession10Future.get().complete(gameSession10);
+ dispatchTaskCreated(11, GAME_A_MAIN_ACTIVITY);
+ IGameSessionStub gameSession11 = new IGameSessionStub();
+ gameSession11Future.get().complete(gameSession11);
+ mGameServiceProviderInstance.stop();
+
+ mInOrder.verify(mMockGameService).connected();
+ mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest10), any());
+ mInOrder.verify(mMockGameSessionService).create(eq(createGameSessionRequest11), any());
+ mInOrder.verify(mMockGameService).disconnected();
+ mInOrder.verifyNoMoreInteractions();
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+ assertThat(gameSession11.mIsDestroyed).isTrue();
+ assertThat(mFakeGameServiceConnector.getIsConnected()).isFalse();
+ assertThat(mFakeGameServiceConnector.getConnectCount()).isEqualTo(1);
+ assertThat(mFakeGameSessionServiceConnector.getIsConnected()).isFalse();
+ assertThat(mFakeGameSessionServiceConnector.getConnectCount()).isEqualTo(1);
+ }
+
+ private Supplier<AndroidFuture<IBinder>> captureCreateGameSessionFuture(
+ CreateGameSessionRequest expectedCreateGameSessionRequest) throws Exception {
+ final AtomicReference<AndroidFuture<IBinder>> gameSessionFuture = new AtomicReference<>();
+ doAnswer(invocation -> {
+ gameSessionFuture.set(invocation.getArgument(1));
+ return null;
+ }).when(mMockGameSessionService).create(eq(expectedCreateGameSessionRequest), any());
+
+ return gameSessionFuture::get;
+ }
+
+ private void dispatchTaskRemoved(int taskId) {
+ dispatchTaskChangeEvent(taskStackListener -> {
+ taskStackListener.onTaskRemoved(taskId);
+ });
+ }
+
+ private void dispatchTaskCreated(int taskId, @Nullable ComponentName componentName) {
+ dispatchTaskChangeEvent(taskStackListener -> {
+ taskStackListener.onTaskCreated(taskId, componentName);
+ });
+ }
+
+ private void dispatchTaskChangeEvent(
+ ThrowingConsumer<ITaskStackListener> taskStackListenerConsumer) {
+ for (ITaskStackListener taskStackListener : mTaskStackListeners) {
+ taskStackListenerConsumer.accept(taskStackListener);
+ }
+ }
+
+ private static class IGameSessionStub extends IGameSession.Stub {
+ boolean mIsDestroyed = false;
+
+ @Override
+ public void destroy() {
+ mIsDestroyed = true;
+ }
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderSelectorImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderSelectorImplTest.java
new file mode 100644
index 0000000..59d0970
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderSelectorImplTest.java
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.app;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.platform.test.annotations.Presubmit;
+import android.service.games.GameService;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.SystemService;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+
+/**
+ * Unit tests for the {@link GameServiceProviderSelectorImpl}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public final class GameServiceProviderSelectorImplTest {
+
+ private static final UserHandle USER_HANDLE_10 = new UserHandle(10);
+
+ private static final int GAME_SERVICE_META_DATA_RES_ID = 1337;
+ private static final String GAME_SERVICE_PACKAGE_NAME = "com.game.service.provider";
+ private static final String GAME_SERVICE_CLASS_NAME = "com.game.service.provider.GameService";
+ private static final ComponentName GAME_SERVICE_COMPONENT =
+ new ComponentName(GAME_SERVICE_PACKAGE_NAME, GAME_SERVICE_CLASS_NAME);
+
+ private static final int GAME_SERVICE_B_META_DATA_RES_ID = 1338;
+ private static final String GAME_SERVICE_B_CLASS_NAME =
+ "com.game.service.provider.GameServiceB";
+ private static final ComponentName GAME_SERVICE_B_COMPONENT =
+ new ComponentName(GAME_SERVICE_PACKAGE_NAME, GAME_SERVICE_B_CLASS_NAME);
+ private static final ServiceInfo GAME_SERVICE_B_WITH_OUT_META_DATA =
+ serviceInfo(GAME_SERVICE_PACKAGE_NAME, GAME_SERVICE_B_CLASS_NAME);
+ private static final ServiceInfo GAME_SERVICE_B_SERVICE_INFO =
+ addGameServiceMetaData(GAME_SERVICE_B_WITH_OUT_META_DATA,
+ GAME_SERVICE_B_META_DATA_RES_ID);
+
+ private static final String GAME_SESSION_SERVICE_CLASS_NAME =
+ "com.game.service.provider.GameSessionService";
+ private static final ComponentName GAME_SESSION_SERVICE_COMPONENT =
+ new ComponentName(GAME_SERVICE_PACKAGE_NAME, GAME_SESSION_SERVICE_CLASS_NAME);
+ private static final ServiceInfo GAME_SERVICE_SERVICE_INFO_WITHOUT_META_DATA =
+ serviceInfo(GAME_SERVICE_PACKAGE_NAME, GAME_SERVICE_CLASS_NAME);
+ private static final ServiceInfo GAME_SERVICE_SERVICE_INFO =
+ addGameServiceMetaData(GAME_SERVICE_SERVICE_INFO_WITHOUT_META_DATA,
+ GAME_SERVICE_META_DATA_RES_ID);
+
+ @Mock
+ private PackageManager mMockPackageManager;
+ private Resources mSpyResources;
+ private MockitoSession mMockingSession;
+ private GameServiceProviderSelector mGameServiceProviderSelector;
+
+ @Before
+ public void setUp() throws PackageManager.NameNotFoundException {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ mSpyResources = spy(
+ InstrumentationRegistry.getInstrumentation().getContext().getResources());
+
+ when(mMockPackageManager.getResourcesForApplication(anyString()))
+ .thenReturn(mSpyResources);
+ mGameServiceProviderSelector = new GameServiceProviderSelectorImpl(
+ mSpyResources,
+ mMockPackageManager);
+ }
+
+ @After
+ public void tearDown() {
+ mMockingSession.finishMocking();
+ }
+
+ @Test
+ public void get_nullUser_returnsNull()
+ throws Exception {
+ seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+ seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+ resolveInfo(GAME_SERVICE_SERVICE_INFO));
+ seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+ seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+ GAME_SERVICE_META_DATA_RES_ID,
+ "res/xml/game_service_metadata_valid.xml");
+
+ GameServiceProviderConfiguration gameServiceProviderConfiguration =
+ mGameServiceProviderSelector.get(null);
+
+ assertThat(gameServiceProviderConfiguration).isNull();
+ }
+
+ @Test
+ public void get_managedUser_returnsNull()
+ throws Exception {
+ seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+ seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+ resolveInfo(GAME_SERVICE_SERVICE_INFO));
+ seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+ seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+ GAME_SERVICE_META_DATA_RES_ID,
+ "res/xml/game_service_metadata_valid.xml");
+
+ GameServiceProviderConfiguration gameServiceProviderConfiguration =
+ mGameServiceProviderSelector.get(managedTargetUser(USER_HANDLE_10));
+
+ assertThat(gameServiceProviderConfiguration).isNull();
+ }
+
+ @Test
+ public void get_noSystemGameService_returnsNull()
+ throws Exception {
+ seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+ resolveInfo(GAME_SERVICE_SERVICE_INFO));
+ seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+ seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+ GAME_SERVICE_META_DATA_RES_ID,
+ "res/xml/game_service_metadata_valid.xml");
+
+ GameServiceProviderConfiguration gameServiceProviderConfiguration =
+ mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
+
+ assertThat(gameServiceProviderConfiguration).isNull();
+ }
+
+ @Test
+ public void get_noGameServiceProvidersAvailable_returnsNull()
+ throws Exception {
+ seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+ seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10);
+ seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+ seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+ GAME_SERVICE_META_DATA_RES_ID,
+ "res/xml/game_service_metadata_valid.xml");
+
+ GameServiceProviderConfiguration gameServiceProviderConfiguration =
+ mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
+
+ assertThat(gameServiceProviderConfiguration).isNull();
+ }
+
+ @Test
+ public void get_gameServiceProviderHasNoMetaData_returnsNull()
+ throws Exception {
+ seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+ seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+ resolveInfo(GAME_SERVICE_SERVICE_INFO_WITHOUT_META_DATA));
+ seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+
+ GameServiceProviderConfiguration gameServiceProviderConfiguration =
+ mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
+
+ assertThat(gameServiceProviderConfiguration).isNull();
+ }
+
+ @Test
+ public void get_gameSessionServiceDoesNotExist_returnsNull()
+ throws Exception {
+ seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+ seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+ resolveInfo(GAME_SERVICE_SERVICE_INFO));
+ seedServiceServiceInfoNotFound(GAME_SESSION_SERVICE_COMPONENT);
+ seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+ GAME_SERVICE_META_DATA_RES_ID,
+ "res/xml/game_service_metadata_valid.xml");
+
+ GameServiceProviderConfiguration gameServiceProviderConfiguration =
+ mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
+
+ assertThat(gameServiceProviderConfiguration).isNull();
+ }
+
+ @Test
+ public void get_metaDataWrongFirstTag_returnsNull() throws Exception {
+ seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+ seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+ resolveInfo(GAME_SERVICE_SERVICE_INFO));
+ seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+ seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+ GAME_SERVICE_META_DATA_RES_ID,
+ "res/xml/game_service_metadata_wrong_first_tag.xml");
+
+ GameServiceProviderConfiguration gameServiceProviderConfiguration =
+ mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
+
+ assertThat(gameServiceProviderConfiguration).isNull();
+ }
+
+ @Test
+ public void get_validGameServiceProviderAvailable_returnsGameServiceProvider()
+ throws Exception {
+ seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+ seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+ resolveInfo(GAME_SERVICE_SERVICE_INFO));
+ seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+ seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+ GAME_SERVICE_META_DATA_RES_ID,
+ "res/xml/game_service_metadata_valid.xml");
+
+ GameServiceProviderConfiguration gameServiceProviderConfiguration =
+ mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
+
+ GameServiceProviderConfiguration expectedGameServiceProviderConfiguration =
+ new GameServiceProviderConfiguration(USER_HANDLE_10,
+ GAME_SERVICE_COMPONENT,
+ GAME_SESSION_SERVICE_COMPONENT);
+ assertThat(gameServiceProviderConfiguration).isEqualTo(
+ expectedGameServiceProviderConfiguration);
+ }
+
+ @Test
+ public void get_multipleGameServiceProvidersAllValid_returnsFirstValidGameServiceProvider()
+ throws Exception {
+ seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+
+ seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+ resolveInfo(GAME_SERVICE_B_SERVICE_INFO), resolveInfo(GAME_SERVICE_SERVICE_INFO));
+ seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+ seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+ GAME_SERVICE_B_META_DATA_RES_ID,
+ "res/xml/game_service_metadata_valid.xml");
+ seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+ GAME_SERVICE_META_DATA_RES_ID,
+ "res/xml/game_service_metadata_valid.xml");
+
+ GameServiceProviderConfiguration gameServiceProviderConfiguration =
+ mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
+
+ GameServiceProviderConfiguration expectedGameServiceProviderConfiguration =
+ new GameServiceProviderConfiguration(USER_HANDLE_10,
+ GAME_SERVICE_B_COMPONENT,
+ GAME_SESSION_SERVICE_COMPONENT);
+ assertThat(gameServiceProviderConfiguration).isEqualTo(
+ expectedGameServiceProviderConfiguration);
+ }
+
+ @Test
+ public void get_multipleGameServiceProvidersSomeInvalid_returnsFirstValidGameServiceProvider()
+ throws Exception {
+ seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
+
+ seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
+ resolveInfo(GAME_SERVICE_B_SERVICE_INFO), resolveInfo(GAME_SERVICE_SERVICE_INFO));
+ seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
+ seedGameServiceMetaDataFromFile(GAME_SERVICE_PACKAGE_NAME,
+ GAME_SERVICE_META_DATA_RES_ID,
+ "res/xml/game_service_metadata_valid.xml");
+
+ GameServiceProviderConfiguration gameServiceProviderConfiguration =
+ mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10));
+
+ GameServiceProviderConfiguration expectedGameServiceProviderConfiguration =
+ new GameServiceProviderConfiguration(USER_HANDLE_10,
+ GAME_SERVICE_COMPONENT,
+ GAME_SESSION_SERVICE_COMPONENT);
+ assertThat(gameServiceProviderConfiguration).isEqualTo(
+ expectedGameServiceProviderConfiguration);
+ }
+
+ private void seedSystemGameServicePackageName(String gameServicePackageName) {
+ when(mSpyResources.getString(com.android.internal.R.string.config_systemGameService))
+ .thenReturn(gameServicePackageName);
+ }
+
+ private void seedGameServiceResolveInfos(
+ String gameServicePackageName,
+ UserHandle userHandle,
+ ResolveInfo... resolveInfos) {
+ doReturn(ImmutableList.copyOf(resolveInfos))
+ .when(mMockPackageManager).queryIntentServicesAsUser(
+ argThat(intent ->
+ intent != null
+ && intent.getAction().equals(
+ GameService.ACTION_GAME_SERVICE)
+ && intent.getPackage().equals(gameServicePackageName)
+ ),
+ anyInt(),
+ eq(userHandle.getIdentifier()));
+ }
+
+ private void seedServiceServiceInfo(ComponentName componentName) throws Exception {
+ when(mMockPackageManager.getServiceInfo(eq(componentName), anyInt()))
+ .thenReturn(
+ serviceInfo(componentName.getPackageName(), componentName.getClassName()));
+ }
+
+ private void seedServiceServiceInfoNotFound(ComponentName componentName) throws Exception {
+ when(mMockPackageManager.getServiceInfo(eq(componentName), anyInt()))
+ .thenThrow(new PackageManager.NameNotFoundException());
+ }
+
+ private void seedGameServiceMetaDataFromFile(String packageName, int resId, String fileName)
+ throws Exception {
+
+ AssetManager assetManager =
+ InstrumentationRegistry.getInstrumentation().getContext().getAssets();
+ XmlResourceParser xmlResourceParser =
+ assetManager.openXmlResourceParser(fileName);
+
+ when(mMockPackageManager.getXml(eq(packageName), eq(resId), any()))
+ .thenReturn(xmlResourceParser);
+ }
+
+ private static UserInfo eligibleUserInfo(int uid) {
+ return new UserInfo(uid, "", "", UserInfo.FLAG_FULL);
+ }
+
+ private static UserInfo managedUserInfo(int uid) {
+ UserInfo userInfo = eligibleUserInfo(uid);
+ userInfo.userType = UserManager.USER_TYPE_PROFILE_MANAGED;
+ return userInfo;
+ }
+
+ private static ResolveInfo resolveInfo(ServiceInfo serviceInfo) {
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.serviceInfo = serviceInfo;
+ return resolveInfo;
+ }
+
+ private static ServiceInfo serviceInfo(String packageName, String name) {
+ ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.packageName = packageName;
+ applicationInfo.enabled = true;
+
+ ServiceInfo serviceInfo = new ServiceInfo();
+ serviceInfo.applicationInfo = applicationInfo;
+ serviceInfo.packageName = packageName;
+ serviceInfo.name = name;
+ serviceInfo.enabled = true;
+
+ return serviceInfo;
+ }
+
+ private static ServiceInfo addGameServiceMetaData(ServiceInfo serviceInfo, int resId) {
+ if (serviceInfo.metaData == null) {
+ serviceInfo.metaData = new Bundle();
+ }
+ serviceInfo.metaData.putInt(GameService.SERVICE_META_DATA, resId);
+
+ return serviceInfo;
+ }
+
+ private static SystemService.TargetUser managedTargetUser(UserHandle userHandle) {
+ return new SystemService.TargetUser(managedUserInfo(userHandle.getIdentifier()));
+ }
+
+ private static SystemService.TargetUser eligibleTargetUser(UserHandle userHandle) {
+ return new SystemService.TargetUser(eligibleUserInfo(userHandle.getIdentifier()));
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java
index 349da03..edf6816 100644
--- a/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java
@@ -57,6 +57,8 @@
import androidx.test.filters.SmallTest;
import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesByPackageConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveByPackageConfig;
import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
import com.android.internal.compat.IPlatformCompat;
import com.android.modules.utils.testing.TestableDeviceConfig.TestableDeviceConfigRule;
@@ -108,7 +110,13 @@
@Captor
private ArgumentCaptor<CompatibilityOverrideConfig> mOverridesToAddConfigCaptor;
@Captor
+ private ArgumentCaptor<CompatibilityOverridesByPackageConfig>
+ mOverridesToAddByPackageConfigCaptor;
+ @Captor
private ArgumentCaptor<CompatibilityOverridesToRemoveConfig> mOverridesToRemoveConfigCaptor;
+ @Captor
+ private ArgumentCaptor<CompatibilityOverridesToRemoveByPackageConfig>
+ mOverridesToRemoveByPackageConfigCaptor;
@Rule
public TestableDeviceConfigRule mDeviceConfigRule = new TestableDeviceConfigRule();
@@ -165,13 +173,19 @@
.setString(PACKAGE_3, "123:1:9:true,123:10:11:false,123:11::true")
.setString(PACKAGE_4, "").build());
+ verify(mPlatformCompat).putAllOverridesOnReleaseBuilds(
+ mOverridesToAddByPackageConfigCaptor.capture());
+ verify(mPlatformCompat).removeAllOverridesOnReleaseBuilds(
+ mOverridesToRemoveByPackageConfigCaptor.capture());
+ Map<String, CompatibilityOverrideConfig> packageNameToAddedOverrides =
+ mOverridesToAddByPackageConfigCaptor.getValue().packageNameToOverrides;
+ Map<String, CompatibilityOverridesToRemoveConfig> packageNameToRemovedOverrides =
+ mOverridesToRemoveByPackageConfigCaptor.getValue().packageNameToOverridesToRemove;
Map<Long, PackageOverride> addedOverrides;
+ assertThat(packageNameToAddedOverrides.keySet()).containsExactly(PACKAGE_1, PACKAGE_3);
+ assertThat(packageNameToRemovedOverrides.keySet()).containsExactly(PACKAGE_3, PACKAGE_4);
// Package 1
- verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
- eq(PACKAGE_1));
- verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
- any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
- addedOverrides = mOverridesToAddConfigCaptor.getValue().overrides;
+ addedOverrides = packageNameToAddedOverrides.get(PACKAGE_1).overrides;
assertThat(addedOverrides).hasSize(3);
assertThat(addedOverrides.get(123L)).isEqualTo(
new PackageOverride.Builder().setEnabled(true).build());
@@ -179,29 +193,17 @@
new PackageOverride.Builder().setMinVersionCode(2).setEnabled(true).build());
assertThat(addedOverrides.get(789L)).isEqualTo(
new PackageOverride.Builder().setEnabled(false).build());
- // Package 2
- verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
- any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
- verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
- any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_2));
// Package 3
- verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
- eq(PACKAGE_3));
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
- mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_3));
- addedOverrides = mOverridesToAddConfigCaptor.getValue().overrides;
+ addedOverrides = packageNameToAddedOverrides.get(PACKAGE_3).overrides;
assertThat(addedOverrides).hasSize(1);
assertThat(addedOverrides.get(123L)).isEqualTo(
new PackageOverride.Builder().setMinVersionCode(10).setMaxVersionCode(
11).setEnabled(false).build());
- assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L, 789L);
- // Package 4
- verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
- any(CompatibilityOverrideConfig.class), eq(PACKAGE_4));
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
- mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_4));
- assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 456L,
+ assertThat(packageNameToRemovedOverrides.get(PACKAGE_3).changeIds).containsExactly(456L,
789L);
+ // Package 4
+ assertThat(packageNameToRemovedOverrides.get(PACKAGE_4).changeIds).containsExactly(123L,
+ 456L, 789L);
}
@Test
@@ -213,11 +215,15 @@
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
.setString(PACKAGE_1, "123:::true").build());
- verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
- eq(PACKAGE_1));
- verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
- any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
- assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(123L);
+ verify(mPlatformCompat).putAllOverridesOnReleaseBuilds(
+ mOverridesToAddByPackageConfigCaptor.capture());
+ verify(mPlatformCompat, never()).removeAllOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveByPackageConfig.class));
+ Map<String, CompatibilityOverrideConfig> packageNameToAddedOverrides =
+ mOverridesToAddByPackageConfigCaptor.getValue().packageNameToOverrides;
+ assertThat(packageNameToAddedOverrides.keySet()).containsExactly(PACKAGE_1);
+ assertThat(packageNameToAddedOverrides.get(PACKAGE_1).overrides.keySet()).containsExactly(
+ 123L);
}
@Test
@@ -238,30 +244,28 @@
.setString(PACKAGE_2, "123:::true")
.setString(PACKAGE_3, "456:::true").build());
+ verify(mPlatformCompat).putAllOverridesOnReleaseBuilds(
+ mOverridesToAddByPackageConfigCaptor.capture());
+ verify(mPlatformCompat).removeAllOverridesOnReleaseBuilds(
+ mOverridesToRemoveByPackageConfigCaptor.capture());
+ Map<String, CompatibilityOverrideConfig> packageNameToAddedOverrides =
+ mOverridesToAddByPackageConfigCaptor.getValue().packageNameToOverrides;
+ Map<String, CompatibilityOverridesToRemoveConfig> packageNameToRemovedOverrides =
+ mOverridesToRemoveByPackageConfigCaptor.getValue().packageNameToOverridesToRemove;
+ assertThat(packageNameToAddedOverrides.keySet()).containsExactly(PACKAGE_1, PACKAGE_3);
+ assertThat(packageNameToRemovedOverrides.keySet()).containsExactly(PACKAGE_2, PACKAGE_3);
// Package 1
- verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
- eq(PACKAGE_1));
- verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
- any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
- assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(789L);
+ assertThat(packageNameToAddedOverrides.get(PACKAGE_1).overrides.keySet()).containsExactly(
+ 789L);
// Package 2
- verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
- any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
- mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2));
- assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L, 789L);
+ assertThat(packageNameToRemovedOverrides.get(PACKAGE_2).changeIds).containsExactly(456L,
+ 789L);
// Package 3
- verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
- eq(PACKAGE_3));
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
- mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_3));
- assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(456L);
- assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 789L);
+ assertThat(packageNameToAddedOverrides.get(PACKAGE_3).overrides.keySet()).containsExactly(
+ 456L);
+ assertThat(packageNameToRemovedOverrides.get(PACKAGE_3).changeIds).containsExactly(123L,
+ 789L);
// Package 4 (not applied because it hasn't changed after the listener was added)
- verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
- any(CompatibilityOverrideConfig.class), eq(PACKAGE_4));
- verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
- any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_4));
}
@Test
@@ -279,23 +283,28 @@
.setString(FLAG_REMOVE_OVERRIDES,
PACKAGE_1 + "=123:456," + PACKAGE_2 + "=*").build());
- // Package 1
- verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
- any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
- verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
- mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
- List<CompatibilityOverridesToRemoveConfig> configs =
- mOverridesToRemoveConfigCaptor.getAllValues();
+ verify(mPlatformCompat, never()).putAllOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesByPackageConfig.class));
+ verify(mPlatformCompat, times(2)).removeAllOverridesOnReleaseBuilds(
+ mOverridesToRemoveByPackageConfigCaptor.capture());
+ List<CompatibilityOverridesToRemoveByPackageConfig> configs =
+ mOverridesToRemoveByPackageConfigCaptor.getAllValues();
assertThat(configs.size()).isAtLeast(2);
- assertThat(configs.get(configs.size() - 2).changeIds).containsExactly(123L, 456L);
- assertThat(configs.get(configs.size() - 1).changeIds).containsExactly(789L);
- // Package 2
- verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
- any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
- mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2));
- assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 456L,
+ Map<String, CompatibilityOverridesToRemoveConfig> firstPackageNameToRemovedOverrides =
+ configs.get(configs.size() - 2).packageNameToOverridesToRemove;
+ Map<String, CompatibilityOverridesToRemoveConfig> secondPackageNameToRemovedOverrides =
+ configs.get(configs.size() - 1).packageNameToOverridesToRemove;
+ assertThat(firstPackageNameToRemovedOverrides.keySet()).containsExactly(PACKAGE_1,
+ PACKAGE_2);
+ assertThat(secondPackageNameToRemovedOverrides.keySet()).containsExactly(PACKAGE_1);
+ // Package 1
+ assertThat(firstPackageNameToRemovedOverrides.get(PACKAGE_1).changeIds).containsExactly(
+ 123L, 456L);
+ assertThat(secondPackageNameToRemovedOverrides.get(PACKAGE_1).changeIds).containsExactly(
789L);
+ // Package 2
+ assertThat(firstPackageNameToRemovedOverrides.get(PACKAGE_2).changeIds).containsExactly(
+ 123L, 456L, 789L);
}
@Test
@@ -315,34 +324,42 @@
.setString(FLAG_REMOVE_OVERRIDES, PACKAGE_2 + "=123," + PACKAGE_3 + "=789")
.setString(PACKAGE_2, "123:::true").build());
+ verify(mPlatformCompat).putAllOverridesOnReleaseBuilds(
+ mOverridesToAddByPackageConfigCaptor.capture());
+ verify(mPlatformCompat, times(2)).removeAllOverridesOnReleaseBuilds(
+ mOverridesToRemoveByPackageConfigCaptor.capture());
+ Map<String, CompatibilityOverrideConfig> packageNameToAddedOverrides =
+ mOverridesToAddByPackageConfigCaptor.getValue().packageNameToOverrides;
+ List<CompatibilityOverridesToRemoveByPackageConfig> removeConfigs =
+ mOverridesToRemoveByPackageConfigCaptor.getAllValues();
+ assertThat(removeConfigs.size()).isAtLeast(2);
+ Map<String, CompatibilityOverridesToRemoveConfig> firstPackageNameToRemovedOverrides =
+ removeConfigs.get(removeConfigs.size() - 2).packageNameToOverridesToRemove;
+ Map<String, CompatibilityOverridesToRemoveConfig> secondPackageNameToRemovedOverrides =
+ removeConfigs.get(removeConfigs.size() - 1).packageNameToOverridesToRemove;
+ assertThat(packageNameToAddedOverrides.keySet()).containsExactly(PACKAGE_1, PACKAGE_3);
+ assertThat(firstPackageNameToRemovedOverrides.keySet()).containsExactly(PACKAGE_2,
+ PACKAGE_3);
+ assertThat(secondPackageNameToRemovedOverrides.keySet()).containsExactly(PACKAGE_1,
+ PACKAGE_2,
+ PACKAGE_3);
// Package 1
- verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
- eq(PACKAGE_1));
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
- mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
- assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(123L,
- 789L);
- assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L);
+ assertThat(packageNameToAddedOverrides.get(PACKAGE_1).overrides.keySet()).containsExactly(
+ 123L, 789L);
+ assertThat(secondPackageNameToRemovedOverrides.get(PACKAGE_1).changeIds).containsExactly(
+ 456L);
// Package 2
- verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
- any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
- verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
- mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2));
- List<CompatibilityOverridesToRemoveConfig> configs =
- mOverridesToRemoveConfigCaptor.getAllValues();
- assertThat(configs.size()).isAtLeast(2);
- assertThat(configs.get(configs.size() - 2).changeIds).containsExactly(123L);
- assertThat(configs.get(configs.size() - 1).changeIds).containsExactly(456L, 789L);
+ assertThat(firstPackageNameToRemovedOverrides.get(PACKAGE_2).changeIds).containsExactly(
+ 123L);
+ assertThat(secondPackageNameToRemovedOverrides.get(PACKAGE_2).changeIds).containsExactly(
+ 456L, 789L);
// Package 3
- verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
- eq(PACKAGE_3));
- verify(mPlatformCompat, times(2)).removeOverridesOnReleaseBuilds(
- mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_3));
- assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(456L);
- configs = mOverridesToRemoveConfigCaptor.getAllValues();
- assertThat(configs.size()).isAtLeast(2);
- assertThat(configs.get(configs.size() - 2).changeIds).containsExactly(789L);
- assertThat(configs.get(configs.size() - 1).changeIds).containsExactly(123L);
+ assertThat(packageNameToAddedOverrides.get(PACKAGE_3).overrides.keySet()).containsExactly(
+ 456L);
+ assertThat(firstPackageNameToRemovedOverrides.get(PACKAGE_3).changeIds).containsExactly(
+ 789L);
+ assertThat(secondPackageNameToRemovedOverrides.get(PACKAGE_3).changeIds).containsExactly(
+ 123L);
}
@Test
@@ -362,38 +379,41 @@
.setString(FLAG_OWNED_CHANGE_IDS, "123,456,789")
.setString(PACKAGE_2, "123:::true").build());
+ verify(mPlatformCompat).putAllOverridesOnReleaseBuilds(
+ mOverridesToAddByPackageConfigCaptor.capture());
+ verify(mPlatformCompat, times(2)).removeAllOverridesOnReleaseBuilds(
+ mOverridesToRemoveByPackageConfigCaptor.capture());
+ Map<String, CompatibilityOverrideConfig> packageNameToAddedOverrides =
+ mOverridesToAddByPackageConfigCaptor.getValue().packageNameToOverrides;
+ List<CompatibilityOverridesToRemoveByPackageConfig> removeConfigs =
+ mOverridesToRemoveByPackageConfigCaptor.getAllValues();
+ assertThat(removeConfigs.size()).isAtLeast(2);
+ Map<String, CompatibilityOverridesToRemoveConfig> firstPackageNameToRemovedOverrides =
+ removeConfigs.get(removeConfigs.size() - 2).packageNameToOverridesToRemove;
+ Map<String, CompatibilityOverridesToRemoveConfig> secondPackageNameToRemovedOverrides =
+ removeConfigs.get(removeConfigs.size() - 1).packageNameToOverridesToRemove;
+ assertThat(packageNameToAddedOverrides.keySet()).containsExactly(PACKAGE_2);
+ assertThat(firstPackageNameToRemovedOverrides.keySet()).containsExactly(PACKAGE_1);
+ assertThat(secondPackageNameToRemovedOverrides.keySet()).containsExactly(PACKAGE_2);
// Package 1
- verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
- any(CompatibilityOverrideConfig.class), eq(PACKAGE_1));
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
- mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_1));
- assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(123L, 456L,
- 789L);
+ assertThat(firstPackageNameToRemovedOverrides.get(PACKAGE_1).changeIds).containsExactly(
+ 123L, 456L, 789L);
// Package 2
- verify(mPlatformCompat).putOverridesOnReleaseBuilds(mOverridesToAddConfigCaptor.capture(),
- eq(PACKAGE_2));
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
- mOverridesToRemoveConfigCaptor.capture(), eq(PACKAGE_2));
- assertThat(mOverridesToAddConfigCaptor.getValue().overrides.keySet()).containsExactly(123L);
- assertThat(mOverridesToRemoveConfigCaptor.getValue().changeIds).containsExactly(456L, 789L);
- // Package 3
- verify(mPlatformCompat, never()).putOverridesOnReleaseBuilds(
- any(CompatibilityOverrideConfig.class), eq(PACKAGE_3));
- verify(mPlatformCompat, never()).removeOverridesOnReleaseBuilds(
- any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_3));
+ assertThat(packageNameToAddedOverrides.get(PACKAGE_2).overrides.keySet()).containsExactly(
+ 123L);
+ assertThat(secondPackageNameToRemovedOverrides.get(PACKAGE_2).changeIds).containsExactly(
+ 456L, 789L);
}
@Test
- public void onPropertiesChanged_platformCompatThrowsExceptionForSomeCalls_skipsFailedCalls()
+ public void onPropertiesChanged_platformCompatThrowsExceptionForPutCall_skipsFailedCall()
throws Exception {
mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
mockGetApplicationInfo(PACKAGE_2, /* versionCode= */ 0);
mockGetApplicationInfo(PACKAGE_3, /* versionCode= */ 0);
mockGetApplicationInfo(PACKAGE_4, /* versionCode= */ 0);
- doThrow(new RemoteException()).when(mPlatformCompat).putOverridesOnReleaseBuilds(
- any(CompatibilityOverrideConfig.class), eq(PACKAGE_2));
- doThrow(new RemoteException()).when(mPlatformCompat).removeOverridesOnReleaseBuilds(
- any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_3));
+ doThrow(new RemoteException()).when(mPlatformCompat).putAllOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesByPackageConfig.class));
mService.registerDeviceConfigListeners();
DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
@@ -403,26 +423,34 @@
.setString(PACKAGE_3, "123:::true")
.setString(PACKAGE_4, "123:::true").build());
- // Package 1
- verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class),
- eq(PACKAGE_1));
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
- any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_1));
- // Package 2
- verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class),
- eq(PACKAGE_2));
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
- any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_2));
- // Package 3
- verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class),
- eq(PACKAGE_3));
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
- any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_3));
- // Package 4
- verify(mPlatformCompat).putOverridesOnReleaseBuilds(any(CompatibilityOverrideConfig.class),
- eq(PACKAGE_1));
- verify(mPlatformCompat).removeOverridesOnReleaseBuilds(
- any(CompatibilityOverridesToRemoveConfig.class), eq(PACKAGE_4));
+ verify(mPlatformCompat).putAllOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesByPackageConfig.class));
+ verify(mPlatformCompat).removeAllOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveByPackageConfig.class));
+ }
+
+ @Test
+ public void onPropertiesChanged_platformCompatThrowsExceptionForRemoveCall_skipsFailedCall()
+ throws Exception {
+ mockGetApplicationInfo(PACKAGE_1, /* versionCode= */ 0);
+ mockGetApplicationInfo(PACKAGE_2, /* versionCode= */ 0);
+ mockGetApplicationInfo(PACKAGE_3, /* versionCode= */ 0);
+ mockGetApplicationInfo(PACKAGE_4, /* versionCode= */ 0);
+ doThrow(new RemoteException()).when(mPlatformCompat).removeAllOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveByPackageConfig.class));
+
+ mService.registerDeviceConfigListeners();
+ DeviceConfig.setProperties(new Properties.Builder(NAMESPACE_1)
+ .setString(FLAG_OWNED_CHANGE_IDS, "123,456")
+ .setString(PACKAGE_1, "123:::true")
+ .setString(PACKAGE_2, "123:::true")
+ .setString(PACKAGE_3, "123:::true")
+ .setString(PACKAGE_4, "123:::true").build());
+
+ verify(mPlatformCompat).putAllOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesByPackageConfig.class));
+ verify(mPlatformCompat).removeAllOverridesOnReleaseBuilds(
+ any(CompatibilityOverridesToRemoveByPackageConfig.class));
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index ae5984a41..44a8b30 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -121,6 +121,9 @@
/** The active map simulating the in memory storage of Settings */
private val mSettingsMap = WatchedArrayMap<String, PackageSetting>()
+ /** The shared libraries on the device */
+ private lateinit var mSharedLibraries: SharedLibrariesImpl
+
init {
PropertyInvalidatedCache.disableForTestMode()
val apply = ExtendedMockito.mockitoSession()
@@ -324,6 +327,11 @@
any(AndroidPackage::class.java), anyBoolean(), any(File::class.java))) {
PackageAbiHelper.NativeLibraryPaths("", false, "", "")
}
+ whenever(mocks.injector.bootstrap(any(PackageManagerService::class.java))) {
+ mSharedLibraries = SharedLibrariesImpl(
+ getArgument<Any>(0) as PackageManagerService, mocks.injector)
+ }
+ whenever(mocks.injector.sharedLibrariesImpl) { mSharedLibraries }
// everything visible by default
whenever(mocks.appsFilter.shouldFilterApplication(
anyInt(), nullable(), nullable(), anyInt())) { false }
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt
new file mode 100644
index 0000000..edbfecc
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm
+
+import android.os.Build
+import com.android.server.testutils.any
+import com.android.server.testutils.spy
+import com.android.server.testutils.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import kotlin.test.assertFailsWith
+
+@RunWith(JUnit4::class)
+class PackageFreezerTest {
+
+ companion object {
+ const val TEST_PACKAGE = "com.android.test.package"
+ const val TEST_REASON = "test reason"
+ const val TEST_USER_ID = 0
+ }
+
+ @Rule
+ @JvmField
+ val rule = MockSystemRule()
+
+ lateinit var pms: PackageManagerService
+
+ private fun createPackageManagerService(vararg stageExistingPackages: String):
+ PackageManagerService {
+ stageExistingPackages.forEach {
+ rule.system().stageScanExistingPackage(it, 1L,
+ rule.system().dataAppDirectory)
+ }
+ var pms = PackageManagerService(rule.mocks().injector,
+ false /*coreOnly*/,
+ false /*factoryTest*/,
+ MockSystem.DEFAULT_VERSION_INFO.fingerprint,
+ false /*isEngBuild*/,
+ false /*isUserDebugBuild*/,
+ Build.VERSION_CODES.CUR_DEVELOPMENT,
+ Build.VERSION.INCREMENTAL,
+ false /*snapshotEnabled*/)
+ rule.system().validateFinalState()
+ return pms
+ }
+
+ private fun frozenMessage(packageName: String) = "Package $packageName is currently frozen!"
+
+ private fun <T : Throwable> assertThrowContainsMessage(
+ exceptionClass: kotlin.reflect.KClass<T>,
+ message: String,
+ block: () -> Unit
+ ) {
+ assertThat(assertFailsWith(exceptionClass, block).message).contains(message)
+ }
+
+ @Before
+ @Throws(Exception::class)
+ fun setup() {
+ rule.system().stageNominalSystemState()
+ pms = spy(createPackageManagerService(TEST_PACKAGE))
+ whenever(pms.killApplication(any(), any(), any(), any()))
+ }
+
+ @Test
+ fun freezePackage() {
+ val freezer = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms)
+ verify(pms, times(1))
+ .killApplication(eq(TEST_PACKAGE), any(), eq(TEST_USER_ID), eq(TEST_REASON))
+
+ assertThrowContainsMessage(SecurityException::class, frozenMessage(TEST_PACKAGE)) {
+ pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+ }
+
+ freezer.close()
+ pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+ }
+
+ @Test
+ fun freezePackage_twice() {
+ val freezer1 = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms)
+ val freezer2 = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms)
+ verify(pms, times(2))
+ .killApplication(eq(TEST_PACKAGE), any(), eq(TEST_USER_ID), eq(TEST_REASON))
+
+ assertThrowContainsMessage(SecurityException::class, frozenMessage(TEST_PACKAGE)) {
+ pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+ }
+
+ freezer1.close()
+ assertThrowContainsMessage(SecurityException::class, frozenMessage(TEST_PACKAGE)) {
+ pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+ }
+
+ freezer2.close()
+ pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+ }
+
+ @Test
+ fun freezePackage_withoutClosing() {
+ var freezer: PackageFreezer? = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms)
+ verify(pms, times(1))
+ .killApplication(eq(TEST_PACKAGE), any(), eq(TEST_USER_ID), eq(TEST_REASON))
+
+ assertThrowContainsMessage(SecurityException::class, frozenMessage(TEST_PACKAGE)) {
+ pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+ }
+
+ freezer = null
+ System.gc()
+ System.runFinalization()
+
+ pms.checkPackageStartable(TEST_PACKAGE, TEST_USER_ID)
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/TEST_MAPPING b/services/tests/mockingservicestests/src/com/android/server/pm/TEST_MAPPING
new file mode 100644
index 0000000..13e255fe4
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksMockingServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.pm"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 80f2729..e756124 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -97,6 +97,10 @@
<uses-permission
android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
+ <queries>
+ <package android:name="com.android.servicestests.apps.suspendtestapp" />
+ </queries>
+
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
android:targetSdkVersion="26"/>
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index e93e544..82b7540 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -247,4 +247,21 @@
verify(mMockServiceClient).onPerformGestureResult(0, false);
}
+ @Test
+ public void unbind_resetAllMagnification() {
+ mConnection.unbindLocked();
+ verify(mMockMagnificationProcessor).resetAllIfNeeded(anyInt());
+ }
+
+ @Test
+ public void binderDied_resetAllMagnification() {
+ setServiceBinding(COMPONENT_NAME);
+ mConnection.bindLocked();
+ mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
+
+ mConnection.binderDied();
+
+ verify(mMockMagnificationProcessor).resetAllIfNeeded(anyInt());
+ }
+
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java
index 621507e..99d6c2a 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationProcessorTest.java
@@ -24,6 +24,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
@@ -235,7 +236,17 @@
mMagnificationProcessor.resetCurrentMagnification(TEST_DISPLAY, /* animate= */false);
- verify(mMockWindowMagnificationManager).reset(TEST_DISPLAY);
+ verify(mMockWindowMagnificationManager).disableWindowMagnification(TEST_DISPLAY, false,
+ null);
+ }
+
+ @Test
+ public void resetAllIfNeeded_resetFullscreenAndWindowMagnificationByConnectionId() {
+ final int connectionId = 1;
+ mMagnificationProcessor.resetAllIfNeeded(connectionId);
+
+ verify(mMockFullScreenMagnificationController).resetAllIfNeeded(eq(connectionId));
+ verify(mMockWindowMagnificationManager).resetAllIfNeeded(eq(connectionId));
}
@Test
@@ -322,7 +333,7 @@
final MagnificationConfig result = mMagnificationProcessor.getMagnificationConfig(
TEST_DISPLAY);
verify(mMockMagnificationController).transitionMagnificationConfigMode(eq(TEST_DISPLAY),
- eq(newConfig), anyBoolean());
+ eq(newConfig), anyBoolean(), anyInt());
assertConfigEquals(newConfig, result);
}
@@ -438,7 +449,7 @@
anyFloat(), anyFloat(), anyFloat());
doAnswer(enableWindowMagnificationStubAnswer).when(
mWindowMagnificationManager).enableWindowMagnification(eq(TEST_DISPLAY),
- anyFloat(), anyFloat(), anyFloat(), any());
+ anyFloat(), anyFloat(), anyFloat(), any(), anyInt());
}
public void resetAndStubMethods() {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index 08421de..c9ae11a 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -293,7 +293,7 @@
// Enable window magnification while animating.
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, DEFAULT_SCALE,
- Float.NaN, Float.NaN, null);
+ Float.NaN, Float.NaN, null, TEST_SERVICE_ID);
mMockConnection.invokeCallbacks();
assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
@@ -310,7 +310,7 @@
mMagnificationController.transitionMagnificationConfigMode(TEST_DISPLAY,
obtainMagnificationConfig(MODE_WINDOW),
- false);
+ false, TEST_SERVICE_ID);
verify(mScreenMagnificationController).reset(eq(TEST_DISPLAY), eq(false));
mMockConnection.invokeCallbacks();
@@ -325,13 +325,13 @@
activateMagnifier(MODE_WINDOW, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
mMagnificationController.transitionMagnificationConfigMode(TEST_DISPLAY,
obtainMagnificationConfig(MODE_FULLSCREEN),
- animate);
+ animate, TEST_SERVICE_ID);
mMockConnection.invokeCallbacks();
assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
verify(mScreenMagnificationController).setScaleAndCenter(TEST_DISPLAY,
DEFAULT_SCALE, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y,
- animate, MAGNIFICATION_GESTURE_HANDLER_ID);
+ animate, TEST_SERVICE_ID);
}
@Test
@@ -345,7 +345,7 @@
// Config-setting mode
mMagnificationController.transitionMagnificationConfigMode(TEST_DISPLAY,
obtainMagnificationConfig(MODE_FULLSCREEN),
- true);
+ true, TEST_SERVICE_ID);
assertEquals(DEFAULT_SCALE, mScreenMagnificationController.getScale(TEST_DISPLAY), 0);
assertEquals(MAGNIFIED_CENTER_X, mScreenMagnificationController.getCenterX(TEST_DISPLAY),
@@ -365,7 +365,7 @@
// Config-setting mode
mMagnificationController.transitionMagnificationConfigMode(TEST_DISPLAY,
obtainMagnificationConfig(MODE_FULLSCREEN),
- true);
+ true, TEST_SERVICE_ID);
verify(mTransitionCallBack, never()).onResult(TEST_DISPLAY, true);
}
@@ -772,7 +772,7 @@
centerY, true, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
} else {
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, DEFAULT_SCALE,
- centerX, centerY, null);
+ centerX, centerY, null, TEST_SERVICE_ID);
mMockConnection.invokeCallbacks();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
index 0659a60..4c03ec3 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MockWindowMagnificationConnection.java
@@ -35,6 +35,9 @@
import android.view.accessibility.IWindowMagnificationConnection;
import android.view.accessibility.IWindowMagnificationConnectionCallback;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Mocks the basic logic of window magnification in System UI. We assume the screen size is
* unlimited, so source bounds is always on the center of the mirror window bounds.
@@ -42,6 +45,8 @@
class MockWindowMagnificationConnection {
public static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
+ public static final int TEST_DISPLAY_2 = Display.DEFAULT_DISPLAY + 1;
+ private final List mValidDisplayIds;
private final IWindowMagnificationConnection mConnection;
private final Binder mBinder;
private final boolean mSuspendCallback;
@@ -60,6 +65,10 @@
}
MockWindowMagnificationConnection(boolean suspendCallback) throws RemoteException {
+ mValidDisplayIds = new ArrayList();
+ mValidDisplayIds.add(TEST_DISPLAY);
+ mValidDisplayIds.add(TEST_DISPLAY_2);
+
mSuspendCallback = suspendCallback;
mConnection = mock(IWindowMagnificationConnection.class);
mBinder = mock(Binder.class);
@@ -86,8 +95,8 @@
private void stubEnableWindowMagnification() throws RemoteException {
doAnswer((invocation) -> {
final int displayId = invocation.getArgument(0);
- if (displayId != TEST_DISPLAY) {
- throw new IllegalArgumentException("only support default display :" + displayId);
+ if (!mValidDisplayIds.contains(displayId)) {
+ throw new IllegalArgumentException("Not support display :" + displayId);
}
mWindowMagnificationEnabled = true;
final float scale = invocation.getArgument(1);
@@ -107,8 +116,8 @@
private void stubDisableWindowMagnification() throws RemoteException {
doAnswer((invocation) -> {
final int displayId = invocation.getArgument(0);
- if (displayId != TEST_DISPLAY) {
- throw new IllegalArgumentException("only support default display :" + displayId);
+ if (!mValidDisplayIds.contains(displayId)) {
+ throw new IllegalArgumentException("Not support display :" + displayId);
}
setAnimationCallback(invocation.getArgument(1));
mHasPendingCallback = true;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index 85512f3..8b7a191 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -16,6 +16,9 @@
package com.android.server.accessibility.magnification;
+import static com.android.server.accessibility.magnification.MockWindowMagnificationConnection.TEST_DISPLAY;
+import static com.android.server.accessibility.magnification.MockWindowMagnificationConnection.TEST_DISPLAY_2;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
@@ -38,13 +41,13 @@
import android.content.IntentFilter;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
-import android.view.Display;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
@@ -67,8 +70,8 @@
*/
public class WindowMagnificationManagerTest {
- private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
private static final int CURRENT_USER_ID = UserHandle.USER_SYSTEM;
+ private static final int SERVICE_ID = 1;
private MockWindowMagnificationConnection mMockConnection;
@Mock
@@ -185,7 +188,7 @@
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 2f, 200f, 300f,
- mAnimationCallback);
+ mAnimationCallback, SERVICE_ID);
verify(mMockConnection.getConnection()).enableWindowMagnification(eq(TEST_DISPLAY), eq(2f),
eq(200f), eq(300f), eq(0f), eq(0f),
@@ -377,14 +380,51 @@
}
@Test
- public void resetMagnification_enabled_windowMagnifierDisabled() {
+ public void requestConnectionToNull_expectedGetterResults() {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
- assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, 1, 1);
- mWindowMagnificationManager.reset(TEST_DISPLAY);
+ mWindowMagnificationManager.requestConnection(false);
+
+ assertEquals(1f, mWindowMagnificationManager.getScale(TEST_DISPLAY), 0);
+ assertTrue(Float.isNaN(mWindowMagnificationManager.getCenterX(TEST_DISPLAY)));
+ assertTrue(Float.isNaN(mWindowMagnificationManager.getCenterY(TEST_DISPLAY)));
+ final Region bounds = new Region();
+ mWindowMagnificationManager.getMagnificationSourceBounds(TEST_DISPLAY, bounds);
+ assertTrue(bounds.isEmpty());
+ }
+
+ @Test
+ public void resetAllMagnification_enabledBySameId_windowMagnifiersDisabled() {
+ mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f,
+ 100f, 200f, null, WindowMagnificationManager.WINDOW_POSITION_AT_CENTER, SERVICE_ID);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY_2, 3f,
+ 100f, 200f, null, WindowMagnificationManager.WINDOW_POSITION_AT_CENTER, SERVICE_ID);
+ assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
+ assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY_2));
+
+ mWindowMagnificationManager.resetAllIfNeeded(SERVICE_ID);
assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
+ assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY_2));
+ }
+
+ @Test
+ public void resetAllMagnification_enabledByDifferentId_windowMagnifierDisabled() {
+ final int serviceId2 = SERVICE_ID + 1;
+ mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f,
+ 100f, 200f, null, WindowMagnificationManager.WINDOW_POSITION_AT_CENTER, SERVICE_ID);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY_2, 3f,
+ 100f, 200f, null, WindowMagnificationManager.WINDOW_POSITION_AT_CENTER, serviceId2);
+ assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
+ assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY_2));
+
+ mWindowMagnificationManager.resetAllIfNeeded(SERVICE_ID);
+
+ assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
+ assertTrue(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY_2));
}
@Test
@@ -439,6 +479,22 @@
}
@Test
+ public void magnifierGetters_disabled_expectedValues() {
+ mWindowMagnificationManager.requestConnection(true);
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f,
+ 100f, 200f, WindowMagnificationManager.WINDOW_POSITION_AT_CENTER);
+
+ mWindowMagnificationManager.disableWindowMagnification(TEST_DISPLAY, false);
+
+ assertEquals(1f, mWindowMagnificationManager.getScale(TEST_DISPLAY), 0);
+ assertTrue(Float.isNaN(mWindowMagnificationManager.getCenterX(TEST_DISPLAY)));
+ assertTrue(Float.isNaN(mWindowMagnificationManager.getCenterY(TEST_DISPLAY)));
+ final Region bounds = new Region();
+ mWindowMagnificationManager.getMagnificationSourceBounds(TEST_DISPLAY, bounds);
+ assertTrue(bounds.isEmpty());
+ }
+
+ @Test
public void onDisplayRemoved_enabledOnTestDisplay_disabled() {
mWindowMagnificationManager.requestConnection(true);
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, 100f, 200f);
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index d926dcb..b2854ce 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -36,6 +36,8 @@
import com.android.internal.compat.AndroidBuildClassifier;
import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.CompatibilityOverridesByPackageConfig;
+import com.android.internal.compat.CompatibilityOverridesToRemoveByPackageConfig;
import com.android.internal.compat.CompatibilityOverridesToRemoveConfig;
import org.junit.Before;
@@ -303,6 +305,51 @@
assertThat(compatConfig.isChangeEnabled(unknownChangeId, applicationInfo)).isTrue();
}
+ @Test
+ public void testInstallerCanAddOverridesForMultiplePackages() throws Exception {
+ final String packageName1 = "com.some.package1";
+ final String packageName2 = "com.some.package2";
+ final long disabledChangeId1 = 1234L;
+ final long disabledChangeId2 = 1235L;
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledOverridableChangeWithId(disabledChangeId1)
+ .addDisabledOverridableChangeWithId(disabledChangeId2)
+ .build();
+ ApplicationInfo applicationInfo1 = ApplicationInfoBuilder.create()
+ .withPackageName(packageName1)
+ .build();
+ ApplicationInfo applicationInfo2 = ApplicationInfoBuilder.create()
+ .withPackageName(packageName2)
+ .build();
+ PackageManager packageManager = mock(PackageManager.class);
+ when(mContext.getPackageManager()).thenReturn(packageManager);
+ when(packageManager.getApplicationInfo(eq(packageName1), anyInt()))
+ .thenReturn(applicationInfo1);
+ when(packageManager.getApplicationInfo(eq(packageName2), anyInt()))
+ .thenReturn(applicationInfo2);
+
+ // Force the validator to prevent overriding non-overridable changes by using a user build.
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+ Map<Long, PackageOverride> overrides1 = new HashMap<>();
+ overrides1.put(disabledChangeId1, new PackageOverride.Builder().setEnabled(true).build());
+ Map<Long, PackageOverride> overrides2 = new HashMap<>();
+ overrides2.put(disabledChangeId1, new PackageOverride.Builder().setEnabled(true).build());
+ overrides2.put(disabledChangeId2, new PackageOverride.Builder().setEnabled(true).build());
+ Map<String, CompatibilityOverrideConfig> packageNameToOverrides = new HashMap<>();
+ packageNameToOverrides.put(packageName1, new CompatibilityOverrideConfig(overrides1));
+ packageNameToOverrides.put(packageName2, new CompatibilityOverrideConfig(overrides2));
+ CompatibilityOverridesByPackageConfig config = new CompatibilityOverridesByPackageConfig(
+ packageNameToOverrides);
+
+ compatConfig.addAllPackageOverrides(config, /* skipUnknownChangeIds */ true);
+
+ assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo1)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo1)).isFalse();
+ assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo2)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo2)).isTrue();
+ }
+
@Test
public void testPreventInstallerSetNonOverridable() throws Exception {
@@ -641,6 +688,73 @@
}
@Test
+ public void testInstallerCanRemoveOverridesForMultiplePackages() throws Exception {
+ final String packageName1 = "com.some.package1";
+ final String packageName2 = "com.some.package2";
+ final long disabledChangeId1 = 1234L;
+ final long disabledChangeId2 = 1235L;
+ final long enabledChangeId = 1236L;
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledOverridableChangeWithId(disabledChangeId1)
+ .addDisabledOverridableChangeWithId(disabledChangeId2)
+ .addEnabledOverridableChangeWithId(enabledChangeId)
+ .build();
+ ApplicationInfo applicationInfo1 = ApplicationInfoBuilder.create()
+ .withPackageName(packageName1)
+ .build();
+ ApplicationInfo applicationInfo2 = ApplicationInfoBuilder.create()
+ .withPackageName(packageName2)
+ .build();
+ PackageManager packageManager = mock(PackageManager.class);
+ when(mContext.getPackageManager()).thenReturn(packageManager);
+ when(packageManager.getApplicationInfo(eq(packageName1), anyInt()))
+ .thenReturn(applicationInfo1);
+ when(packageManager.getApplicationInfo(eq(packageName2), anyInt()))
+ .thenReturn(applicationInfo2);
+
+ assertThat(compatConfig.addOverride(disabledChangeId1, packageName1, true)).isTrue();
+ assertThat(compatConfig.addOverride(disabledChangeId2, packageName1, true)).isTrue();
+ assertThat(compatConfig.addOverride(enabledChangeId, packageName1, false)).isTrue();
+ assertThat(compatConfig.addOverride(disabledChangeId1, packageName2, true)).isTrue();
+ assertThat(compatConfig.addOverride(disabledChangeId2, packageName2, true)).isTrue();
+ assertThat(compatConfig.addOverride(enabledChangeId, packageName2, false)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo1)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo1)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(enabledChangeId, applicationInfo1)).isFalse();
+ assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo1)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo1)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(enabledChangeId, applicationInfo1)).isFalse();
+
+ // Force the validator to prevent overriding non-overridable changes by using a user build.
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+
+ Set<Long> overridesToRemove1 = new HashSet<>();
+ overridesToRemove1.add(disabledChangeId1);
+ overridesToRemove1.add(enabledChangeId);
+ Set<Long> overridesToRemove2 = new HashSet<>();
+ overridesToRemove2.add(disabledChangeId1);
+ overridesToRemove2.add(disabledChangeId2);
+ Map<String, CompatibilityOverridesToRemoveConfig> packageNameToOverridesToRemove =
+ new HashMap<>();
+ packageNameToOverridesToRemove.put(packageName1,
+ new CompatibilityOverridesToRemoveConfig(overridesToRemove1));
+ packageNameToOverridesToRemove.put(packageName2,
+ new CompatibilityOverridesToRemoveConfig(overridesToRemove2));
+ CompatibilityOverridesToRemoveByPackageConfig config =
+ new CompatibilityOverridesToRemoveByPackageConfig(packageNameToOverridesToRemove);
+
+ compatConfig.removeAllPackageOverrides(config);
+
+ assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo1)).isFalse();
+ assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo1)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(enabledChangeId, applicationInfo1)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(disabledChangeId1, applicationInfo2)).isFalse();
+ assertThat(compatConfig.isChangeEnabled(disabledChangeId2, applicationInfo2)).isFalse();
+ assertThat(compatConfig.isChangeEnabled(enabledChangeId, applicationInfo2)).isFalse();
+ }
+
+ @Test
public void testPreventInstallerRemoveNonOverridable() throws Exception {
final long disabledChangeId1 = 1234L;
final long disabledChangeId2 = 1235L;
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 70641c2..b811e28 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -129,6 +129,7 @@
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TelephonyNetworkSpecifier;
+import android.net.wifi.WifiInfo;
import android.os.Binder;
import android.os.Handler;
import android.os.INetworkManagementService;
@@ -226,13 +227,13 @@
private static final long TEST_START = 1194220800000L;
private static final String TEST_IFACE = "test0";
- private static final String TEST_SSID = "AndroidAP";
+ private static final String TEST_WIFI_NETWORK_KEY = "TestWifiNetworkKey";
private static final String TEST_IMSI = "310210";
private static final int TEST_SUB_ID = 42;
private static final Network TEST_NETWORK = mock(Network.class, CALLS_REAL_METHODS);
- private static NetworkTemplate sTemplateWifi = buildTemplateWifi(TEST_SSID);
+ private static NetworkTemplate sTemplateWifi = buildTemplateWifi(TEST_WIFI_NETWORK_KEY);
private static NetworkTemplate sTemplateCarrierMetered =
buildTemplateCarrierMetered(TEST_IMSI);
@@ -1986,9 +1987,8 @@
assertEquals("Unexpected template match rule in network policies",
NetworkTemplate.MATCH_CARRIER,
actualPolicy.template.getMatchRule());
- assertEquals("Unexpected subscriberId match rule in network policies",
- NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT,
- actualPolicy.template.getSubscriberIdMatchRule());
+ assertTrue("Unexpected subscriberIds size in network policies",
+ actualPolicy.template.getSubscriberIds().size() > 0);
assertEquals("Unexpected template meteredness in network policies",
METERED_YES, actualPolicy.template.getMeteredness());
}
@@ -2003,9 +2003,8 @@
assertEquals("Unexpected template match rule in network policies",
NetworkTemplate.MATCH_WIFI,
actualPolicy.template.getMatchRule());
- assertEquals("Unexpected subscriberId match rule in network policies",
- NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_ALL,
- actualPolicy.template.getSubscriberIdMatchRule());
+ assertEquals("Unexpected subscriberIds size in network policies",
+ actualPolicy.template.getSubscriberIds().size(), 0);
assertEquals("Unexpected template meteredness in network policies",
METERED_NO, actualPolicy.template.getMeteredness());
}
@@ -2098,10 +2097,13 @@
}
private static NetworkStateSnapshot buildWifi() {
+ WifiInfo mockWifiInfo = mock(WifiInfo.class);
+ when(mockWifiInfo.makeCopy(anyLong())).thenReturn(mockWifiInfo);
+ when(mockWifiInfo.getCurrentNetworkKey()).thenReturn(TEST_WIFI_NETWORK_KEY);
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_IFACE);
final NetworkCapabilities networkCapabilities = new NetworkCapabilities.Builder()
- .addTransportType(TRANSPORT_WIFI).setSsid(TEST_SSID).build();
+ .addTransportType(TRANSPORT_WIFI).setTransportInfo(mockWifiInfo).build();
return new NetworkStateSnapshot(TEST_NETWORK, networkCapabilities, prop,
null /*subscriberId*/, TYPE_WIFI);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 6c9f8fe..1b898fa 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -264,17 +264,17 @@
final SuspendParams params = packageUserState1.getSuspendParams().valueAt(0);
watcher.verifyNoChangeReported("fetch user state");
assertThat(params, is(notNullValue()));
- assertThat(params.appExtras.size(), is(1));
- assertThat(params.appExtras.getString("app_extra_string"), is("value"));
- assertThat(params.launcherExtras.size(), is(1));
- assertThat(params.launcherExtras.getLong("launcher_extra_long"), is(4L));
- assertThat(params.dialogInfo, is(notNullValue()));
- assertThat(params.dialogInfo.getDialogMessage(), is("Dialog Message"));
- assertThat(params.dialogInfo.getTitleResId(), is(ID_NULL));
- assertThat(params.dialogInfo.getIconResId(), is(TEST_RESOURCE_ID));
- assertThat(params.dialogInfo.getNeutralButtonTextResId(), is(ID_NULL));
- assertThat(params.dialogInfo.getNeutralButtonAction(), is(BUTTON_ACTION_MORE_DETAILS));
- assertThat(params.dialogInfo.getDialogMessageResId(), is(ID_NULL));
+ assertThat(params.getAppExtras().size(), is(1));
+ assertThat(params.getAppExtras().getString("app_extra_string"), is("value"));
+ assertThat(params.getLauncherExtras().size(), is(1));
+ assertThat(params.getLauncherExtras().getLong("launcher_extra_long"), is(4L));
+ assertThat(params.getDialogInfo(), is(notNullValue()));
+ assertThat(params.getDialogInfo().getDialogMessage(), is("Dialog Message"));
+ assertThat(params.getDialogInfo().getTitleResId(), is(ID_NULL));
+ assertThat(params.getDialogInfo().getIconResId(), is(TEST_RESOURCE_ID));
+ assertThat(params.getDialogInfo().getNeutralButtonTextResId(), is(ID_NULL));
+ assertThat(params.getDialogInfo().getNeutralButtonAction(), is(BUTTON_ACTION_MORE_DETAILS));
+ assertThat(params.getDialogInfo().getDialogMessageResId(), is(ID_NULL));
}
@Test
@@ -351,18 +351,18 @@
final SuspendParams params11 = readPus1.getSuspendParams().valueAt(0);
watcher.verifyNoChangeReported("read package param");
assertThat(params11, is(notNullValue()));
- assertThat(params11.dialogInfo, is(dialogInfo1));
- assertThat(BaseBundle.kindofEquals(params11.appExtras, appExtras1), is(true));
- assertThat(BaseBundle.kindofEquals(params11.launcherExtras, launcherExtras1),
+ assertThat(params11.getDialogInfo(), is(dialogInfo1));
+ assertThat(BaseBundle.kindofEquals(params11.getAppExtras(), appExtras1), is(true));
+ assertThat(BaseBundle.kindofEquals(params11.getLauncherExtras(), launcherExtras1),
is(true));
watcher.verifyNoChangeReported("read package param");
assertThat(readPus1.getSuspendParams().keyAt(1), is("suspendingPackage2"));
final SuspendParams params12 = readPus1.getSuspendParams().valueAt(1);
assertThat(params12, is(notNullValue()));
- assertThat(params12.dialogInfo, is(dialogInfo2));
- assertThat(BaseBundle.kindofEquals(params12.appExtras, appExtras2), is(true));
- assertThat(BaseBundle.kindofEquals(params12.launcherExtras, launcherExtras2),
+ assertThat(params12.getDialogInfo(), is(dialogInfo2));
+ assertThat(BaseBundle.kindofEquals(params12.getAppExtras(), appExtras2), is(true));
+ assertThat(BaseBundle.kindofEquals(params12.getLauncherExtras(), launcherExtras2),
is(true));
watcher.verifyNoChangeReported("read package param");
@@ -373,9 +373,9 @@
assertThat(readPus2.getSuspendParams().keyAt(0), is("suspendingPackage3"));
final SuspendParams params21 = readPus2.getSuspendParams().valueAt(0);
assertThat(params21, is(notNullValue()));
- assertThat(params21.dialogInfo, is(nullValue()));
- assertThat(BaseBundle.kindofEquals(params21.appExtras, appExtras1), is(true));
- assertThat(params21.launcherExtras, is(nullValue()));
+ assertThat(params21.getDialogInfo(), is(nullValue()));
+ assertThat(BaseBundle.kindofEquals(params21.getAppExtras(), appExtras1), is(true));
+ assertThat(params21.getLauncherExtras(), is(nullValue()));
watcher.verifyNoChangeReported("read package param");
final PackageUserStateInternal readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3)
@@ -388,7 +388,7 @@
@Test
public void testPackageRestrictionsSuspendedDefault() {
final PackageSetting defaultSetting = createPackageSetting(PACKAGE_NAME_1);
- assertThat(defaultSetting.getSuspended(0), is(false));
+ assertThat(defaultSetting.getUserStateOrDefault(0).isSuspended(), is(false));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index 828d419c..1e4134e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -82,7 +82,8 @@
assertThat(testUserState.equals(oldUserState), is(false));
oldUserState = new PackageUserStateImpl();
- oldUserState.setSuspended(true);
+ oldUserState.putSuspendParams("suspendingPackage",
+ SuspendParams.getInstanceOrNull(null, new PersistableBundle(), null));
assertThat(testUserState.equals(oldUserState), is(false));
oldUserState = new PackageUserStateImpl();
@@ -231,7 +232,6 @@
final PackageUserStateImpl testUserState1 = new PackageUserStateImpl();
- testUserState1.setSuspended(true);
testUserState1.setSuspendParams(paramsMap1);
PackageUserStateImpl testUserState2 =
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
index 2290ef7..398148f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
@@ -25,23 +25,16 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
import android.app.AppGlobals;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.IPackageManager;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.SuspendDialogInfo;
-import android.content.res.Resources;
import android.os.BaseBundle;
import android.os.Bundle;
import android.os.Handler;
@@ -50,13 +43,6 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import android.util.Log;
-import android.view.IWindowManager;
-import android.view.WindowManagerGlobal;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.FlakyTest;
@@ -65,7 +51,6 @@
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
-import com.android.servicestests.apps.suspendtestapp.SuspendTestActivity;
import com.android.servicestests.apps.suspendtestapp.SuspendTestReceiver;
import org.junit.After;
@@ -76,7 +61,6 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
@@ -84,8 +68,6 @@
@LargeTest
@FlakyTest
public class SuspendPackagesTest {
- private static final String TAG = SuspendPackagesTest.class.getSimpleName();
- private static final String TEST_APP_LABEL = "Suspend Test App";
private static final String TEST_APP_PACKAGE_NAME = SuspendTestReceiver.PACKAGE_NAME;
private static final String[] PACKAGES_TO_SUSPEND = new String[]{TEST_APP_PACKAGE_NAME};
@@ -105,75 +87,11 @@
public static final String EXTRA_RECEIVED_PACKAGE_NAME =
SuspendPackagesTest.INSTRUMENTATION_PACKAGE + ".extra.RECEIVED_PACKAGE_NAME";
-
private Context mContext;
private PackageManager mPackageManager;
private LauncherApps mLauncherApps;
private Handler mReceiverHandler;
- private AppCommunicationReceiver mAppCommsReceiver;
private StubbedCallback mTestCallback;
- private UiDevice mUiDevice;
- private ComponentName mDeviceAdminComponent;
- private boolean mPoSet;
- private boolean mDoSet;
-
- private static final class AppCommunicationReceiver extends BroadcastReceiver {
- private Context context;
- private boolean registered;
- private SynchronousQueue<Intent> intentQueue = new SynchronousQueue<>();
-
- AppCommunicationReceiver(Context context) {
- this.context = context;
- }
-
- void register(Handler handler, String... actions) {
- registered = true;
- final IntentFilter intentFilter = new IntentFilter();
- for (String action : actions) {
- intentFilter.addAction(action);
- }
- context.registerReceiver(this, intentFilter, null, handler);
- }
-
- void unregister() {
- if (registered) {
- context.unregisterReceiver(this);
- }
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.d(TAG, "AppCommunicationReceiver#onReceive: " + intent.getAction());
- try {
- intentQueue.offer(intent, 5, TimeUnit.SECONDS);
- } catch (InterruptedException ie) {
- throw new RuntimeException("Receiver thread interrupted", ie);
- }
- }
-
- Intent pollForIntent(long secondsToWait) {
- if (!registered) {
- throw new IllegalStateException("Receiver not registered");
- }
- final Intent intent;
- try {
- intent = intentQueue.poll(secondsToWait, TimeUnit.SECONDS);
- } catch (InterruptedException ie) {
- throw new RuntimeException("Interrupted while waiting for app broadcast", ie);
- }
- return intent;
- }
-
- void drainPendingBroadcasts() {
- while (pollForIntent(5) != null) ;
- }
-
- Intent receiveIntentFromApp() {
- final Intent intentReceived = pollForIntent(5);
- assertNotNull("No intent received from app within 5 seconds", intentReceived);
- return intentReceived;
- }
- }
@Before
public void setUp() {
@@ -181,9 +99,6 @@
mPackageManager = mContext.getPackageManager();
mLauncherApps = (LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
mReceiverHandler = new Handler(Looper.getMainLooper());
- mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- mDeviceAdminComponent = new ComponentName(mContext,
- "com.android.server.devicepolicy.DummyDeviceAdmins$Admin1");
IPackageManager ipm = AppGlobals.getPackageManager();
try {
// Otherwise implicit broadcasts will not be delivered.
@@ -192,31 +107,6 @@
e.rethrowAsRuntimeException();
}
unsuspendTestPackage();
- mAppCommsReceiver = new AppCommunicationReceiver(mContext);
- }
-
- /**
- * Care should be taken when used with {@link #mAppCommsReceiver} in the same test as both use
- * the same handler.
- */
- private Bundle requestAppAction(String action) throws InterruptedException {
- final AtomicReference<Bundle> result = new AtomicReference<>();
- final CountDownLatch receiverLatch = new CountDownLatch(1);
- final ComponentName testReceiverComponent = new ComponentName(TEST_APP_PACKAGE_NAME,
- SuspendTestReceiver.class.getCanonicalName());
- final Intent broadcastIntent = new Intent(action)
- .setComponent(testReceiverComponent)
- .setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- mContext.sendOrderedBroadcast(broadcastIntent, null, new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- result.set(getResultExtras(true));
- receiverLatch.countDown();
- }
- }, mReceiverHandler, 0, null, null);
-
- assertTrue("Test receiver timed out ", receiverLatch.await(5, TimeUnit.SECONDS));
- return result.get();
}
private PersistableBundle getExtras(String keyPrefix, long lval, String sval, double dval) {
@@ -240,14 +130,6 @@
assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
}
- private void startTestAppActivity() {
- final Intent testActivity = new Intent()
- .setComponent(new ComponentName(TEST_APP_PACKAGE_NAME,
- SuspendTestActivity.class.getCanonicalName()))
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(testActivity);
- }
-
private static boolean areSameExtras(BaseBundle expected, BaseBundle received) {
if (expected != null) {
expected.get(""); // hack to unparcel the bundles.
@@ -265,93 +147,6 @@
}
@Test
- public void testIsPackageSuspended() throws Exception {
- suspendTestPackage(null, null, null);
- assertTrue("isPackageSuspended is false",
- mPackageManager.isPackageSuspended(TEST_APP_PACKAGE_NAME));
- }
-
- @Test
- public void testSuspendedStateFromApp() throws Exception {
- Bundle resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
- assertFalse(resultFromApp.getBoolean(SuspendTestReceiver.EXTRA_SUSPENDED, true));
- assertNull(resultFromApp.getBundle(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
-
- final PersistableBundle appExtras = getExtras("testSuspendedStateFromApp", 20, "20", 0.2);
- suspendTestPackage(appExtras, null, null);
-
- resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
- assertTrue("resultFromApp:suspended is false",
- resultFromApp.getBoolean(SuspendTestReceiver.EXTRA_SUSPENDED));
- final Bundle receivedAppExtras =
- resultFromApp.getBundle(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS);
- assertSameExtras("Received app extras different to the ones supplied",
- appExtras, receivedAppExtras);
- }
-
- @Test
- public void testMyPackageSuspendedUnsuspended() {
- mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_SUSPENDED,
- ACTION_REPORT_MY_PACKAGE_UNSUSPENDED);
- mAppCommsReceiver.drainPendingBroadcasts();
- final PersistableBundle appExtras = getExtras("testMyPackageSuspendBroadcasts", 1, "1", .1);
- suspendTestPackage(appExtras, null, null);
- Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
- assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
- ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
- assertSameExtras("Received app extras different to the ones supplied", appExtras,
- intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
- unsuspendTestPackage();
- intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
- assertEquals("MY_PACKAGE_UNSUSPENDED delivery not reported",
- ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
- }
-
- @Test
- public void testUpdatingAppExtras() {
- mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_SUSPENDED);
- final PersistableBundle extras1 = getExtras("testMyPackageSuspendedOnChangingExtras", 1,
- "1", 0.1);
- suspendTestPackage(extras1, null, null);
- Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
- assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
- ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
- assertSameExtras("Received app extras different to the ones supplied", extras1,
- intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
- final PersistableBundle extras2 = getExtras("testMyPackageSuspendedOnChangingExtras", 2,
- "2", 0.2);
- suspendTestPackage(extras2, null, null);
- intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
- assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
- ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
- assertSameExtras("Received app extras different to the updated extras", extras2,
- intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
- }
-
- @Test
- public void testCannotSuspendSelf() {
- final String[] unchangedPkgs = mPackageManager.setPackagesSuspended(
- new String[]{mContext.getOpPackageName()}, true, null, null,
- (SuspendDialogInfo) null);
- assertTrue(unchangedPkgs.length == 1);
- assertEquals(mContext.getOpPackageName(), unchangedPkgs[0]);
- }
-
- @Test
- public void testActivityStoppedOnSuspend() {
- mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_TEST_ACTIVITY_STARTED,
- ACTION_REPORT_TEST_ACTIVITY_STOPPED);
- startTestAppActivity();
- Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
- assertEquals("Test activity start not reported",
- ACTION_REPORT_TEST_ACTIVITY_STARTED, intentFromApp.getAction());
- suspendTestPackage(null, null, null);
- intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
- assertEquals("Test activity stop not reported on suspending the test app",
- ACTION_REPORT_TEST_ACTIVITY_STOPPED, intentFromApp.getAction());
- }
-
- @Test
public void testGetLauncherExtrasNonNull() {
final Bundle extrasWhenUnsuspended = mLauncherApps.getSuspendedPackageLauncherExtras(
TEST_APP_PACKAGE_NAME, mContext.getUser());
@@ -383,14 +178,15 @@
public void testOnPackagesSuspendedNewAndOld() throws InterruptedException {
final PersistableBundle suppliedExtras = getExtras(
"testOnPackagesSuspendedNewAndOld", 2, "2", 0.2);
- final AtomicReference<String> overridingBothCallbackResult = new AtomicReference<>("");
- final CountDownLatch twoCallbackLatch = new CountDownLatch(2);
+ final AtomicReference<String> error = new AtomicReference<>("");
+ final CountDownLatch rightCallbackLatch = new CountDownLatch(1);
+ final CountDownLatch wrongCallbackLatch = new CountDownLatch(1);
mTestCallback = new StubbedCallback() {
@Override
public void onPackagesSuspended(String[] packageNames, UserHandle user) {
- overridingBothCallbackResult.set(overridingBothCallbackResult.get()
+ error.set(error.get()
+ "Old callback called even when the new one is overriden. ");
- twoCallbackLatch.countDown();
+ wrongCallbackLatch.countDown();
}
@Override
@@ -411,17 +207,16 @@
errorString.append("Unexpected launcherExtras, supplied: " + suppliedExtras
+ ", received: " + launcherExtras + ". ");
}
- overridingBothCallbackResult.set(overridingBothCallbackResult.get()
+ error.set(error.get()
+ errorString.toString());
- twoCallbackLatch.countDown();
+ rightCallbackLatch.countDown();
}
};
mLauncherApps.registerCallback(mTestCallback, mReceiverHandler);
suspendTestPackage(null, suppliedExtras, null);
- assertFalse("Both callbacks were invoked", twoCallbackLatch.await(5, TimeUnit.SECONDS));
- twoCallbackLatch.countDown();
- assertTrue("No callback was invoked", twoCallbackLatch.await(2, TimeUnit.SECONDS));
- final String result = overridingBothCallbackResult.get();
+ assertFalse("Wrong callback was invoked", wrongCallbackLatch.await(5, TimeUnit.SECONDS));
+ assertTrue("Right callback wasn't invoked", rightCallbackLatch.await(2, TimeUnit.SECONDS));
+ final String result = error.get();
assertTrue("Callbacks did not complete as expected: " + result, result.isEmpty());
}
@@ -457,103 +252,6 @@
assertTrue("Callback did not complete as expected: " + result, result.isEmpty());
}
- private void turnScreenOn() throws Exception {
- if (!mUiDevice.isScreenOn()) {
- mUiDevice.wakeUp();
- }
- final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
- wm.dismissKeyguard(null, null);
- }
-
- @Test
- public void testInterceptorActivity() throws Exception {
- turnScreenOn();
- mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED,
- ACTION_REPORT_TEST_ACTIVITY_STARTED);
- final String testMessage = "This is a test message to report suspension of %1$s";
- suspendTestPackage(null, null,
- new SuspendDialogInfo.Builder().setMessage(testMessage).build());
- startTestAppActivity();
- assertNull("No broadcast was expected from app", mAppCommsReceiver.pollForIntent(2));
- assertNotNull("Given dialog message not shown", mUiDevice.wait(
- Until.findObject(By.text(String.format(testMessage, TEST_APP_LABEL))), 5000));
- final String buttonText = mContext.getResources().getString(Resources.getSystem()
- .getIdentifier("app_suspended_more_details", "string", "android"));
- final UiObject2 moreDetailsButton = mUiDevice.findObject(
- By.clickable(true).text(buttonText));
- assertNotNull(buttonText + " button not shown", moreDetailsButton);
- moreDetailsButton.click();
- final Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
- assertEquals(buttonText + " activity start not reported",
- ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED, intentFromApp.getAction());
- final String receivedPackageName = intentFromApp.getStringExtra(
- EXTRA_RECEIVED_PACKAGE_NAME);
- assertEquals("Wrong package name received by " + buttonText + " activity",
- TEST_APP_PACKAGE_NAME, receivedPackageName);
- }
-
- private boolean setProfileOwner() throws IOException {
- final String result = mUiDevice.executeShellCommand("dpm set-profile-owner --user cur "
- + mDeviceAdminComponent.flattenToString());
- return mPoSet = result.trim().startsWith("Success");
- }
-
- private boolean setDeviceOwner() throws IOException {
- final String result = mUiDevice.executeShellCommand("dpm set-device-owner --user cur "
- + mDeviceAdminComponent.flattenToString());
- return mDoSet = result.trim().startsWith("Success");
- }
-
- private void removeProfileOrDeviceOwner() throws IOException {
- if (mPoSet || mDoSet) {
- mUiDevice.executeShellCommand("dpm remove-active-admin --user cur "
- + mDeviceAdminComponent.flattenToString());
- mPoSet = mDoSet = false;
- }
- }
-
- @Test
- public void testCanSuspendWhenProfileOwner() throws IOException {
- assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
- assertTrue("Profile-owner could not be set", setProfileOwner());
- suspendTestPackage(null, null, null);
- }
-
- @Test
- public void testCanSuspendWhenDeviceOwner() throws IOException {
- assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
- assertTrue("Device-owner could not be set", setDeviceOwner());
- suspendTestPackage(null, null, null);
- }
-
- @Test
- public void testPackageUnsuspendedOnAddingDeviceOwner() throws IOException {
- assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
- mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_UNSUSPENDED,
- ACTION_REPORT_MY_PACKAGE_SUSPENDED);
- mAppCommsReceiver.drainPendingBroadcasts();
- suspendTestPackage(null, null, null);
- Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
- assertEquals(ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
- assertTrue("Device-owner could not be set", setDeviceOwner());
- intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
- assertEquals(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
- }
-
- @Test
- public void testPackageUnsuspendedOnAddingProfileOwner() throws IOException {
- assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
- mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_UNSUSPENDED,
- ACTION_REPORT_MY_PACKAGE_SUSPENDED);
- mAppCommsReceiver.drainPendingBroadcasts();
- suspendTestPackage(null, null, null);
- Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
- assertEquals(ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
- assertTrue("Profile-owner could not be set", setProfileOwner());
- intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
- assertEquals(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
- }
-
@Test
public void testCameraBlockedOnSuspend() throws Exception {
assertOpBlockedOnSuspend(OP_CAMERA);
@@ -596,13 +294,9 @@
@After
public void tearDown() throws IOException {
- mAppCommsReceiver.unregister();
if (mTestCallback != null) {
mLauncherApps.unregisterCallback(mTestCallback);
}
- removeProfileOrDeviceOwner();
- mContext.sendBroadcast(new Intent(ACTION_FINISH_TEST_ACTIVITY)
- .setPackage(TEST_APP_PACKAGE_NAME));
}
private static abstract class StubbedCallback extends LauncherApps.Callback {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 62a0dd4..419dda5 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -62,6 +62,7 @@
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static com.google.common.truth.Truth.assertThat;
@@ -5482,6 +5483,39 @@
}
@Test
+ public void testRateLimitedToasts_windowsRemoved() throws Exception {
+ final String testPackage = "testPackageName";
+ assertEquals(0, mService.mToastQueue.size());
+ mService.isSystemUid = false;
+ setToastRateIsWithinQuota(false); // rate limit reached
+ setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false);
+ setAppInForegroundForToasts(mUid, false);
+
+ // package is not suspended
+ when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
+ .thenReturn(false);
+
+ Binder token = new Binder();
+ INotificationManager nmService = (INotificationManager) mService.mService;
+
+ nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null);
+
+ // window token was added when enqueued
+ ArgumentCaptor<Binder> binderCaptor =
+ ArgumentCaptor.forClass(Binder.class);
+ verify(mWindowManagerInternal).addWindowToken(binderCaptor.capture(),
+ eq(TYPE_TOAST), anyInt(), eq(null));
+
+ // but never shown
+ verify(mStatusBar, times(0))
+ .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
+
+ // and removed when rate limited
+ verify(mWindowManagerInternal)
+ .removeWindowToken(eq(binderCaptor.getValue()), eq(true), anyInt());
+ }
+
+ @Test
public void backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast() throws
Exception {
final String testPackage = "testPackageName";
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 2e62286..8a057f7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2311,17 +2311,15 @@
// Set initial orientation and update.
activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- mDisplayContent.updateOrientation(
- mDisplayContent.getRequestedOverrideConfiguration(),
- null /* freezeThisOneIfNeeded */, false /* forceUpdate */);
+ mDisplayContent.updateOrientation(null /* freezeThisOneIfNeeded */,
+ false /* forceUpdate */);
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getLastOrientation());
appWindow.mResizeReported = false;
// Update the orientation to perform 180 degree rotation and check that resize was reported.
activity.setOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
- mDisplayContent.updateOrientation(
- mDisplayContent.getRequestedOverrideConfiguration(),
- null /* freezeThisOneIfNeeded */, false /* forceUpdate */);
+ mDisplayContent.updateOrientation(null /* freezeThisOneIfNeeded */,
+ false /* forceUpdate */);
// In this test, DC will not get config update. Set the waiting flag to false.
mDisplayContent.mWaitingForConfig = false;
mWm.mRoot.performSurfacePlacement();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index af45b80..acf6dc5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -22,18 +22,9 @@
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.ITYPE_TOP_GESTURES;
import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
@@ -56,11 +47,8 @@
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.InsetsState;
-import android.view.InsetsVisibilities;
import android.view.PrivacyIndicatorBounds;
import android.view.RoundedCorners;
-import android.view.WindowInsets.Side;
-import android.view.WindowInsets.Type;
import androidx.test.filters.SmallTest;
@@ -108,15 +96,6 @@
updateDisplayFrames();
}
- void addWindowWithRawInsetsState(WindowState win) {
- addWindow(win);
- // Without mPerformLayout in display content, the window cannot see any insets. Override the
- // insets state with the global one.
- final InsetsState insetsState =
- win.getDisplayContent().getInsetsStateController().getRawInsetsState();
- win.mAboveInsetsState.set(insetsState);
- }
-
public void setRotation(int rotation, boolean includingWindows) {
mRotation = rotation;
updateDisplayFrames();
@@ -232,388 +211,6 @@
}
@Test
- public void layoutWindowLw_fitStatusBars() {
- mWindow.mAttrs.setFitInsetsTypes(Type.statusBars());
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
- }
-
- @Test
- public void layoutWindowLw_fitNavigationBars() {
- mWindow.mAttrs.setFitInsetsTypes(Type.navigationBars());
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
- }
-
- @Test
- public void layoutWindowLw_fitAllSides() {
- mWindow.mAttrs.setFitInsetsSides(Side.all());
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- }
-
- @Test
- public void layoutWindowLw_fitTopOnly() {
- mWindow.mAttrs.setFitInsetsSides(Side.TOP);
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
- }
-
- @Test
- public void layoutWindowLw_fitInsetsIgnoringVisibility() {
- final InsetsState state =
- mDisplayContent.getInsetsStateController().getRawInsetsState();
- state.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
- state.getSource(InsetsState.ITYPE_NAVIGATION_BAR).setVisible(false);
- mWindow.mAttrs.setFitInsetsIgnoringVisibility(true);
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- }
-
- @Test
- public void layoutWindowLw_fitInsetsNotIgnoringVisibility() {
- final InsetsState state =
- mDisplayContent.getInsetsStateController().getRawInsetsState();
- state.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
- state.getSource(InsetsState.ITYPE_NAVIGATION_BAR).setVisible(false);
- mWindow.mAttrs.setFitInsetsIgnoringVisibility(false);
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- }
-
- @Test
- public void layoutWindowLw_insetParentFrameByIme() {
- final InsetsState state =
- mDisplayContent.getInsetsStateController().getRawInsetsState();
- state.getSource(InsetsState.ITYPE_IME).setVisible(true);
- state.getSource(InsetsState.ITYPE_IME).setFrame(
- 0, DISPLAY_HEIGHT - IME_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT);
- mWindow.mAttrs.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, IME_HEIGHT);
- }
-
- @Test
- public void layoutWindowLw_fitDisplayCutout() {
- addDisplayCutout();
-
- mWindow.mAttrs.setFitInsetsTypes(Type.displayCutout());
- mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout() {
- addDisplayCutout();
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_never() {
- addDisplayCutout();
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_shortEdges() {
- addDisplayCutout();
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_always() {
- addDisplayCutout();
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_layoutFullscreen() {
- addDisplayCutout();
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_fullscreen() {
- addDisplayCutout();
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mDisplayContent.getInsetsStateController().getRawInsetsState()
- .getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
- final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
- requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
- mWindow.setRequestedVisibilities(requestedVisibilities);
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, 0);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_fullscreenInCutout() {
- addDisplayCutout();
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mDisplayContent.getInsetsStateController().getRawInsetsState()
- .getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
- final InsetsVisibilities requestedVisibilities = new InsetsVisibilities();
- requestedVisibilities.setVisibility(ITYPE_STATUS_BAR, false);
- mWindow.setRequestedVisibilities(requestedVisibilities);
- mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
- assertInsetByTopBottom(mWindow.getDisplayFrame(), 0, 0);
- }
-
-
- @Test
- public void layoutWindowLw_withDisplayCutout_landscape() {
- addDisplayCutout();
- setRotation(ROTATION_90, true /* includingWindows */);
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_seascape() {
- addDisplayCutout();
- setRotation(ROTATION_270, true /* includingWindows */);
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetBy(mWindow.getParentFrame(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
- assertInsetBy(mWindow.getDisplayFrame(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_fullscreen_landscape() {
- addDisplayCutout();
- setRotation(ROTATION_90, true /* includingWindows */);
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_floatingInScreen() {
- addDisplayCutout();
-
- mWindow.mAttrs.flags = FLAG_LAYOUT_IN_SCREEN;
- mWindow.mAttrs.setFitInsetsTypes(Type.systemBars() & ~Type.statusBars());
- mWindow.mAttrs.type = TYPE_APPLICATION_OVERLAY;
- mWindow.mAttrs.width = DISPLAY_WIDTH;
- mWindow.mAttrs.height = DISPLAY_HEIGHT;
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mWindow.getDisplayFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_fullscreenInCutout_landscape() {
- addDisplayCutout();
- setRotation(ROTATION_90, true /* includingWindows */);
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
- }
-
- @Test
- public void layoutWindowLw_withLongEdgeDisplayCutout() {
- addLongEdgeDisplayCutout();
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- }
-
- @Test
- public void layoutWindowLw_withLongEdgeDisplayCutout_never() {
- addLongEdgeDisplayCutout();
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- }
-
- @Test
- public void layoutWindowLw_withLongEdgeDisplayCutout_shortEdges() {
- addLongEdgeDisplayCutout();
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- }
-
- @Test
- public void layoutWindowLw_withLongEdgeDisplayCutout_always() {
- addLongEdgeDisplayCutout();
-
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- addWindowWithRawInsetsState(mWindow);
-
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
- }
-
- @Test
- public void layoutWindowLw_withForwardInset_SoftInputAdjustNothing() {
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_NOTHING;
- addWindowWithRawInsetsState(mWindow);
-
- final int forwardedInsetBottom = 50;
- mDisplayPolicy.setForwardedInsets(Insets.of(0, 0, 0, forwardedInsetBottom));
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-
- assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
- assertInsetBy(mWindow.getDisplayFrame(), 0, 0, 0, 0);
- }
-
- @Test
public void layoutHint_appWindow() {
mWindow.mAttrs.setFitInsetsTypes(0);
@@ -691,22 +288,4 @@
assertEquals(DISPLAY_WIDTH, frame.width());
assertEquals(DISPLAY_HEIGHT, rotatedFrame.width());
}
-
- /**
- * Asserts that {@code actual} is inset by the given amounts from the full display rect.
- *
- * Convenience wrapper for when only the top and bottom inset are non-zero.
- */
- private void assertInsetByTopBottom(Rect actual, int expectedInsetTop,
- int expectedInsetBottom) {
- assertInsetBy(actual, 0, expectedInsetTop, 0, expectedInsetBottom);
- }
-
- /** Asserts that {@code actual} is inset by the given amounts from the full display rect. */
- private void assertInsetBy(Rect actual, int expectedInsetLeft, int expectedInsetTop,
- int expectedInsetRight, int expectedInsetBottom) {
- assertEquals(new Rect(expectedInsetLeft, expectedInsetTop,
- mFrames.mDisplayWidth - expectedInsetRight,
- mFrames.mDisplayHeight - expectedInsetBottom), actual);
- }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 8da8596..6970005 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -189,11 +189,6 @@
assertEquals(0,
displayPolicy.updateLightNavigationBarLw(APPEARANCE_LIGHT_NAVIGATION_BARS, null));
- // Dimming window clears APPEARANCE_LIGHT_NAVIGATION_BARS.
- assertEquals(0, displayPolicy.updateLightNavigationBarLw(0, dimming));
- assertEquals(0, displayPolicy.updateLightNavigationBarLw(
- APPEARANCE_LIGHT_NAVIGATION_BARS, dimming));
-
// Control window overrides APPEARANCE_LIGHT_NAVIGATION_BARS flag.
assertEquals(0, displayPolicy.updateLightNavigationBarLw(0, opaqueDarkNavBar));
assertEquals(0, displayPolicy.updateLightNavigationBarLw(
diff --git a/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java b/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
index 3714d99..f5d915d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
@@ -39,6 +39,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
/**
* Test for the splash screen exception list
@@ -55,7 +56,16 @@
private DeviceConfig.Properties mInitialWindowManagerProperties;
private final HandlerExecutor mExecutor = new HandlerExecutor(
new Handler(Looper.getMainLooper()));
- private final SplashScreenExceptionList mList = new SplashScreenExceptionList(mExecutor);
+ private final SplashScreenExceptionList mList = new SplashScreenExceptionList(mExecutor) {
+ @Override
+ void updateDeviceConfig(String rawList) {
+ super.updateDeviceConfig(rawList);
+ if (mOnUpdateDeviceConfig != null) {
+ mOnUpdateDeviceConfig.accept(rawList);
+ }
+ }
+ };
+ private Consumer<String> mOnUpdateDeviceConfig;
@Before
public void setUp() throws Exception {
@@ -91,13 +101,11 @@
private void setExceptionListAndWaitForCallback(String commaSeparatedList) {
CountDownLatch latch = new CountDownLatch(1);
- DeviceConfig.OnPropertiesChangedListener onPropertiesChangedListener = (p) -> {
- if (commaSeparatedList.equals(p.getString(KEY_SPLASH_SCREEN_EXCEPTION_LIST, null))) {
+ mOnUpdateDeviceConfig = rawList -> {
+ if (commaSeparatedList.equals(rawList)) {
latch.countDown();
}
};
- DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
- mExecutor, onPropertiesChangedListener);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
KEY_SPLASH_SCREEN_EXCEPTION_LIST, commaSeparatedList, false);
try {
@@ -105,8 +113,6 @@
latch.await(1, TimeUnit.SECONDS));
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
- } finally {
- DeviceConfig.removeOnPropertiesChangedListener(onPropertiesChangedListener);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index a1d0eb8..790b154 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -25,11 +25,10 @@
import static com.android.server.wm.utils.CommonUtils.runWithShellPermissionIdentity;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
import android.app.Activity;
+import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.TaskDescription;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
@@ -57,7 +56,6 @@
import androidx.test.filters.MediumTest;
import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
@@ -73,49 +71,42 @@
@MediumTest
public class TaskStackChangedListenerTest {
- private static final int VIRTUAL_DISPLAY_WIDTH = 800;
- private static final int VIRTUAL_DISPLAY_HEIGHT = 600;
- private static final int VIRTUAL_DISPLAY_DENSITY = 160;
-
private ITaskStackListener mTaskStackListener;
- private DisplayManager mDisplayManager;
private VirtualDisplay mVirtualDisplay;
+ private ImageReader mImageReader;
private static final int WAIT_TIMEOUT_MS = 5000;
private static final Object sLock = new Object();
- @Before
- public void setUp() {
- mDisplayManager = getInstrumentation().getContext().getSystemService(
- DisplayManager.class);
- mVirtualDisplay = createVirtualDisplay(
- getClass().getSimpleName() + "_virtualDisplay",
- VIRTUAL_DISPLAY_WIDTH, VIRTUAL_DISPLAY_HEIGHT, VIRTUAL_DISPLAY_DENSITY);
- }
-
@After
public void tearDown() throws Exception {
- ActivityTaskManager.getService().unregisterTaskStackListener(mTaskStackListener);
- mTaskStackListener = null;
- mVirtualDisplay.release();
+ if (mTaskStackListener != null) {
+ ActivityTaskManager.getService().unregisterTaskStackListener(mTaskStackListener);
+ }
+ if (mVirtualDisplay != null) {
+ mVirtualDisplay.release();
+ mImageReader.close();
+ }
}
- private VirtualDisplay createVirtualDisplay(String name, int width, int height, int density) {
- VirtualDisplay virtualDisplay = null;
- try (ImageReader reader = ImageReader.newInstance(width, height,
- /* format= */ PixelFormat.RGBA_8888, /* maxImages= */ 2)) {
- int flags = VIRTUAL_DISPLAY_FLAG_PRESENTATION | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
- | VIRTUAL_DISPLAY_FLAG_PUBLIC;
- virtualDisplay = mDisplayManager.createVirtualDisplay(
- name, width, height, density, reader.getSurface(), flags);
- virtualDisplay.setSurface(reader.getSurface());
- }
- assertTrue("display id must be unique",
- virtualDisplay.getDisplay().getDisplayId() != Display.DEFAULT_DISPLAY);
+ private VirtualDisplay createVirtualDisplay() {
+ final int width = 800;
+ final int height = 600;
+ final int density = 160;
+ final DisplayManager displayManager = getInstrumentation().getContext().getSystemService(
+ DisplayManager.class);
+ mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888,
+ 2 /* maxImages */);
+ final int flags = VIRTUAL_DISPLAY_FLAG_PRESENTATION | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+ | VIRTUAL_DISPLAY_FLAG_PUBLIC;
+ final String name = getClass().getSimpleName() + "_VirtualDisplay";
+ mVirtualDisplay = displayManager.createVirtualDisplay(name, width, height, density,
+ mImageReader.getSurface(), flags);
+ mVirtualDisplay.setSurface(mImageReader.getSurface());
assertNotNull("display must be registered",
- Arrays.asList(mDisplayManager.getDisplays()).stream().filter(
+ Arrays.stream(displayManager.getDisplays()).filter(
d -> d.getName().equals(name)).findAny());
- return virtualDisplay;
+ return mVirtualDisplay;
}
@Test
@@ -163,11 +154,10 @@
mTaskId = taskId;
}
@Override
- public void onTaskDescriptionChanged(int taskId, TaskDescription td)
- throws RemoteException {
- if (mTaskId == taskId && !TextUtils.isEmpty(td.getLabel())) {
- params[0] = taskId;
- params[1] = td;
+ public void onTaskDescriptionChanged(RunningTaskInfo info) {
+ if (mTaskId == info.taskId && !TextUtils.isEmpty(info.taskDescription.getLabel())) {
+ params[0] = info.taskId;
+ params[1] = info.taskDescription;
latch.countDown();
}
}
@@ -211,75 +201,71 @@
@Test
@Presubmit
public void testTaskChangeCallBacks() throws Exception {
- final Object[] params = new Object[2];
final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1);
final CountDownLatch taskMovedToFrontLatch = new CountDownLatch(1);
final CountDownLatch taskRemovedLatch = new CountDownLatch(1);
final CountDownLatch taskRemovalStartedLatch = new CountDownLatch(1);
- final CountDownLatch onDetachedFromWindowLatch = new CountDownLatch(1);
+ final int[] expectedTaskId = { -1 };
+ final int[] receivedTaskId = { -1 };
+ final ComponentName expectedName = new ComponentName(getInstrumentation().getContext(),
+ ActivityTaskChangeCallbacks.class);
registerTaskStackChangedListener(new TaskStackListener() {
@Override
- public void onTaskCreated(int taskId, ComponentName componentName)
- throws RemoteException {
- params[0] = taskId;
- params[1] = componentName;
- taskCreatedLaunchLatch.countDown();
+ public void onTaskCreated(int taskId, ComponentName componentName) {
+ receivedTaskId[0] = taskId;
+ if (expectedName.equals(componentName)) {
+ taskCreatedLaunchLatch.countDown();
+ }
}
@Override
- public void onTaskMovedToFront(int taskId) throws RemoteException {
- params[0] = taskId;
+ public void onTaskMovedToFront(RunningTaskInfo info) {
+ receivedTaskId[0] = info.taskId;
taskMovedToFrontLatch.countDown();
}
@Override
- public void onTaskRemovalStarted(int taskId) {
- params[0] = taskId;
- taskRemovalStartedLatch.countDown();
+ public void onTaskRemovalStarted(RunningTaskInfo info) {
+ if (expectedTaskId[0] == info.taskId) {
+ taskRemovalStartedLatch.countDown();
+ }
}
@Override
- public void onTaskRemoved(int taskId) throws RemoteException {
- if (taskCreatedLaunchLatch.getCount() == 1) {
- // The test activity hasn't started. Ignore the noise from previous test.
- return;
+ public void onTaskRemoved(int taskId) {
+ if (expectedTaskId[0] == taskId) {
+ taskRemovedLatch.countDown();
}
- params[0] = taskId;
- taskRemovedLatch.countDown();
}
});
final ActivityTaskChangeCallbacks activity =
(ActivityTaskChangeCallbacks) startTestActivity(ActivityTaskChangeCallbacks.class);
- activity.setDetachedFromWindowLatch(onDetachedFromWindowLatch);
- final int id = activity.getTaskId();
+ expectedTaskId[0] = activity.getTaskId();
// Test for onTaskCreated and onTaskMovedToFront
waitForCallback(taskMovedToFrontLatch);
assertEquals(0, taskCreatedLaunchLatch.getCount());
- assertEquals(id, params[0]);
- ComponentName componentName = (ComponentName) params[1];
- assertEquals(ActivityTaskChangeCallbacks.class.getName(), componentName.getClassName());
+ assertEquals(expectedTaskId[0], receivedTaskId[0]);
+ // Ensure that the window is attached before removal so there will be a detached callback.
+ waitForCallback(activity.mOnAttachedToWindowCountDownLatch);
// Test for onTaskRemovalStarted.
assertEquals(1, taskRemovalStartedLatch.getCount());
assertEquals(1, taskRemovedLatch.getCount());
activity.finishAndRemoveTask();
waitForCallback(taskRemovalStartedLatch);
// onTaskRemovalStarted happens before the activity's window is removed.
- assertFalse(activity.mOnDetachedFromWindowCalled);
- assertEquals(id, params[0]);
+ assertEquals(1, activity.mOnDetachedFromWindowCountDownLatch.getCount());
// Test for onTaskRemoved.
waitForCallback(taskRemovedLatch);
- assertEquals(id, params[0]);
- waitForCallback(onDetachedFromWindowLatch);
- assertTrue(activity.mOnDetachedFromWindowCalled);
+ waitForCallback(activity.mOnDetachedFromWindowCountDownLatch);
}
@Test
public void testTaskDisplayChanged() throws Exception {
- int virtualDisplayId = mVirtualDisplay.getDisplay().getDisplayId();
+ final int virtualDisplayId = createVirtualDisplay().getDisplay().getDisplayId();
// Launch a Activity inside VirtualDisplay
CountDownLatch displayChangedLatch1 = new CountDownLatch(1);
@@ -498,18 +484,18 @@
}
public static class ActivityTaskChangeCallbacks extends TestActivity {
- public boolean mOnDetachedFromWindowCalled = false;
- private CountDownLatch mOnDetachedFromWindowCountDownLatch;
+ final CountDownLatch mOnAttachedToWindowCountDownLatch = new CountDownLatch(1);
+ final CountDownLatch mOnDetachedFromWindowCountDownLatch = new CountDownLatch(1);
+
+ @Override
+ public void onAttachedToWindow() {
+ mOnAttachedToWindowCountDownLatch.countDown();
+ }
@Override
public void onDetachedFromWindow() {
- mOnDetachedFromWindowCalled = true;
mOnDetachedFromWindowCountDownLatch.countDown();
}
-
- void setDetachedFromWindowLatch(CountDownLatch countDownLatch) {
- mOnDetachedFromWindowCountDownLatch = countDownLatch;
- }
}
public static class ActivityInVirtualDisplay extends TestActivity {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index ec6cd92..ed3888c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -556,8 +556,15 @@
// The redrawn window will be faded in when the transition finishes. And because this test
// only use one non-activity window, the fade rotation controller should also be cleared.
- statusBar.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
+ statusBar.mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
+ final SurfaceControl.Transaction postDrawTransaction =
+ mock(SurfaceControl.Transaction.class);
+ final boolean layoutNeeded = statusBar.finishDrawing(postDrawTransaction);
+ assertFalse(layoutNeeded);
player.finish();
+ // The controller should capture the draw transaction and merge it when preparing to run
+ // fade-in animation.
+ verify(mDisplayContent.getPendingTransaction()).merge(eq(postDrawTransaction));
assertNull(mDisplayContent.getFadeRotationAnimationController());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java
index 117f2ff..338555e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java
@@ -16,16 +16,32 @@
package com.android.server.wm;
+import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT;
+import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
+import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
+import static android.view.InsetsState.ITYPE_RIGHT_DISPLAY_CUTOUT;
+import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
import static android.view.WindowLayout.UNSPECIFIED_LENGTH;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static org.junit.Assert.assertEquals;
import android.app.WindowConfiguration;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
+import android.view.DisplayCutout;
import android.view.Gravity;
import android.view.InsetsState;
import android.view.InsetsVisibilities;
+import android.view.WindowInsets;
import android.view.WindowLayout;
import android.view.WindowManager;
@@ -35,7 +51,7 @@
import org.junit.Test;
/**
- * Tests for the {@link WindowLayout#computeWindowFrames}.
+ * Tests for the {@link WindowLayout#computeFrames}.
*
* Build/Install/Run:
* atest WmTests:WindowLayoutTests
@@ -47,6 +63,11 @@
private static final int DISPLAY_HEIGHT = 1000;
private static final int STATUS_BAR_HEIGHT = 10;
private static final int NAVIGATION_BAR_HEIGHT = 15;
+ private static final int IME_HEIGHT = 400;
+ private static final int DISPLAY_CUTOUT_HEIGHT = 8;
+ private static final Rect DISPLAY_CUTOUT_BOUNDS_TOP =
+ new Rect(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT);
+ private static final Insets WATERFALL_INSETS = Insets.of(6, 0, 12, 0);
private final WindowLayout mWindowLayout = new WindowLayout();
private final Rect mDisplayFrame = new Rect();
@@ -69,9 +90,9 @@
mAttrs = new WindowManager.LayoutParams();
mState = new InsetsState();
mState.setDisplayFrame(new Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT));
- mState.getSource(InsetsState.ITYPE_STATUS_BAR).setFrame(
+ mState.getSource(ITYPE_STATUS_BAR).setFrame(
0, 0, DISPLAY_WIDTH, STATUS_BAR_HEIGHT);
- mState.getSource(InsetsState.ITYPE_NAVIGATION_BAR).setFrame(
+ mState.getSource(ITYPE_NAVIGATION_BAR).setFrame(
0, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT);
mState.getDisplayCutoutSafe(mDisplayCutoutSafe);
mWindowBounds = new Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
@@ -83,34 +104,65 @@
mCompatScale = 1f;
}
- @Test
- public void testDefaultLayoutParams() {
- computeWindowFrames();
+ private void computeFrames() {
+ mWindowLayout.computeFrames(mAttrs, mState, mDisplayCutoutSafe, mWindowBounds,
+ mWindowingMode, mRequestedWidth, mRequestedHeight, mRequestedVisibilities,
+ mAttachedWindowFrame, mCompatScale, mDisplayFrame, mParentFrame, mFrame);
+ }
- assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
- mDisplayFrame);
- assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
- mParentFrame);
- assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
- mFrame);
+ private void addDisplayCutout() {
+ mState.setDisplayCutout(new DisplayCutout(
+ Insets.of(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0),
+ new Rect(),
+ DISPLAY_CUTOUT_BOUNDS_TOP,
+ new Rect(),
+ new Rect(),
+ WATERFALL_INSETS));
+ mState.getDisplayCutoutSafe(mDisplayCutoutSafe);
+ mState.getSource(ITYPE_LEFT_DISPLAY_CUTOUT).setFrame(
+ 0, 0, mDisplayCutoutSafe.left, DISPLAY_HEIGHT);
+ mState.getSource(ITYPE_TOP_DISPLAY_CUTOUT).setFrame(
+ 0, 0, DISPLAY_WIDTH, mDisplayCutoutSafe.top);
+ mState.getSource(ITYPE_RIGHT_DISPLAY_CUTOUT).setFrame(
+ mDisplayCutoutSafe.right, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
+ mState.getSource(ITYPE_BOTTOM_DISPLAY_CUTOUT).setFrame(
+ 0, mDisplayCutoutSafe.bottom, DISPLAY_WIDTH, DISPLAY_HEIGHT);
+ }
+
+ private static void assertInsetByTopBottom(int top, int bottom, Rect actual) {
+ assertInsetBy(0, top, 0, bottom, actual);
+ }
+
+ private static void assertInsetBy(int left, int top, int right, int bottom, Rect actual) {
+ assertRect(left, top, DISPLAY_WIDTH - right, DISPLAY_HEIGHT - bottom, actual);
+ }
+
+ private static void assertRect(int left, int top, int right, int bottom, Rect actual) {
+ assertEquals(new Rect(left, top, right, bottom), actual);
}
@Test
- public void testUnmeasured() {
+ public void defaultParams() {
+ computeFrames();
+
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+ }
+
+ @Test
+ public void unmeasured() {
mRequestedWidth = UNSPECIFIED_LENGTH;
mRequestedHeight = UNSPECIFIED_LENGTH;
- computeWindowFrames();
+ computeFrames();
- assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
- mDisplayFrame);
- assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
- mParentFrame);
- assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
- mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
}
@Test
- public void testUnmeasuredWithSizeSpecifiedInLayoutParams() {
+ public void unmeasuredWithSizeSpecifiedInLayoutParams() {
final int width = DISPLAY_WIDTH / 2;
final int height = DISPLAY_HEIGHT / 2;
mRequestedWidth = UNSPECIFIED_LENGTH;
@@ -118,41 +170,218 @@
mAttrs.width = width;
mAttrs.height = height;
mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
- computeWindowFrames();
+ computeFrames();
- assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
- mDisplayFrame);
- assertRect(0, STATUS_BAR_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
- mParentFrame);
- assertRect(0, STATUS_BAR_HEIGHT, width, STATUS_BAR_HEIGHT + height,
- mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
+ assertRect(0, STATUS_BAR_HEIGHT, width, STATUS_BAR_HEIGHT + height, mFrame);
}
@Test
- public void testNonFullscreenWindowBounds() {
+ public void nonFullscreenWindowBounds() {
final int top = Math.max(DISPLAY_HEIGHT / 2, STATUS_BAR_HEIGHT);
mWindowBounds.set(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT);
mRequestedWidth = UNSPECIFIED_LENGTH;
mRequestedHeight = UNSPECIFIED_LENGTH;
- computeWindowFrames();
+ computeFrames();
- assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
+ assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, mDisplayFrame);
+ assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, mParentFrame);
+ assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, mFrame);
+ }
+
+ @Test
+ public void fitStatusBars() {
+ mAttrs.setFitInsetsTypes(WindowInsets.Type.statusBars());
+ computeFrames();
+
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mDisplayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mParentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mFrame);
+ }
+
+ @Test
+ public void fitNavigationBars() {
+ mAttrs.setFitInsetsTypes(WindowInsets.Type.navigationBars());
+ computeFrames();
+
+ assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
+ assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mParentFrame);
+ assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mFrame);
+ }
+
+ @Test
+ public void fitZeroTypes() {
+ mAttrs.setFitInsetsTypes(0);
+ computeFrames();
+
+ assertInsetByTopBottom(0, 0, mDisplayFrame);
+ assertInsetByTopBottom(0, 0, mParentFrame);
+ assertInsetByTopBottom(0, 0, mFrame);
+ }
+
+ @Test
+ public void fitAllSides() {
+ mAttrs.setFitInsetsSides(WindowInsets.Side.all());
+ computeFrames();
+
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+ }
+
+ @Test
+ public void fitTopOnly() {
+ mAttrs.setFitInsetsSides(WindowInsets.Side.TOP);
+ computeFrames();
+
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mDisplayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mParentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mFrame);
+ }
+
+ @Test
+ public void fitZeroSides() {
+ mAttrs.setFitInsetsSides(0);
+ computeFrames();
+
+ assertInsetByTopBottom(0, 0, mDisplayFrame);
+ assertInsetByTopBottom(0, 0, mParentFrame);
+ assertInsetByTopBottom(0, 0, mFrame);
+ }
+
+ @Test
+ public void fitInvisibleInsets() {
+ mState.getSource(ITYPE_STATUS_BAR).setVisible(false);
+ mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false);
+ computeFrames();
+
+ assertInsetByTopBottom(0, 0, mDisplayFrame);
+ assertInsetByTopBottom(0, 0, mParentFrame);
+ assertInsetByTopBottom(0, 0, mFrame);
+ }
+
+ @Test
+ public void fitInvisibleInsetsIgnoringVisibility() {
+ mState.getSource(ITYPE_STATUS_BAR).setVisible(false);
+ mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false);
+ mAttrs.setFitInsetsIgnoringVisibility(true);
+ computeFrames();
+
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+ }
+
+ @Test
+ public void insetParentFrameByIme() {
+ mState.getSource(InsetsState.ITYPE_IME).setVisible(true);
+ mState.getSource(InsetsState.ITYPE_IME).setFrame(
+ 0, DISPLAY_HEIGHT - IME_HEIGHT, DISPLAY_WIDTH, DISPLAY_HEIGHT);
+ mAttrs.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
+ computeFrames();
+
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, IME_HEIGHT, mParentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, IME_HEIGHT, mFrame);
+ }
+
+ @Test
+ public void fitDisplayCutout() {
+ addDisplayCutout();
+ mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ mAttrs.setFitInsetsTypes(WindowInsets.Type.displayCutout());
+ computeFrames();
+
+ assertInsetBy(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0,
mDisplayFrame);
- assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
+ assertInsetBy(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0,
mParentFrame);
- assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
+ assertInsetBy(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0,
mFrame);
}
- // TODO(b/161810301): Move tests here from DisplayPolicyLayoutTests and add more tests.
+ @Test
+ public void layoutInDisplayCutoutModeDefault() {
+ addDisplayCutout();
+ mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
+ mAttrs.setFitInsetsTypes(0);
+ computeFrames();
- private void computeWindowFrames() {
- mWindowLayout.computeWindowFrames(mAttrs, mState, mDisplayCutoutSafe, mWindowBounds,
- mWindowingMode, mRequestedWidth, mRequestedHeight, mRequestedVisibilities,
- mAttachedWindowFrame, mCompatScale, mDisplayFrame, mParentFrame, mFrame);
+ assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+ mDisplayFrame);
+ assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+ mParentFrame);
+ assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+ mFrame);
}
- private void assertRect(int left, int top, int right, int bottom, Rect actual) {
- assertEquals(new Rect(left, top, right, bottom), actual);
+ @Test
+ public void layoutInDisplayCutoutModeDefaultWithLayoutInScreenAndLayoutInsetDecor() {
+ addDisplayCutout();
+ mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
+ mAttrs.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+ mAttrs.setFitInsetsTypes(0);
+ computeFrames();
+
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mDisplayFrame);
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mParentFrame);
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mFrame);
+ }
+
+ @Test
+ public void layoutInDisplayCutoutModeDefaultWithInvisibleSystemBars() {
+ addDisplayCutout();
+ mState.getSource(ITYPE_STATUS_BAR).setVisible(false);
+ mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false);
+ mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
+ mAttrs.setFitInsetsTypes(0);
+ computeFrames();
+
+ assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+ mDisplayFrame);
+ assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+ mParentFrame);
+ assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+ mFrame);
+ }
+
+ @Test
+ public void layoutInDisplayCutoutModeShortEdges() {
+ addDisplayCutout();
+ mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ mAttrs.setFitInsetsTypes(0);
+ computeFrames();
+
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mDisplayFrame);
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mParentFrame);
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mFrame);
+ }
+
+ @Test
+ public void layoutInDisplayCutoutModeNever() {
+ addDisplayCutout();
+ mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
+ mAttrs.setFitInsetsTypes(0);
+ computeFrames();
+
+ assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+ mDisplayFrame);
+ assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+ mParentFrame);
+ assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
+ mFrame);
+ }
+
+ @Test
+ public void layoutInDisplayCutoutModeAlways() {
+ addDisplayCutout();
+ mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ mAttrs.setFitInsetsTypes(0);
+ computeFrames();
+
+ assertInsetByTopBottom(0, 0, mDisplayFrame);
+ assertInsetByTopBottom(0, 0, mParentFrame);
+ assertInsetByTopBottom(0, 0, mFrame);
}
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 4220fd7..2fb67d7 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -175,10 +175,7 @@
// Delay for debouncing USB disconnects.
// We often get rapid connect/disconnect events when enabling USB functions,
// which need debouncing.
- private static final int DEVICE_STATE_UPDATE_DELAY = 3000;
-
- // Delay for debouncing USB disconnects on Type-C ports in host mode
- private static final int HOST_STATE_UPDATE_DELAY = 1000;
+ private static final int UPDATE_DELAY = 1000;
// Timeout for entering USB request mode.
// Request is cancelled if host does not configure device within 10 seconds.
@@ -648,7 +645,7 @@
msg.arg1 = connected;
msg.arg2 = configured;
// debounce disconnects to avoid problems bringing up USB tethering
- sendMessageDelayed(msg, (connected == 0) ? DEVICE_STATE_UPDATE_DELAY : 0);
+ sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
}
public void updateHostState(UsbPort port, UsbPortStatus status) {
@@ -663,7 +660,7 @@
removeMessages(MSG_UPDATE_PORT_STATE);
Message msg = obtainMessage(MSG_UPDATE_PORT_STATE, args);
// debounce rapid transitions of connect/disconnect on type-c ports
- sendMessageDelayed(msg, HOST_STATE_UPDATE_DELAY);
+ sendMessageDelayed(msg, UPDATE_DELAY);
}
private void setAdbEnabled(boolean enable) {
diff --git a/telephony/common/com/google/android/mms/util/SqliteWrapper.java b/telephony/common/com/google/android/mms/util/SqliteWrapper.java
index e2d62f8..6d9b3210 100644
--- a/telephony/common/com/google/android/mms/util/SqliteWrapper.java
+++ b/telephony/common/com/google/android/mms/util/SqliteWrapper.java
@@ -17,7 +17,6 @@
package com.google.android.mms.util;
-import android.app.ActivityManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.ContentValues;
@@ -25,49 +24,15 @@
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
-import android.os.Build;
import android.util.Log;
-import android.widget.Toast;
public final class SqliteWrapper {
private static final String TAG = "SqliteWrapper";
- private static final String SQLITE_EXCEPTION_DETAIL_MESSAGE
- = "unable to open database file";
private SqliteWrapper() {
// Forbidden being instantiated.
}
- // FIXME: It looks like outInfo.lowMemory does not work well as we expected.
- // after run command: adb shell fillup -p 100, outInfo.lowMemory is still false.
- private static boolean isLowMemory(Context context) {
- if (null == context) {
- return false;
- }
-
- ActivityManager am = (ActivityManager)
- context.getSystemService(Context.ACTIVITY_SERVICE);
- ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo();
- am.getMemoryInfo(outInfo);
-
- return outInfo.lowMemory;
- }
-
- // FIXME: need to optimize this method.
- private static boolean isLowMemory(SQLiteException e) {
- return e.getMessage().equals(SQLITE_EXCEPTION_DETAIL_MESSAGE);
- }
-
- @UnsupportedAppUsage
- public static void checkSQLiteException(Context context, SQLiteException e) {
- if (isLowMemory(e)) {
- Toast.makeText(context, com.android.internal.R.string.low_memory,
- Toast.LENGTH_SHORT).show();
- } else {
- throw e;
- }
- }
-
@UnsupportedAppUsage
public static Cursor query(Context context, ContentResolver resolver, Uri uri,
String[] projection, String selection, String[] selectionArgs, String sortOrder) {
@@ -75,21 +40,10 @@
return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
} catch (SQLiteException e) {
Log.e(TAG, "Catch a SQLiteException when query: ", e);
- checkSQLiteException(context, e);
return null;
}
}
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static boolean requery(Context context, Cursor cursor) {
- try {
- return cursor.requery();
- } catch (SQLiteException e) {
- Log.e(TAG, "Catch a SQLiteException when requery: ", e);
- checkSQLiteException(context, e);
- return false;
- }
- }
@UnsupportedAppUsage
public static int update(Context context, ContentResolver resolver, Uri uri,
ContentValues values, String where, String[] selectionArgs) {
@@ -97,7 +51,6 @@
return resolver.update(uri, values, where, selectionArgs);
} catch (SQLiteException e) {
Log.e(TAG, "Catch a SQLiteException when update: ", e);
- checkSQLiteException(context, e);
return -1;
}
}
@@ -109,7 +62,6 @@
return resolver.delete(uri, where, selectionArgs);
} catch (SQLiteException e) {
Log.e(TAG, "Catch a SQLiteException when delete: ", e);
- checkSQLiteException(context, e);
return -1;
}
}
@@ -121,7 +73,6 @@
return resolver.insert(uri, values);
} catch (SQLiteException e) {
Log.e(TAG, "Catch a SQLiteException when insert: ", e);
- checkSQLiteException(context, e);
return null;
}
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 3f6d913..82113f2 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4181,6 +4181,56 @@
"gba_ua_tls_cipher_suite_int";
/**
+ * The data stall recovery timers array in milliseconds, each element is the delay before
+ * performining next recovery action.
+ *
+ * The default value of timers array are: [180000ms, 180000ms, 180000ms] (3 minutes)
+ * Array[0]: It's the timer between RECOVERY_ACTION GET_DATA_CALL_LIST and CLEANUP, if data
+ * stall symptom still occurred, it will perform next recovery action after 180000ms.
+ * Array[1]: It's the timer between RECOVERY_ACTION CLEANUP and RADIO_RESTART, if data stall
+ * symptom still occurred, it will perform next recovery action after 180000ms.
+ * Array[2]: It's the timer between RECOVERY_ACTION RADIO_RESTART and RESET_MODEM, if data stall
+ * symptom still occurred, it will perform next recovery action after 180000ms.
+ *
+ * See the {@code RECOVERY_ACTION_*} constants in
+ * {@link com.android.internal.telephony.data.DataStallRecoveryManager}
+ * @hide
+ */
+ public static final String KEY_DATA_STALL_RECOVERY_TIMERS_LONG_ARRAY =
+ "data_stall_recovery_timers_long_array";
+
+ /**
+ * The data stall recovery action boolean array, we use this array to determine if the
+ * data stall recovery action needs to be skipped.
+ *
+ * For example, if the carrier use the same APN for both of IA and default type,
+ * the data call will not disconnect in modem side (so the RECOVERY_ACTION_CLEANUP
+ * did not effect). In this case, we can config the boolean variable of action
+ * RECOVERY_ACTION_CLEANUP to true, then it can be ignored to speed up the recovery
+ * action procedure.
+ *
+ * The default value of boolean array are: [false, false, false, false]
+ * Array[0]: When performing the recovery action, we can use this boolean value to determine
+ * if we need to perform RECOVERY_ACTION_GET_DATA_CALL_LIST.
+ * Array[1]: If data stall symptom still occurred, we can use this boolean value to determine
+ * if we need to perform RECOVERY_ACTION_CLEANUP. For example, if the carrier use the same APN
+ * for both of IA and default type, the data call will not disconnect in modem side
+ * (so the RECOVERY_ACTION_CLEANUP did not effect). In this case, we can config the boolean
+ * variable of action RECOVERY_ACTION_CLEANUP to true, then it can be ignored to speed up the
+ * recovery action procedure.
+ * Array[2]: If data stall symptom still occurred, we can use this boolean value to determine
+ * if we need to perform RECOVERY_ACTION_RADIO_RESTART.
+ * Array[3]: If data stall symptom still occurred, we can use this boolean value to determine
+ * if we need to perform RECOVERY_ACTION_MODEM_RESET.
+ *
+ * See the {@code RECOVERY_ACTION_*} constants in
+ * {@link com.android.internal.telephony.data.DataStallRecoveryManager}
+ * @hide
+ */
+ public static final String KEY_DATA_STALL_RECOVERY_SHOULD_SKIP_BOOL_ARRAY =
+ "data_stall_recovery_should_skip_bool_array";
+
+ /**
* Configs used by ImsServiceEntitlement.
*/
public static final class ImsServiceEntitlement {
@@ -5230,7 +5280,7 @@
"telephony_network_capability_priorities_string_array";
/**
- * Defines the rules for data retry.
+ * Defines the rules for data setup retry.
*
* The syntax of the retry rule:
* 1. Retry based on {@link NetworkCapabilities}. Note that only APN-type network capabilities
@@ -5262,8 +5312,34 @@
* // TODO: remove KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS
* @hide
*/
- public static final String KEY_TELEPHONY_DATA_RETRY_RULES_STRING_ARRAY =
- "telephony_data_retry_rules_string_array";
+ public static final String KEY_TELEPHONY_DATA_SETUP_RETRY_RULES_STRING_ARRAY =
+ "telephony_data_setup_retry_rules_string_array";
+
+ /**
+ * Defines the rules for data handover retry.
+ *
+ * The syntax of the retry rule:
+ * 1. Retry when handover fails.
+ * "retry_interval=[n1|n2|n3|...], [maximum_retries=n]"
+ *
+ * For example,
+ * "retry_interval=1000|3000|5000, maximum_retries=10" means handover retry will happen in 1s,
+ * 3s, 5s, 5s, 5s....up to 10 times.
+ *
+ * 2. Retry when handover fails with certain fail causes.
+ * "retry_interval=[n1|n2|n3|...], fail_causes=[cause1|cause2|cause3|...], [maximum_retries=n]
+ *
+ * For example,
+ * "retry_interval=1000, maximum_retries=3, fail_causes=5" means handover retry every 1 second
+ * for up to 3 times when handover fails with the cause 5.
+ *
+ * "maximum_retries=0, fail_causes=6|10|67" means handover retry should not happen for those
+ * causes.
+ *
+ * @hide
+ */
+ public static final String KEY_TELEPHONY_DATA_HANDOVER_RETRY_RULES_STRING_ARRAY =
+ "telephony_data_handover_retry_rules_string_array";
/**
* The patterns of missed incoming call sms. This is the regular expression used for
@@ -5624,7 +5700,7 @@
"others:max_retries=3, 5000, 5000, 5000"});
sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, 20000);
sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 3000);
- sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG, 10000);
+ sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG, 3000);
sDefaults.putInt(KEY_CARRIER_DATA_CALL_RETRY_NETWORK_REQUESTED_MAX_COUNT_INT, 3);
sDefaults.putString(KEY_CARRIER_ERI_FILE_NAME_STRING, "eri.xml");
sDefaults.putInt(KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT, 7200);
@@ -6108,7 +6184,7 @@
"ims:40", "dun:30", "enterprise:20", "internet:20"
});
sDefaults.putStringArray(
- KEY_TELEPHONY_DATA_RETRY_RULES_STRING_ARRAY, new String[] {
+ KEY_TELEPHONY_DATA_SETUP_RETRY_RULES_STRING_ARRAY, new String[] {
"capabilities=eims, retry_interval=1000, maximum_retries=20",
"fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2253|"
+ "2254, maximum_retries=0", // No retry for those causes
@@ -6117,6 +6193,10 @@
+ "5000|10000|15000|20000|40000|60000|120000|240000|"
+ "600000|1200000|1800000, maximum_retries=20"
});
+ sDefaults.putStringArray(
+ KEY_TELEPHONY_DATA_HANDOVER_RETRY_RULES_STRING_ARRAY, new String[] {
+ "retry_interval=1000|2000|4000|8000|16000, maximum_retries=5"
+ });
sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]);
sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false);
sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, "");
@@ -6142,6 +6222,11 @@
+ "target=GERAN|UTRAN|EUTRAN|NGRAN|IWLAN, type=allowed"});
sDefaults.putInt(KEY_CELLULAR_USAGE_SETTING_INT,
SubscriptionManager.USAGE_SETTING_UNKNOWN);
+ // Default data stall recovery configurations.
+ sDefaults.putLongArray(KEY_DATA_STALL_RECOVERY_TIMERS_LONG_ARRAY,
+ new long[] {180000, 180000, 180000});
+ sDefaults.putBooleanArray(KEY_DATA_STALL_RECOVERY_SHOULD_SKIP_BOOL_ARRAY,
+ new boolean[] {false, false, false, false});
}
/**
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index e8633dd..947dc01 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -600,7 +600,7 @@
/** @hide */
public static int convertRssnrUnitFromTenDbToDB(int rssnr) {
- return rssnr / 10;
+ return (int) Math.floor((float) rssnr / 10);
}
/** @hide */
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d835ea4..f5505e6 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -6145,6 +6145,7 @@
DATA_CONNECTED,
DATA_SUSPENDED,
DATA_DISCONNECTING,
+ DATA_HANDOVER_IN_PROGRESS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface DataState{}
@@ -6169,6 +6170,12 @@
public static final int DATA_DISCONNECTING = 4;
/**
+ * Data connection state: Handover in progress. The connection is being transited from cellular
+ * network to IWLAN, or from IWLAN to cellular network.
+ */
+ public static final int DATA_HANDOVER_IN_PROGRESS = 5;
+
+ /**
* Used for checking if the SDK version for {@link TelephonyManager#getDataState} is above Q.
*/
@ChangeId
@@ -6184,6 +6191,7 @@
* @see #DATA_CONNECTED
* @see #DATA_SUSPENDED
* @see #DATA_DISCONNECTING
+ * @see #DATA_HANDOVER_IN_PROGRESS
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
public int getDataState() {
@@ -13005,6 +13013,25 @@
@Retention(RetentionPolicy.SOURCE)
public @interface DataEnabledReason{}
+ /** @hide */
+ @IntDef({
+ DATA_ENABLED_REASON_UNKNOWN,
+ DATA_ENABLED_REASON_USER,
+ DATA_ENABLED_REASON_POLICY,
+ DATA_ENABLED_REASON_CARRIER,
+ DATA_ENABLED_REASON_THERMAL,
+ DATA_ENABLED_REASON_OVERRIDE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DataEnabledChangedReason{}
+
+ /**
+ * To indicate that data was enabled or disabled due to an unknown reason.
+ * Note that this is not a valid reason for {@link #setDataEnabledForReason(int, boolean)} and
+ * is only used to indicate that data enabled was changed.
+ */
+ public static final int DATA_ENABLED_REASON_UNKNOWN = -1;
+
/**
* To indicate that user enabled or disabled data.
*/
@@ -13032,6 +13059,13 @@
public static final int DATA_ENABLED_REASON_THERMAL = 3;
/**
+ * To indicate data was enabled or disabled due to {@link MobileDataPolicy} overrides.
+ * Note that this is not a valid reason for {@link #setDataEnabledForReason(int, boolean)} and
+ * is only used to indicate that data enabled was changed due to an override.
+ */
+ public static final int DATA_ENABLED_REASON_OVERRIDE = 4;
+
+ /**
* Control of data connection and provide the reason triggering the data connection control.
* This can be called for following reasons
* <ol>
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 9ed230a..4ff59b5 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -521,11 +521,11 @@
private final boolean mAlwaysOn;
/**
- * Returns the MTU size of the IPv4 mobile interface to which the APN connected. Note this value
- * is used only if MTU size is not provided in {@link DataCallResponse}.
+ * Returns the default MTU (Maximum Transmission Unit) size in bytes of the IPv4 routes brought
+ * up by this APN setting. Note this value will only be used when MTU size is not provided
+ * in {@link DataCallResponse#getMtuV4()} during network bring up.
*
- * @return the MTU size of the APN
- * @hide
+ * @return the MTU size in bytes of the route.
*/
public int getMtuV4() {
return mMtuV4;
@@ -533,10 +533,10 @@
/**
* Returns the MTU size of the IPv6 mobile interface to which the APN connected. Note this value
- * is used only if MTU size is not provided in {@link DataCallResponse}.
+ * will only be used when MTU size is not provided in {@link DataCallResponse#getMtuV6()}
+ * during network bring up.
*
- * @return the MTU size of the APN
- * @hide
+ * @return the MTU size in bytes of the route.
*/
public int getMtuV6() {
return mMtuV6;
@@ -1753,25 +1753,25 @@
}
/**
- * Set the MTU size of the IPv4 mobile interface to which the APN connected. Note this value
- * is used only if MTU size is not provided in {@link DataCallResponse}.
+ * Set the default MTU (Maximum Transmission Unit) size in bytes of the IPv4 routes brought
+ * up by this APN setting. Note this value will only be used when MTU size is not provided
+ * in {@link DataCallResponse#getMtuV4()} during network bring up.
*
- * @param mtuV4 the MTU size to set for the APN
- * @hide
+ * @param mtuV4 the MTU size in bytes of the route.
*/
- public Builder setMtuV4(int mtuV4) {
+ public @NonNull Builder setMtuV4(int mtuV4) {
this.mMtuV4 = mtuV4;
return this;
}
/**
- * Set the MTU size of the IPv6 mobile interface to which the APN connected. Note this value
- * is used only if MTU size is not provided in {@link DataCallResponse}.
+ * Set the default MTU (Maximum Transmission Unit) size in bytes of the IPv6 routes brought
+ * up by this APN setting. Note this value will only be used when MTU size is not provided
+ * in {@link DataCallResponse#getMtuV6()} during network bring up.
*
- * @param mtuV6 the MTU size to set for the APN
- * @hide
+ * @param mtuV6 the MTU size in bytes of the route.
*/
- public Builder setMtuV6(int mtuV6) {
+ public @NonNull Builder setMtuV6(int mtuV6) {
this.mMtuV6 = mtuV6;
return this;
}
@@ -1779,15 +1779,25 @@
/**
* Sets the profile id to which the APN saved in modem.
*
- * @param profileId the profile id to set for the APN
- * @hide
+ * @param profileId the profile id to set for the APN.
*/
- public Builder setProfileId(int profileId) {
+ public @NonNull Builder setProfileId(int profileId) {
this.mProfileId = profileId;
return this;
}
/**
+ * Set if the APN setting should be persistent/non-persistent in modem.
+ *
+ * @param isPersistent {@code true} if this APN setting should be persistent/non-persistent
+ * in modem.
+ * @return The same instance of the builder.
+ */
+ public @NonNull Builder setPersistent(boolean isPersistent) {
+ return setModemCognitive(isPersistent);
+ }
+
+ /**
* Sets if the APN setting is to be set in modem.
*
* @param modemCognitive if the APN setting is to be set in modem
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index 479f057..a166a5d 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -38,8 +38,10 @@
import java.util.Objects;
/**
- * Description of a mobile data profile used for establishing
- * data connections.
+ * Description of a mobile data profile used for establishing data networks. The data profile
+ * consist an {@link ApnSetting} which is needed for 2G/3G/4G networks bring up, and a
+ * {@link TrafficDescriptor} contains additional information that can be used for 5G standalone
+ * network bring up.
*
* @hide
*/
@@ -113,7 +115,9 @@
/**
* @return Id of the data profile.
+ * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getProfileId()} instead.
*/
+ @Deprecated
public int getProfileId() {
if (mApnSetting != null) {
return mApnSetting.getProfileId();
@@ -124,9 +128,10 @@
/**
* @return The APN (Access Point Name) to establish data connection. This is a string
* specifically defined by the carrier.
+ * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getApnName()} instead.
*/
- @NonNull
- public String getApn() {
+ @Deprecated
+ public @NonNull String getApn() {
if (mApnSetting != null) {
return TextUtils.emptyIfNull(mApnSetting.getApnName());
}
@@ -135,7 +140,9 @@
/**
* @return The connection protocol defined in 3GPP TS 27.007 section 10.1.1.
+ * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getProtocol()} instead.
*/
+ @Deprecated
public @ProtocolType int getProtocolType() {
if (mApnSetting != null) {
return mApnSetting.getProtocol();
@@ -145,7 +152,9 @@
/**
* @return The authentication protocol used for this PDP context.
+ * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getAuthType()} instead.
*/
+ @Deprecated
public @AuthType int getAuthType() {
if (mApnSetting != null) {
return mApnSetting.getAuthType();
@@ -154,10 +163,11 @@
}
/**
- * @return The username for APN. Can be null.
+ * @return The username for APN.
+ * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getUser()} instead.
*/
- @Nullable
- public String getUserName() {
+ @Deprecated
+ public @Nullable String getUserName() {
if (mApnSetting != null) {
return mApnSetting.getUser();
}
@@ -165,10 +175,11 @@
}
/**
- * @return The password for APN. Can be null.
+ * @return The password for APN.
+ * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getPassword()} instead.
*/
- @Nullable
- public String getPassword() {
+ @Deprecated
+ public @Nullable String getPassword() {
if (mApnSetting != null) {
return mApnSetting.getPassword();
}
@@ -232,7 +243,9 @@
/**
* @return The supported APN types bitmask.
+ * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getApnTypeBitmask()} instead.
*/
+ @Deprecated
public @ApnType int getSupportedApnTypesBitmask() {
if (mApnSetting != null) {
return mApnSetting.getApnTypeBitmask();
@@ -242,7 +255,9 @@
/**
* @return The connection protocol on roaming network defined in 3GPP TS 27.007 section 10.1.1.
+ * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getRoamingProtocol()} instead.
*/
+ @Deprecated
public @ProtocolType int getRoamingProtocolType() {
if (mApnSetting != null) {
return mApnSetting.getRoamingProtocol();
@@ -252,7 +267,10 @@
/**
* @return The bearer bitmask indicating the applicable networks for this data profile.
+ * @deprecated use {@link #getApnSetting()} and {@link ApnSetting#getNetworkTypeBitmask()}
+ * instead.
*/
+ @Deprecated
public @NetworkTypeBitMask int getBearerBitmask() {
if (mApnSetting != null) {
return mApnSetting.getNetworkTypeBitmask();
@@ -262,7 +280,8 @@
/**
* @return The maximum transmission unit (MTU) size in bytes.
- * @deprecated use {@link #getMtuV4} or {@link #getMtuV6} instead.
+ * @deprecated use {@link #getApnSetting()} and {@link ApnSetting#getMtuV4()}/
+ * {@link ApnSetting#getMtuV6()} instead.
*/
@Deprecated
public int getMtu() {
@@ -272,7 +291,9 @@
/**
* This replaces the deprecated method getMtu.
* @return The maximum transmission unit (MTU) size in bytes, for IPv4.
+ * @deprecated use {@link #getApnSetting()} and {@link ApnSetting#getMtuV4()} instead.
*/
+ @Deprecated
public int getMtuV4() {
if (mApnSetting != null) {
return mApnSetting.getMtuV4();
@@ -282,7 +303,9 @@
/**
* @return The maximum transmission unit (MTU) size in bytes, for IPv6.
+ * @deprecated use {@link #getApnSetting()} and {@link ApnSetting#getMtuV6()} instead.
*/
+ @Deprecated
public int getMtuV6() {
if (mApnSetting != null) {
return mApnSetting.getMtuV6();
@@ -292,7 +315,9 @@
/**
* @return {@code true} if modem must persist this data profile.
+ * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#isPersistent()} instead.
*/
+ @Deprecated
public boolean isPersistent() {
if (mApnSetting != null) {
return mApnSetting.isPersistent();
@@ -320,16 +345,16 @@
}
/**
- * @return The APN setting
- * @hide TODO: Remove before T is released.
+ * @return The APN setting {@link ApnSetting}, which is used to establish data network on
+ * 2G/3G/4G.
*/
public @Nullable ApnSetting getApnSetting() {
return mApnSetting;
}
/**
- * @return The traffic descriptor
- * @hide TODO: Remove before T is released.
+ * @return The traffic descriptor {@link TrafficDescriptor}, which can be used to establish
+ * data network on 5G.
*/
public @Nullable TrafficDescriptor getTrafficDescriptor() {
return mTrafficDescriptor;
@@ -539,7 +564,10 @@
*
* @param profileId Network domain.
* @return The same instance of the builder.
+ * @deprecated use {@link #setApnSetting(ApnSetting)} and
+ * {@link ApnSetting.Builder#setProfileId(int)} instead.
*/
+ @Deprecated
public @NonNull Builder setProfileId(int profileId) {
mProfileId = profileId;
return this;
@@ -551,7 +579,10 @@
*
* @param apn Access point name
* @return The same instance of the builder.
+ * @deprecated use {@link #setApnSetting(ApnSetting)} and
+ * {@link ApnSetting.Builder#setApnName(String)} instead.
*/
+ @Deprecated
public @NonNull Builder setApn(@NonNull String apn) {
mApn = apn;
return this;
@@ -562,7 +593,10 @@
*
* @param protocolType The connection protocol defined in 3GPP TS 27.007 section 10.1.1.
* @return The same instance of the builder.
+ * @deprecated use {@link #setApnSetting(ApnSetting)} and
+ * {@link ApnSetting.Builder#setProtocol(int)} instead.
*/
+ @Deprecated
public @NonNull Builder setProtocolType(@ProtocolType int protocolType) {
mProtocolType = protocolType;
return this;
@@ -573,7 +607,10 @@
*
* @param authType The authentication type
* @return The same instance of the builder.
+ * @deprecated use {@link #setApnSetting(ApnSetting)} and
+ * {@link ApnSetting.Builder#setAuthType(int)} instead.
*/
+ @Deprecated
public @NonNull Builder setAuthType(@AuthType int authType) {
mAuthType = authType;
return this;
@@ -584,7 +621,10 @@
*
* @param userName The user name
* @return The same instance of the builder.
+ * @deprecated use {@link #setApnSetting(ApnSetting)} and
+ * {@link ApnSetting.Builder#setUser(String)} instead.
*/
+ @Deprecated
public @NonNull Builder setUserName(@NonNull String userName) {
mUserName = userName;
return this;
@@ -595,7 +635,10 @@
*
* @param password The password
* @return The same instance of the builder.
+ * @deprecated use {@link #setApnSetting(ApnSetting)} and
+ * {@link ApnSetting.Builder#setPassword(String)} (int)} instead.
*/
+ @Deprecated
public @NonNull Builder setPassword(@NonNull String password) {
mPassword = password;
return this;
@@ -628,7 +671,10 @@
*
* @param supportedApnTypesBitmask The supported APN types bitmask.
* @return The same instance of the builder.
+ * @deprecated use {@link #setApnSetting(ApnSetting)} and
+ * {@link ApnSetting.Builder#setApnTypeBitmask(int)} instead.
*/
+ @Deprecated
public @NonNull Builder setSupportedApnTypesBitmask(@ApnType int supportedApnTypesBitmask) {
mSupportedApnTypesBitmask = supportedApnTypesBitmask;
return this;
@@ -639,7 +685,10 @@
*
* @param protocolType The connection protocol defined in 3GPP TS 27.007 section 10.1.1.
* @return The same instance of the builder.
+ * @deprecated use {@link #setApnSetting(ApnSetting)} and
+ * {@link ApnSetting.Builder#setRoamingProtocol(int)} instead.
*/
+ @Deprecated
public @NonNull Builder setRoamingProtocolType(@ProtocolType int protocolType) {
mRoamingProtocolType = protocolType;
return this;
@@ -651,7 +700,10 @@
* @param bearerBitmask The bearer bitmask indicating the applicable networks for this data
* profile.
* @return The same instance of the builder.
+ * @deprecated use {@link #setApnSetting(ApnSetting)} and
+ * {@link ApnSetting.Builder#setNetworkTypeBitmask(int)} instead.
*/
+ @Deprecated
public @NonNull Builder setBearerBitmask(@NetworkTypeBitMask int bearerBitmask) {
mBearerBitmask = bearerBitmask;
return this;
@@ -662,7 +714,9 @@
*
* @param mtu The maximum transmission unit (MTU) size in bytes.
* @return The same instance of the builder.
- * @deprecated use {@link #setApnSetting(ApnSetting)} instead.
+ * @deprecated use {@link #setApnSetting(ApnSetting)} and
+ * {@link ApnSetting.Builder#setMtuV4(int)}/{@link ApnSetting.Builder#setMtuV6(int)}
+ * instead.
*/
@Deprecated
public @NonNull Builder setMtu(int mtu) {
@@ -672,11 +726,13 @@
/**
* Set the maximum transmission unit (MTU) size in bytes, for IPv4.
- * This replaces the deprecated method setMtu.
*
* @param mtu The maximum transmission unit (MTU) size in bytes.
* @return The same instance of the builder.
+ * @deprecated Use {{@link #setApnSetting(ApnSetting)}} and
+ * {@link ApnSetting.Builder#setMtuV4(int)} instead.
*/
+ @Deprecated
public @NonNull Builder setMtuV4(int mtu) {
mMtuV4 = mtu;
return this;
@@ -687,7 +743,10 @@
*
* @param mtu The maximum transmission unit (MTU) size in bytes.
* @return The same instance of the builder.
+ * @deprecated Use {{@link #setApnSetting(ApnSetting)}} and
+ * {@link ApnSetting.Builder#setMtuV6(int)} instead.
*/
+ @Deprecated
public @NonNull Builder setMtuV6(int mtu) {
mMtuV6 = mtu;
return this;
@@ -712,19 +771,23 @@
* @param isPersistent {@code true} if this data profile was used to bring up the last
* default (i.e internet) data connection successfully.
* @return The same instance of the builder.
+ * @deprecated Use {{@link #setApnSetting(ApnSetting)}} and
+ * {@link ApnSetting.Builder#setPersistent(boolean)} instead.
*/
+ @Deprecated
public @NonNull Builder setPersistent(boolean isPersistent) {
mPersistent = isPersistent;
return this;
}
/**
- * Set APN setting.
+ * Set the APN setting. Note that if an APN setting is not set here, then either
+ * {@link #setApn(String)} or {@link #setTrafficDescriptor(TrafficDescriptor)} must be
+ * called. Otherwise {@link IllegalArgumentException} will be thrown when {@link #build()}
+ * the data profile.
*
- * @param apnSetting APN setting
- * @return The same instance of the builder
- *
- * @hide // TODO: Remove before T is released.
+ * @param apnSetting The APN setting.
+ * @return The same instance of the builder.
*/
public @NonNull Builder setApnSetting(@NonNull ApnSetting apnSetting) {
mApnSetting = apnSetting;
@@ -732,12 +795,13 @@
}
/**
- * Set traffic descriptor.
+ * Set the traffic descriptor. Note that if a traffic descriptor is not set here, then
+ * either {@link #setApnSetting(ApnSetting)} or {@link #setApn(String)} must be called.
+ * Otherwise {@link IllegalArgumentException} will be thrown when {@link #build()} the data
+ * profile.
*
- * @param trafficDescriptor Traffic descriptor
- * @return The same instance of the builder
- *
- * @hide // TODO: Remove before T is released.
+ * @param trafficDescriptor The traffic descriptor.
+ * @return The same instance of the builder.
*/
public @NonNull Builder setTrafficDescriptor(@NonNull TrafficDescriptor trafficDescriptor) {
mTrafficDescriptor = trafficDescriptor;
@@ -745,9 +809,9 @@
}
/**
- * Build the DataProfile object
+ * Build the DataProfile object.
*
- * @return The data profile object
+ * @return The data profile object.
*/
public @NonNull DataProfile build() {
if (mApnSetting == null && mApn != null) {
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index 4efd159..f614988 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -262,48 +262,12 @@
* @param refresh Whether sending the REFRESH command to modem.
* @param executor The executor through which the callback should be invoked.
* @param callback The callback to get the result code.
- * @deprecated instead use {@link #disableProfile(String, String, int, boolean, Executor,
- * ResultCallback)}
*/
- @Deprecated
public void disableProfile(String cardId, String iccid, boolean refresh,
@CallbackExecutor Executor executor, ResultCallback<Void> callback) {
try {
getIEuiccCardController().disableProfile(mContext.getOpPackageName(), cardId, iccid,
- TelephonyManager.DEFAULT_PORT_INDEX, refresh,
- new IDisableProfileCallback.Stub() {
- @Override
- public void onComplete(int resultCode) {
- final long token = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> callback.onComplete(resultCode, null));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- });
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling disableProfile", e);
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Disables the profile of the given ICCID.
- *
- * @param cardId The Id of the eUICC.
- * @param iccid The iccid of the profile.
- * @param portIndex the Port index is the unique index referring to a port.
- * @param refresh Whether sending the REFRESH command to modem.
- * @param executor The executor through which the callback should be invoked.
- * @param callback The callback to get the result code.
- */
- public void disableProfile(@Nullable String cardId, @Nullable String iccid, int portIndex,
- boolean refresh, @NonNull @CallbackExecutor Executor executor,
- @NonNull ResultCallback<Void> callback) {
- try {
- getIEuiccCardController().disableProfile(mContext.getOpPackageName(), cardId, iccid,
- portIndex, refresh, new IDisableProfileCallback.Stub() {
+ refresh, new IDisableProfileCallback.Stub() {
@Override
public void onComplete(int resultCode) {
final long token = Binder.clearCallingIdentity();
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
index 1734c98..928223a 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
@@ -47,8 +47,8 @@
in IGetProfileCallback callback);
oneway void getEnabledProfile(String callingPackage, String cardId, int portIndex,
in IGetProfileCallback callback);
- oneway void disableProfile(String callingPackage, String cardId, String iccid, int portIndex,
- boolean refresh, in IDisableProfileCallback callback);
+ oneway void disableProfile(String callingPackage, String cardId, String iccid, boolean refresh,
+ in IDisableProfileCallback callback);
oneway void switchToProfile(String callingPackage, String cardId, String iccid, int portIndex,
boolean refresh, in ISwitchToProfileCallback callback);
oneway void setNickname(String callingPackage, String cardId, String iccid, String nickname,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index 7076a07..8de38f6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -83,7 +83,7 @@
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
/** {@inheritDoc} */
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index b5d01ef..22acc03 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -82,7 +82,7 @@
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
/** {@inheritDoc} */
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
index 59e8dc8..8fe0029 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
@@ -37,16 +37,21 @@
.launcherStrategy
) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
fun openSecondActivity(device: UiDevice, wmHelper: WindowManagerStateHelper) {
- val button = device.wait(
- Until.findObject(By.res(getPackage(), "launch_second_activity")),
- FIND_TIMEOUT)
+ val launchActivityButton = By.res(getPackage(), LAUNCH_SECOND_ACTIVITY)
+ val button = device.wait(Until.findObject(launchActivityButton), FIND_TIMEOUT)
require(button != null) {
"Button not found, this usually happens when the device " +
"was left in an unknown state (e.g. in split screen)"
}
button.click()
+
+ device.wait(Until.gone(launchActivityButton), FIND_TIMEOUT)
wmHelper.waitForAppTransitionIdle()
wmHelper.waitForFullScreenApp(component)
}
+
+ companion object {
+ private const val LAUNCH_SECOND_ACTIVITY = "launch_second_activity"
+ }
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index f12e4ae..56879c9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -20,6 +20,7 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -154,7 +155,7 @@
@Test
fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index 0529fdd..c28466c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -20,6 +20,7 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -156,7 +157,7 @@
@Test
fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index d975cf4..c7f1b99 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -132,7 +132,7 @@
testSpec.navBarLayerRotatesAndScales()
}
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index facca94..46ed0ad 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -20,6 +20,7 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -149,7 +150,7 @@
@Test
fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 3ef4e4c..ebe4be2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -20,6 +20,7 @@
import android.platform.test.annotations.Presubmit
import android.view.Surface
import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -127,7 +128,7 @@
@Test
fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index 84e78ec..f6e5adc 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -217,7 +217,7 @@
@Test
fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
index a7a9fe2..19e2c92 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
@@ -86,8 +86,8 @@
// [Step1]: Swipe right from imeTestApp to testApp task
createTag(TAG_IME_VISIBLE)
val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
- device.swipe(0, displayBounds.bounds.height(),
- displayBounds.bounds.width(), displayBounds.bounds.height(), 50)
+ device.swipe(0, displayBounds.bounds.height,
+ displayBounds.bounds.width, displayBounds.bounds.height, 50)
wmHelper.waitForFullScreenApp(testApp.component)
wmHelper.waitForAppTransitionIdle()
@@ -96,8 +96,8 @@
transitions {
// [Step2]: Swipe left to back to imeTestApp task
val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
- device.swipe(displayBounds.bounds.width(), displayBounds.bounds.height(),
- 0, displayBounds.bounds.height(), 50)
+ device.swipe(displayBounds.bounds.width, displayBounds.bounds.height,
+ 0, displayBounds.bounds.height, 50)
wmHelper.waitForFullScreenApp(imeTestApp.component)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 32feccd..eef7b57 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -81,7 +81,7 @@
}
/** {@inheritDoc} */
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 53b5354..aac4812 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -98,7 +98,7 @@
}
/** {@inheritDoc} */
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index 3914ef6..6e5c600 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -188,7 +188,7 @@
}
/** {@inheritDoc} */
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
fun statusBarLayerPositionAtEnd() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 619f5d2..dfa8f8e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -85,7 +85,7 @@
}
/** {@inheritDoc} */
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
index 769cb1a..882e128 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -148,22 +148,28 @@
val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
testSpec.assertLayers {
- this.coversExactly(displayBounds, LAUNCH_NEW_TASK_ACTIVITY)
+ this.invoke("LAUNCH_NEW_TASK_ACTIVITY coversExactly displayBounds") {
+ it.visibleRegion(LAUNCH_NEW_TASK_ACTIVITY).coversExactly(displayBounds)
+ }
.isInvisible(bgColorLayer)
.then()
// Transitioning
.isVisible(bgColorLayer)
.then()
// Fully transitioned to simple SIMPLE_ACTIVITY
- .coversExactly(displayBounds, SIMPLE_ACTIVITY)
+ .invoke("SIMPLE_ACTIVITY coversExactly displayBounds") {
+ it.visibleRegion(SIMPLE_ACTIVITY).coversExactly(displayBounds)
+ }
.isInvisible(bgColorLayer)
.then()
// Transitioning back
.isVisible(bgColorLayer)
.then()
// Fully transitioned back to LAUNCH_NEW_TASK_ACTIVITY
+ .invoke("LAUNCH_NEW_TASK_ACTIVITY coversExactly displayBounds") {
+ it.visibleRegion(LAUNCH_NEW_TASK_ACTIVITY).coversExactly(displayBounds)
+ }
.isInvisible(bgColorLayer)
- .coversExactly(displayBounds, LAUNCH_NEW_TASK_ACTIVITY)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
index 8f8951b..01fce05 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -31,7 +31,6 @@
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
-import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
@@ -39,6 +38,7 @@
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.common.Rect
import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Test
@@ -68,8 +68,6 @@
private val testApp1 = SimpleAppHelper(instrumentation)
private val testApp2 = NonResizeableAppHelper(instrumentation)
- private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
-
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
@@ -81,15 +79,20 @@
testApp2.launchViaIntent(wmHelper)
wmHelper.waitForFullScreenApp(testApp2.component)
+ startDisplayBounds = wmHelper.currentState.layerState
+ .displays.firstOrNull { !it.isVirtual }
+ ?.layerStackSpace
+ ?: error("Display not found")
+
// Swipe right from bottom to quick switch back
// NOTE: We don't perform an edge-to-edge swipe but instead only swipe in the middle
// as to not accidentally trigger a swipe back or forward action which would result
// in the same behavior but not testing quick swap.
device.swipe(
- startDisplayBounds.bounds.right / 3,
- startDisplayBounds.bounds.bottom,
- 2 * startDisplayBounds.bounds.right / 3,
- startDisplayBounds.bounds.bottom,
+ startDisplayBounds.right / 3,
+ startDisplayBounds.bottom,
+ 2 * startDisplayBounds.right / 3,
+ startDisplayBounds.bottom,
if (testSpec.isLandscapeOrSeascapeAtStart) 75 else 30
)
@@ -103,10 +106,10 @@
// as to not accidentally trigger a swipe back or forward action which would result
// in the same behavior but not testing quick swap.
device.swipe(
- 2 * startDisplayBounds.bounds.right / 3,
- startDisplayBounds.bounds.bottom,
- startDisplayBounds.bounds.right / 3,
- startDisplayBounds.bounds.bottom,
+ 2 * startDisplayBounds.right / 3,
+ startDisplayBounds.bottom,
+ startDisplayBounds.right / 3,
+ startDisplayBounds.bottom,
if (testSpec.isLandscapeOrSeascapeAtStart) 75 else 30
)
@@ -133,7 +136,8 @@
// This test doesn't work in shell transitions because of b/209936664
Assume.assumeFalse(isShellTransitionsEnabled)
testSpec.assertWmStart {
- this.frameRegion(testApp1.component).coversExactly(startDisplayBounds)
+ this.frameRegion(testApp1.component, FlickerComponentName.LETTERBOX)
+ .coversExactly(startDisplayBounds)
}
}
@@ -188,7 +192,8 @@
// This test doesn't work in shell transitions because of b/209936664
Assume.assumeFalse(isShellTransitionsEnabled)
testSpec.assertLayersEnd {
- this.visibleRegion(testApp2.component).coversExactly(startDisplayBounds)
+ this.visibleRegion(testApp2.component, FlickerComponentName.LETTERBOX)
+ .coversExactly(startDisplayBounds)
}
}
@@ -372,6 +377,8 @@
}
companion object {
+ private var startDisplayBounds = Rect.EMPTY
+
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index c18798f..0879b98 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -165,7 +165,7 @@
/**
* Checks the position of the status bar at the start and end of the transition
*/
- @Presubmit
+ @FlakyTest(bugId = 206753786)
@Test
fun statusBarLayerRotatesScales() {
// This test doesn't work in shell transitions because of b/206753786
diff --git a/tests/HwAccelerationTest/Android.bp b/tests/HwAccelerationTest/Android.bp
index e618ed1..51848f2 100644
--- a/tests/HwAccelerationTest/Android.bp
+++ b/tests/HwAccelerationTest/Android.bp
@@ -32,6 +32,10 @@
"**/*.java",
"**/*.kt",
],
+ static_libs: [
+ "androidx.cardview_cardview",
+ ],
+
platform_apis: true,
certificate: "platform",
}
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 22fe424..b0ccbd1 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -789,6 +789,15 @@
</intent-filter>
</activity>
+ <activity android:name="RenderEffectViewActivity"
+ android:label="RenderEffect/View"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
<activity android:name="StretchShaderActivity"
android:label="RenderEffect/Stretch"
android:exported="true">
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/scratches.png b/tests/HwAccelerationTest/res/drawable-nodpi/scratches.png
new file mode 100644
index 0000000..cc8adf1
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable-nodpi/scratches.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/weather_2.jpg b/tests/HwAccelerationTest/res/drawable-nodpi/weather_2.jpg
new file mode 100644
index 0000000..b5aff10
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable-nodpi/weather_2.jpg
Binary files differ
diff --git a/tests/HwAccelerationTest/res/layout/view_runtime_shader.xml b/tests/HwAccelerationTest/res/layout/view_runtime_shader.xml
new file mode 100644
index 0000000..b91377d
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/view_runtime_shader.xml
@@ -0,0 +1,205 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <LinearLayout
+ android:id="@+id/TopLayout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="8dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="16dp"
+ android:text="Sample Card #1"/>
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:layout_marginBottom="16dp"
+ android:clickable="true"
+ android:focusable="true"
+ android:minHeight="148dp">
+
+ <LinearLayout
+ 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:padding="16dp"
+ android:paddingBottom="8dp">
+
+ <ImageView
+ android:layout_width="50dp"
+ android:layout_height="50dp"
+ android:layout_marginEnd="8dp"
+ android:layout_marginRight="8dp"
+ android:contentDescription="Logo"
+ android:src="@drawable/icon"/>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.0"
+ android:layout_marginStart="8dp"
+ android:layout_marginLeft="8dp"
+ android:orientation="vertical">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textStyle="bold"
+ android:text="Image Transition"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:text="Touch the image to trigger the animation"/>
+ </LinearLayout>
+ </LinearLayout>
+
+ <com.android.test.hwui.BitmapTransitionView
+ android:layout_width="match_parent"
+ android:layout_height="194dp"
+ android:padding="8dp"/>
+
+ </LinearLayout>
+
+ </androidx.cardview.widget.CardView>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="16dp"
+ android:text="Sample Card #2"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/CardView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"
+ android:layout_marginBottom="16dp"
+ android:clickable="true"
+ android:focusable="true"
+ android:minHeight="148dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="16dp"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="16dp"
+ android:paddingBottom="8dp">
+
+ <ImageView
+ android:layout_width="50dp"
+ android:layout_height="50dp"
+ android:layout_marginEnd="8dp"
+ android:layout_marginRight="8dp"
+ android:contentDescription="Logo"
+ android:src="@drawable/icon"/>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.0"
+ android:layout_marginStart="8dp"
+ android:layout_marginLeft="8dp"
+ android:orientation="vertical">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textStyle="bold"
+ android:text="View Group Manipulation"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:text="Tap the card to trigger the animation"/>
+ </LinearLayout>
+ </LinearLayout>
+
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="194dp"
+ android:background="@android:color/transparent"
+ android:src="@drawable/weather_2"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="16dp"
+ android:paddingBottom="8dp"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <RatingBar
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="Card Rating"
+ android:isIndicator="true"
+ android:numStars="5"
+ android:rating="4.5"
+
+ android:stepSize="0.5"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="Category 4.5 Storm"/>
+ </LinearLayout>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:maxLines="3"
+ android:textIsSelectable="true"
+ android:text="Lorem ipsum dolor sit amet, nec no nominavi scaevola. Per et
+ sint sapientem, nobis perpetua salutandi mei te. Quo tamquam probatus
+ reprehendunt in. Eos esse purto eruditi ea. Enim tation persius ut sea,
+ eos ad consul populo. Ne eum solet altera. Cibo eligendi et est, electram
+ theophrastus te vel eu."/>
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ </androidx.cardview.widget.CardView>
+ </LinearLayout>
+</ScrollView>
diff --git a/tests/HwAccelerationTest/res/values/styles.xml b/tests/HwAccelerationTest/res/values/styles.xml
index fa5437f..55f4dd69 100644
--- a/tests/HwAccelerationTest/res/values/styles.xml
+++ b/tests/HwAccelerationTest/res/values/styles.xml
@@ -41,4 +41,5 @@
<item name="android:spotShadowAlpha">1</item>
-->
</style>
+
</resources>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt
new file mode 100644
index 0000000..d3ad9e8
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui
+
+import android.animation.ValueAnimator
+import android.content.Context
+import android.graphics.BitmapShader
+import android.graphics.Canvas
+import android.graphics.ImageDecoder
+import android.graphics.Matrix
+import android.graphics.Paint
+import android.graphics.RuntimeShader
+import android.graphics.Shader
+import android.util.AttributeSet
+import android.view.View
+
+class BitmapTransitionView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0
+) : View(context, attrs, defStyleAttr) {
+
+ private val mPaint = Paint()
+ private val mImageA = ImageDecoder.decodeBitmap(
+ ImageDecoder.createSource(context.resources, R.drawable.large_photo))
+ private val mImageB = ImageDecoder.decodeBitmap(
+ ImageDecoder.createSource(context.resources, R.drawable.very_large_photo))
+ private val mShaderA = BitmapShader(mImageA, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
+ private val mShaderB = BitmapShader(mImageB, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
+ private val mShader = RuntimeShader(AGSL, false)
+ private var mCurrentProgress = -1f
+ private var mForwardProgress = true
+ private var mCurrentAnimator = ValueAnimator.ofFloat(-1f, 1f)
+
+ init {
+ isClickable = true
+
+ mCurrentAnimator.duration = 1500
+ mCurrentAnimator.addUpdateListener { animation ->
+ mCurrentProgress = animation.animatedValue as Float
+ postInvalidate()
+ }
+ }
+
+ override fun performClick(): Boolean {
+ if (super.performClick()) return true
+
+ if (mCurrentAnimator.isRunning) {
+ mCurrentAnimator.reverse()
+ return true
+ }
+
+ if (mForwardProgress) {
+ mCurrentAnimator.setFloatValues(-1f, 1f)
+ mForwardProgress = false
+ } else {
+ mCurrentAnimator.setFloatValues(1f, -1f)
+ mForwardProgress = true
+ }
+
+ mCurrentAnimator.start()
+ postInvalidate()
+ return true
+ }
+
+ override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) {
+ val matrixA = Matrix()
+ val matrixB = Matrix()
+
+ matrixA.postScale(width.toFloat() / mImageA.width, height.toFloat() / mImageA.height)
+ matrixB.postScale(width.toFloat() / mImageB.width, height.toFloat() / mImageB.height)
+
+ mShaderA.setLocalMatrix(matrixA)
+ mShaderB.setLocalMatrix(matrixB)
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+
+ mShader.setInputShader("imageA", mShaderA)
+ mShader.setInputShader("imageB", mShaderB)
+ mShader.setIntUniform("imageDimensions", width, height)
+ mShader.setFloatUniform("progress", mCurrentProgress)
+
+ mPaint.shader = mShader
+ canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), mPaint)
+ }
+
+ private companion object {
+ const val AGSL = """
+ uniform shader imageA;
+ uniform shader imageB;
+ uniform ivec2 imageDimensions;
+ uniform float progress;
+
+ const vec2 iSize = vec2(48.0, 48.0);
+ const float iDir = 0.5;
+ const float iRand = 0.81;
+
+ float hash12(vec2 p) {
+ vec3 p3 = fract(vec3(p.xyx) * .1031);
+ p3 += dot(p3, p3.yzx + 33.33);
+ return fract((p3.x + p3.y) * p3.z);
+ }
+
+ float ramp(float2 p) {
+ return mix(hash12(p),
+ dot(p/vec2(imageDimensions), float2(iDir, 1 - iDir)),
+ iRand);
+ }
+
+ half4 main(float2 p) {
+ float2 lowRes = p / iSize;
+ float2 cellCenter = (floor(lowRes) + 0.5) * iSize;
+ float2 posInCell = fract(lowRes) * 2 - 1;
+
+ float v = ramp(cellCenter) + progress;
+ float distToCenter = max(abs(posInCell.x), abs(posInCell.y));
+
+ return distToCenter > v ? imageA.eval(p).rgb1 : imageB.eval(p).rgb1;
+ }
+ """
+ }
+}
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt b/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt
new file mode 100644
index 0000000..06280d2
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui
+
+import android.animation.ValueAnimator
+import android.app.Activity
+import android.graphics.Bitmap
+import android.graphics.BitmapShader
+import android.graphics.ImageDecoder
+import android.graphics.Matrix
+import android.graphics.Shader
+import android.graphics.RenderEffect
+import android.graphics.RuntimeShader
+import android.os.Bundle
+import android.view.View
+
+class RenderEffectViewActivity : Activity() {
+
+ private val mDropsShader = RuntimeShader(dropsAGSL, false)
+ private var mDropsAnimator = ValueAnimator.ofFloat(0f, 1f)
+ private var mStartTime = System.currentTimeMillis()
+ private lateinit var mScratchesImage: Bitmap
+ private lateinit var mScratchesShader: BitmapShader
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.view_runtime_shader)
+
+ val dropsView = findViewById<View>(R.id.CardView)!!
+ dropsView.isClickable = true
+ dropsView.setOnClickListener {
+ if (mDropsAnimator.isRunning) {
+ mDropsAnimator.cancel()
+ dropsView.setRenderEffect(null)
+ } else {
+ mDropsAnimator.start()
+ }
+ }
+
+ val imgSource = ImageDecoder.createSource(resources, R.drawable.scratches)
+ mScratchesImage = ImageDecoder.decodeBitmap(imgSource)
+ mScratchesShader = BitmapShader(mScratchesImage,
+ Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
+
+ mDropsAnimator.duration = 1000
+ mDropsAnimator.repeatCount = ValueAnimator.INFINITE
+ mDropsAnimator.addUpdateListener { _ ->
+ val viewWidth = dropsView.width.toFloat()
+ val viewHeight = dropsView.height.toFloat()
+ val scratchesMatrix = Matrix()
+ scratchesMatrix.postScale(viewWidth / mScratchesImage.width,
+ viewHeight / mScratchesImage.height)
+ mScratchesShader.setLocalMatrix(scratchesMatrix)
+
+ mDropsShader.setInputShader("scratches", mScratchesShader)
+ mDropsShader.setFloatUniform("elapsedSeconds",
+ (System.currentTimeMillis() - mStartTime) / 1000f)
+ mDropsShader.setFloatUniform("viewDimensions", viewWidth, viewHeight)
+
+ val dropsEffect = RenderEffect.createRuntimeShaderEffect(mDropsShader, "background")
+ val blurEffect = RenderEffect.createBlurEffect(10f, 10f, Shader.TileMode.CLAMP)
+
+ dropsView.setRenderEffect(RenderEffect.createChainEffect(dropsEffect, blurEffect))
+ }
+ }
+
+ private companion object {
+ const val dropsAGSL = """
+ uniform float elapsedSeconds;
+ uniform vec2 viewDimensions;
+ uniform shader background;
+ uniform shader scratches;
+
+ vec2 dropsUV(vec2 fragCoord ) {
+ vec2 uv = fragCoord.xy / viewDimensions.xy; // 0 <> 1
+ vec2 offs = vec2(0.);
+ return (offs + uv).xy;
+ }
+
+ const vec3 iFrostColorRGB = vec3(0.5, 0.5, 0.5);
+ const float iFrostColorAlpha = .3;
+
+ half4 main(float2 fragCoord) {
+ half4 bg = background.eval(dropsUV(fragCoord)*viewDimensions.xy);
+ float2 scratchCoord = fragCoord.xy / viewDimensions.xy;;
+ scratchCoord += 1.5;
+ scratchCoord = mod(scratchCoord, 1);
+ half scratch = scratches.eval(scratchCoord*viewDimensions.xy).r;
+ bg.rgb = mix(bg.rgb, iFrostColorRGB, iFrostColorAlpha);
+ bg.rgb = mix(bg.rgb, half3(1), pow(scratch,3));
+ return bg;
+ }
+ """
+ }
+}
\ No newline at end of file
diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py
index e181c62..68e213b 100755
--- a/tools/fonts/fontchain_linter.py
+++ b/tools/fonts/fontchain_linter.py
@@ -14,6 +14,7 @@
LANG_TO_SCRIPT = {
'as': 'Beng',
+ 'am': 'Latn',
'be': 'Cyrl',
'bg': 'Cyrl',
'bn': 'Beng',
@@ -27,15 +28,18 @@
'eu': 'Latn',
'fr': 'Latn',
'ga': 'Latn',
+ 'gl': 'Latn',
'gu': 'Gujr',
'hi': 'Deva',
'hr': 'Latn',
'hu': 'Latn',
'hy': 'Armn',
+ 'it': 'Latn',
'ja': 'Jpan',
'kn': 'Knda',
'ko': 'Kore',
'la': 'Latn',
+ 'lt': 'Latn',
'ml': 'Mlym',
'mn': 'Cyrl',
'mr': 'Deva',
@@ -48,6 +52,7 @@
'ta': 'Taml',
'te': 'Telu',
'tk': 'Latn',
+ 'uk': 'Latn',
}
def lang_to_script(lang_code):
diff --git a/tools/lint/README.md b/tools/lint/README.md
index df2fe2a..2b6d65b 100644
--- a/tools/lint/README.md
+++ b/tools/lint/README.md
@@ -41,6 +41,37 @@
`defaults` field, e.g. `platform_service_defaults`, you can add the `lint` property to that common
module instead of adding it in every module.
+## Create or update a baseline
+
+Baseline files can be used to silence known errors (and warnings) that are deemed to be safe. When
+there is a lint-baseline.xml file in the root folder of the java library, soong will
+automatically use it. You can override the file using lint properties too.
+
+```
+java_library {
+ lint: {
+ baseline_filename: "my-baseline.xml", // default: lint-baseline.xml;
+ }
+}
+```
+
+When using soong to create a lint report (as described above), it also creates a reference
+baseline file. This contains all lint errors and warnings that were found. So the next time
+you run lint, if you use this baseline file, there should be 0 findings.
+
+After the previous invocation, you can find the baseline here:
+
+```
+out/soong/.intermediates/frameworks/base/services/autofill/services.autofill/android_common/lint/lint-baseline.xml
+```
+
+As noted above, this baseline file contains warnings too, which might be undesirable. For example,
+CI tools might surface these warnings in code reviews. In order to create this file without
+warnings, we need to pass another flag to lint: `--nowarn`. The easiest way to do this is to
+locally change the soong code in
+[lint.go](http://cs/aosp-master/build/soong/java/lint.go;l=451;rcl=2e778d5bc4a8d1d77b4f4a3029a4a254ad57db75)
+adding `cmd.Flag("--nowarn")` and running lint again.
+
## Documentation
- [Android Lint Docs](https://googlesamples.github.io/android-custom-lint-rules/)