diff options
513 files changed, 8844 insertions, 4005 deletions
diff --git a/api/Android.bp b/api/Android.bp index 1d4698e7c512..1fdf1771bb13 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -347,3 +347,49 @@ genrule { out: ["combined-removed-dex.txt"], cmd: "$(location gen_combined_removed_dex.sh) $(location metalava) $(genDir) $(in) > $(out)", } + +genrule { + name: "services-system-server-current.txt", + srcs: [ + ":service-permission{.system-server.api.txt}", + ":non-updatable-system-server-current.txt", + ], + out: ["system-server-current.txt"], + tools: ["metalava"], + cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + dists: [ + { + targets: ["droidcore"], + dir: "api", + dest: "system-server-current.txt", + }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/system-server/api", + dest: "merge-android.txt", + }, + ], +} + +genrule { + name: "services-system-server-removed.txt", + srcs: [ + ":service-permission{.system-server.removed-api.txt}", + ":non-updatable-system-server-removed.txt", + ], + out: ["system-server-removed.txt"], + tools: ["metalava"], + cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + dists: [ + { + targets: ["droidcore"], + dir: "api", + dest: "system-server-removed.txt", + }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/system-server/api", + dest: "merge-removed.txt", + }, + ], +} diff --git a/core/api/current.txt b/core/api/current.txt index ece1ce64d928..65fbfa1ab71e 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -21241,7 +21241,7 @@ package android.media { method @NonNull public String getDiagnosticInfo(); } - public final class MediaCodec implements android.media.metrics.PlaybackComponent { + public final class MediaCodec { method public void configure(@Nullable android.media.MediaFormat, @Nullable android.view.Surface, @Nullable android.media.MediaCrypto, int); method public void configure(@Nullable android.media.MediaFormat, @Nullable android.view.Surface, int, @Nullable android.media.MediaDescrambler); method @NonNull public static android.media.MediaCodec createByCodecName(@NonNull String) throws java.io.IOException; @@ -21267,7 +21267,6 @@ package android.media { method @NonNull public android.media.MediaFormat getOutputFormat(int); method @NonNull public android.media.MediaCodec.OutputFrame getOutputFrame(int); method @Nullable public android.media.Image getOutputImage(int); - method public String getPlaybackId(); method @NonNull public android.media.MediaCodec.QueueRequest getQueueRequest(int); method @Nullable public static android.media.Image mapHardwareBuffer(@NonNull android.hardware.HardwareBuffer); method public void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException; @@ -21283,7 +21282,6 @@ package android.media { method public void setOnFrameRenderedListener(@Nullable android.media.MediaCodec.OnFrameRenderedListener, @Nullable android.os.Handler); method public void setOutputSurface(@NonNull android.view.Surface); method public void setParameters(@Nullable android.os.Bundle); - method public void setPlaybackId(@NonNull String); method public void setVideoScalingMode(int); method public void signalEndOfInputStream(); method public void start(); @@ -22120,7 +22118,7 @@ package android.media { ctor public MediaDrmResetException(String); } - public final class MediaExtractor { + public final class MediaExtractor implements android.media.metrics.PlaybackComponent { ctor public MediaExtractor(); method public boolean advance(); method protected void finalize(); @@ -22129,6 +22127,7 @@ package android.media { method public android.media.MediaExtractor.CasInfo getCasInfo(int); method public android.media.DrmInitData getDrmInitData(); method public android.os.PersistableBundle getMetrics(); + method @NonNull public String getPlaybackId(); method @Nullable public java.util.Map<java.util.UUID,byte[]> getPsshInfo(); method public boolean getSampleCryptoInfo(@NonNull android.media.MediaCodec.CryptoInfo); method public int getSampleFlags(); @@ -22150,6 +22149,7 @@ package android.media { method public void setDataSource(@NonNull java.io.FileDescriptor) throws java.io.IOException; method public void setDataSource(@NonNull java.io.FileDescriptor, long, long) throws java.io.IOException; method public void setMediaCas(@NonNull android.media.MediaCas); + method public void setPlaybackId(@NonNull String); method public void unselectTrack(int); field public static final int SAMPLE_FLAG_ENCRYPTED = 2; // 0x2 field public static final int SAMPLE_FLAG_PARTIAL_FRAME = 4; // 0x4 @@ -22283,7 +22283,6 @@ package android.media { field public static final String KEY_ROTATION = "rotation-degrees"; field public static final String KEY_SAMPLE_RATE = "sample-rate"; field public static final String KEY_SLICE_HEIGHT = "slice-height"; - field public static final String KEY_SLOW_MOTION_MARKERS = "slow-motion-markers"; field public static final String KEY_STRIDE = "stride"; field public static final String KEY_TEMPORAL_LAYERING = "ts-schema"; field public static final String KEY_TILE_HEIGHT = "tile-height"; @@ -42040,6 +42039,7 @@ package android.telephony { method public static int getDefaultSmsSubscriptionId(); method public static int getDefaultSubscriptionId(); method public static int getDefaultVoiceSubscriptionId(); + method public int getDeviceToDeviceStatusSharing(int); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions(); method public static int getSlotIndex(int); method @Nullable public int[] getSubscriptionIds(int); @@ -42052,6 +42052,7 @@ package android.telephony { method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener); method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void removeSubscriptionsFromGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDeviceToDeviceStatusSharing(int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int); method public void setSubscriptionOverrideCongested(int, boolean, long); method public void setSubscriptionOverrideCongested(int, boolean, @NonNull int[], long); @@ -42063,6 +42064,11 @@ package android.telephony { field public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED"; field public static final String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS"; field public static final String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS"; + field public static final int D2D_SHARING_ALL = 3; // 0x3 + field public static final int D2D_SHARING_ALL_CONTACTS = 1; // 0x1 + field public static final int D2D_SHARING_DISABLED = 0; // 0x0 + field public static final int D2D_SHARING_STARRED_CONTACTS = 2; // 0x2 + field public static final String D2D_STATUS_SHARING = "d2d_sharing_status"; field public static final int DATA_ROAMING_DISABLE = 0; // 0x0 field public static final int DATA_ROAMING_ENABLE = 1; // 0x1 field public static final int DEFAULT_SUBSCRIPTION_ID = 2147483647; // 0x7fffffff diff --git a/core/api/system-current.txt b/core/api/system-current.txt index b0b2c6cdf0f7..68f057873807 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -8819,6 +8819,7 @@ package android.provider { field public static final String NAMESPACE_STATSD_NATIVE_BOOT = "statsd_native_boot"; field @Deprecated public static final String NAMESPACE_STORAGE = "storage"; field public static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot"; + field public static final String NAMESPACE_SWCODEC_NATIVE = "swcodec_native"; field public static final String NAMESPACE_SYSTEMUI = "systemui"; field public static final String NAMESPACE_SYSTEM_TIME = "system_time"; field public static final String NAMESPACE_TELEPHONY = "telephony"; diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index c812e8e1782a..f7a35143916e 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -450,6 +450,21 @@ public abstract class ActivityManagerInternal { public abstract boolean hasRunningForegroundService(int uid, int foregroundServiceType); /** + * Returns {@code true} if the given notification channel currently has a + * notification associated with a foreground service. This is an AMS check + * because that is the source of truth for the FGS state. + */ + public abstract boolean hasForegroundServiceNotification(String pkg, @UserIdInt int userId, + String channelId); + + /** + * If the given app has any FGSs whose notifications are in the given channel, + * stop them. + */ + public abstract void stopForegroundServicesForChannel(String pkg, @UserIdInt int userId, + String channelId); + + /** * Registers the specified {@code processObserver} to be notified of future changes to * process state. */ diff --git a/core/java/android/companion/Association.java b/core/java/android/companion/Association.java index 9007d9d8bbcc..b060ce2f4460 100644 --- a/core/java/android/companion/Association.java +++ b/core/java/android/companion/Association.java @@ -53,8 +53,6 @@ public final class Association implements Parcelable { - - // Code below generated by codegen v1.0.22. // // DO NOT MODIFY! @@ -242,7 +240,7 @@ public final class Association implements Parcelable { }; @DataClass.Generated( - time = 1612832377589L, + time = 1611795283642L, codegenVersion = "1.0.22", sourceFile = "frameworks/base/core/java/android/companion/Association.java", inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull java.lang.String mDeviceMacAddress\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mDeviceProfile\nprivate final boolean mNotifyOnDeviceNearby\nprivate final long mTimeApprovedMs\npublic int getUserId()\nprivate java.lang.String timeApprovedMsToString()\nclass Association extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstructor=true)") diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index de17fda82d71..9d8a97720f44 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1787,7 +1787,7 @@ public class Intent implements Parcelable, Cloneable { * the package name of the current installed package to be uninstalled. * You can optionally supply {@link #EXTRA_RETURN_RESULT}. * <p> - * Output: If {@link #EXTRA_RETURN_RESULT}, returns whether the install + * Output: If {@link #EXTRA_RETURN_RESULT}, returns whether the uninstall * succeeded. * <p> * Requires {@link android.Manifest.permission#REQUEST_DELETE_PACKAGES} diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index d79b66c1cf56..142b17c3973d 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -6776,7 +6776,7 @@ public abstract class PackageManager { @NonNull public Resources getResourcesForApplication(@NonNull ApplicationInfo app, @Nullable Configuration configuration) throws NameNotFoundException { - throw new UnsupportedOperationException(); + return getResourcesForApplication(app); } /** diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java index 11f3e4582ac2..79831a181b3f 100644 --- a/core/java/android/hardware/soundtrigger/SoundTrigger.java +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java @@ -19,6 +19,7 @@ package android.hardware.soundtrigger; import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD; import static android.Manifest.permission.RECORD_AUDIO; import static android.Manifest.permission.SOUNDTRIGGER_DELEGATE_IDENTITY; +import static android.system.OsConstants.EBUSY; import static android.system.OsConstants.EINVAL; import static android.system.OsConstants.ENODEV; import static android.system.OsConstants.ENOSYS; @@ -91,6 +92,8 @@ public class SoundTrigger { public static final int STATUS_DEAD_OBJECT = -EPIPE; /** @hide */ public static final int STATUS_INVALID_OPERATION = -ENOSYS; + /** @hide */ + public static final int STATUS_BUSY = -EBUSY; /***************************************************************************** * A ModuleProperties describes a given sound trigger hardware module @@ -1835,120 +1838,6 @@ public class SoundTrigger { } } - /** - * Status codes for {@link SoundModelEvent} - */ - /** - * Sound Model was updated - * - * @hide - */ - public static final int SOUNDMODEL_STATUS_UPDATED = 0; - - /** - * A SoundModelEvent is provided by the - * {@link StatusListener#onSoundModelUpdate(SoundModelEvent)} - * callback when a sound model has been updated by the implementation - * - * @hide - */ - public static class SoundModelEvent implements Parcelable { - /** Status e.g {@link #SOUNDMODEL_STATUS_UPDATED} */ - public final int status; - /** The updated sound model handle */ - public final int soundModelHandle; - /** New sound model data */ - @NonNull - public final byte[] data; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - SoundModelEvent(int status, int soundModelHandle, @Nullable byte[] data) { - this.status = status; - this.soundModelHandle = soundModelHandle; - this.data = data != null ? data : new byte[0]; - } - - public static final @android.annotation.NonNull Parcelable.Creator<SoundModelEvent> CREATOR - = new Parcelable.Creator<SoundModelEvent>() { - public SoundModelEvent createFromParcel(Parcel in) { - return SoundModelEvent.fromParcel(in); - } - - public SoundModelEvent[] newArray(int size) { - return new SoundModelEvent[size]; - } - }; - - private static SoundModelEvent fromParcel(Parcel in) { - int status = in.readInt(); - int soundModelHandle = in.readInt(); - byte[] data = in.readBlob(); - return new SoundModelEvent(status, soundModelHandle, data); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(status); - dest.writeInt(soundModelHandle); - dest.writeBlob(data); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + Arrays.hashCode(data); - result = prime * result + soundModelHandle; - result = prime * result + status; - return result; - } - - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - SoundModelEvent other = (SoundModelEvent) obj; - if (!Arrays.equals(data, other.data)) - return false; - if (soundModelHandle != other.soundModelHandle) - return false; - if (status != other.status) - return false; - return true; - } - - @Override - public String toString() { - return "SoundModelEvent [status=" + status + ", soundModelHandle=" + soundModelHandle - + ", data=" + (data == null ? 0 : data.length) + "]"; - } - } - - /** - * Native service state. {@link StatusListener#onServiceStateChange(int)} - */ - // Keep in sync with system/core/include/system/sound_trigger.h - /** - * Sound trigger service is enabled - * - * @hide - */ - public static final int SERVICE_STATE_ENABLED = 0; - /** - * Sound trigger service is disabled - * - * @hide - */ - public static final int SERVICE_STATE_DISABLED = 1; private static Object mServiceLock = new Object(); private static ISoundTriggerMiddlewareService mService; @@ -1975,6 +1864,8 @@ public class SoundTrigger { return STATUS_DEAD_OBJECT; case Status.INTERNAL_ERROR: return STATUS_ERROR; + case Status.RESOURCE_CONTENTION: + return STATUS_BUSY; } return STATUS_ERROR; } @@ -2224,27 +2115,28 @@ public class SoundTrigger { * * @hide */ - public static interface StatusListener { + public interface StatusListener { /** * Called when recognition succeeds of fails */ - public abstract void onRecognition(RecognitionEvent event); + void onRecognition(RecognitionEvent event); /** - * Called when a sound model has been updated + * Called when a sound model has been preemptively unloaded by the underlying + * implementation. */ - public abstract void onSoundModelUpdate(SoundModelEvent event); + void onModelUnloaded(int modelHandle); /** - * Called when the sound trigger native service state changes. - * @param state Native service state. One of {@link SoundTrigger#SERVICE_STATE_ENABLED}, - * {@link SoundTrigger#SERVICE_STATE_DISABLED} + * Called whenever underlying conditions change, such that load/start operations that have + * previously failed or got preempted may now succeed. This is not a guarantee, merely a + * hint that the client may want to retry operations. */ - public abstract void onServiceStateChange(int state); + void onResourcesAvailable(); /** * Called when the sound trigger native service dies */ - public abstract void onServiceDied(); + void onServiceDied(); } } diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java index 431c99dbdc1f..62fb999bf55c 100644 --- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java +++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java @@ -48,7 +48,8 @@ public class SoundTriggerModule { private static final int EVENT_RECOGNITION = 1; private static final int EVENT_SERVICE_DIED = 2; - private static final int EVENT_SERVICE_STATE_CHANGE = 3; + private static final int EVENT_RESOURCES_AVAILABLE = 3; + private static final int EVENT_MODEL_UNLOADED = 4; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int mId; private EventHandlerDelegate mEventHandlerDelegate; @@ -120,6 +121,7 @@ public class SoundTriggerModule { * @param soundModelHandle an array of int where the sound model handle will be returned. * @return - {@link SoundTrigger#STATUS_OK} in case of success * - {@link SoundTrigger#STATUS_ERROR} in case of unspecified error + * - {@link SoundTrigger#STATUS_BUSY} in case of transient resource constraints * - {@link SoundTrigger#STATUS_PERMISSION_DENIED} if the caller does not have * system permission * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached @@ -181,6 +183,7 @@ public class SoundTriggerModule { * recognition mode, keyphrases, users, minimum confidence levels... * @return - {@link SoundTrigger#STATUS_OK} in case of success * - {@link SoundTrigger#STATUS_ERROR} in case of unspecified error + * - {@link SoundTrigger#STATUS_BUSY} in case of transient resource constraints * - {@link SoundTrigger#STATUS_PERMISSION_DENIED} if the caller does not have * system permission * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached @@ -333,8 +336,11 @@ public class SoundTriggerModule { listener.onRecognition( (SoundTrigger.RecognitionEvent) msg.obj); break; - case EVENT_SERVICE_STATE_CHANGE: - listener.onServiceStateChange((int) msg.obj); + case EVENT_RESOURCES_AVAILABLE: + listener.onResourcesAvailable(); + break; + case EVENT_MODEL_UNLOADED: + listener.onModelUnloaded((Integer) msg.obj); break; case EVENT_SERVICE_DIED: listener.onServiceDied(); @@ -364,11 +370,14 @@ public class SoundTriggerModule { } @Override - public synchronized void onRecognitionAvailabilityChange(boolean available) - throws RemoteException { - Message m = mHandler.obtainMessage(EVENT_SERVICE_STATE_CHANGE, - available ? SoundTrigger.SERVICE_STATE_ENABLED - : SoundTrigger.SERVICE_STATE_DISABLED); + public void onModelUnloaded(int modelHandle) throws RemoteException { + Message m = mHandler.obtainMessage(EVENT_MODEL_UNLOADED, modelHandle); + mHandler.sendMessage(m); + } + + @Override + public synchronized void onResourcesAvailable() throws RemoteException { + Message m = mHandler.obtainMessage(EVENT_RESOURCES_AVAILABLE); mHandler.sendMessage(m); } diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java index 16d041ac60f2..d026e959905c 100644 --- a/core/java/android/os/BinderProxy.java +++ b/core/java/android/os/BinderProxy.java @@ -34,6 +34,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; /** * Java proxy for a native IBinder object. @@ -262,27 +265,45 @@ public final class BinderProxy implements IBinder { Log.e(Binder.TAG, "RemoteException while disabling app freezer"); } - for (WeakReference<BinderProxy> weakRef : proxiesToQuery) { - BinderProxy bp = weakRef.get(); - String key; - if (bp == null) { - key = "<cleared weak-ref>"; - } else { - try { - key = bp.getInterfaceDescriptor(); - if ((key == null || key.isEmpty()) && !bp.isBinderAlive()) { - key = "<proxy to dead node>"; + // We run the dump on a separate thread, because there are known cases where + // a process overrides getInterfaceDescriptor() and somehow blocks on it, causing + // the calling thread (usually AMS) to hit the watchdog. + // Do the dumping on a separate thread instead, and give up after a while. + ExecutorService executorService = Executors.newSingleThreadExecutor(); + executorService.submit(() -> { + for (WeakReference<BinderProxy> weakRef : proxiesToQuery) { + BinderProxy bp = weakRef.get(); + String key; + if (bp == null) { + key = "<cleared weak-ref>"; + } else { + try { + key = bp.getInterfaceDescriptor(); + if ((key == null || key.isEmpty()) && !bp.isBinderAlive()) { + key = "<proxy to dead node>"; + } + } catch (Throwable t) { + key = "<exception during getDescriptor>"; } - } catch (Throwable t) { - key = "<exception during getDescriptor>"; + } + Integer i = counts.get(key); + if (i == null) { + counts.put(key, 1); + } else { + counts.put(key, i + 1); } } - Integer i = counts.get(key); - if (i == null) { - counts.put(key, 1); - } else { - counts.put(key, i + 1); + }); + + try { + executorService.shutdown(); + boolean dumpDone = executorService.awaitTermination(20, TimeUnit.SECONDS); + if (!dumpDone) { + Log.e(Binder.TAG, "Failed to complete binder proxy dump," + + " dumping what we have so far."); } + } catch (InterruptedException e) { + // Ignore } try { ActivityManager.getService().enableAppFreezer(true); diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 83f78a56487a..6a31e7daa3e1 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -1317,7 +1317,11 @@ public class Build { public static final boolean IS_USER = "user".equals(TYPE); /** - * Whether this build is running inside a container. + * Whether this build is running on ARC, the Android Runtime for Chrome + * (https://chromium.googlesource.com/chromiumos/docs/+/master/containers_and_vms.md). + * Prior to R this was implemented as a container but from R this will be + * a VM. The name of the property remains ro.boot.conntainer as it is + * referenced in other projects. * * We should try to avoid checking this flag if possible to minimize * unnecessarily diverging from non-container Android behavior. @@ -1328,7 +1332,7 @@ public class Build { * For higher-level behavior differences, other checks should be preferred. * @hide */ - public static final boolean IS_CONTAINER = + public static final boolean IS_ARC = SystemProperties.getBoolean("ro.boot.container", false); /** diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index df24baaf8ad9..ec25d907e70f 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -114,20 +114,18 @@ import java.util.function.Consumer; * * <pre> * public void onCreate() { - * if (DEVELOPER_MODE) { - * StrictMode.setThreadPolicy(new {@link ThreadPolicy.Builder StrictMode.ThreadPolicy.Builder}() - * .detectDiskReads() - * .detectDiskWrites() - * .detectNetwork() // or .detectAll() for all detectable problems - * .penaltyLog() - * .build()); - * StrictMode.setVmPolicy(new {@link VmPolicy.Builder StrictMode.VmPolicy.Builder}() - * .detectLeakedSqlLiteObjects() - * .detectLeakedClosableObjects() - * .penaltyLog() - * .penaltyDeath() - * .build()); - * } + * StrictMode.setThreadPolicy(new {@link ThreadPolicy.Builder StrictMode.ThreadPolicy.Builder}() + * .detectDiskReads() + * .detectDiskWrites() + * .detectNetwork() // or .detectAll() for all detectable problems + * .penaltyLog() + * .build()); + * StrictMode.setVmPolicy(new {@link VmPolicy.Builder StrictMode.VmPolicy.Builder}() + * .detectLeakedSqlLiteObjects() + * .detectLeakedClosableObjects() + * .penaltyLog() + * .penaltyDeath() + * .build()); * super.onCreate(); * } * </pre> @@ -146,9 +144,7 @@ import java.util.function.Consumer; * <p class="note">StrictMode is not a security mechanism and is not guaranteed to find all disk or * network accesses. While it does propagate its state across process boundaries when doing {@link * android.os.Binder} calls, it's still ultimately a best effort mechanism. Notably, disk or network - * access from JNI calls won't necessarily trigger it. Future versions of Android may catch more (or - * fewer) operations, so you should never leave StrictMode enabled in applications distributed on - * Google Play. + * access from JNI calls won't necessarily trigger it. */ public final class StrictMode { private static final String TAG = "StrictMode"; diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl index 98b4e0b4f402..5fe870fc57e6 100644 --- a/core/java/android/os/storage/IStorageManager.aidl +++ b/core/java/android/os/storage/IStorageManager.aidl @@ -198,7 +198,7 @@ interface IStorageManager { void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88; void fixupAppDir(in String path) = 89; void disableAppDataIsolation(in String pkgName, int pid, int userId) = 90; - void notifyAppIoBlocked(in String volumeUuid, int uid, int tid, int reason) = 91; - void notifyAppIoResumed(in String volumeUuid, int uid, int tid, int reason) = 92; - PendingIntent getManageSpaceActivityIntent(in String packageName, int requestCode) = 93; - } + PendingIntent getManageSpaceActivityIntent(in String packageName, int requestCode) = 91; + void notifyAppIoBlocked(in String volumeUuid, int uid, int tid, int reason) = 92; + void notifyAppIoResumed(in String volumeUuid, int uid, int tid, int reason) = 93; +} diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java index 396ba2d3cea5..82c4c715f4b0 100644 --- a/core/java/android/os/storage/StorageManagerInternal.java +++ b/core/java/android/os/storage/StorageManagerInternal.java @@ -52,6 +52,11 @@ public abstract class StorageManagerInternal { } /** + * Return true if fuse is mounted. + */ + public abstract boolean isFuseMounted(int userId); + + /** * Create storage directories if it does not exist. * Return true if the directories were setup correctly, otherwise false. */ diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index e9bbcc79e9df..12964b5ea67c 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -376,6 +376,15 @@ public final class DeviceConfig { public static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot"; /** + * Namespace for swcodec native related features. + * + * @hide + */ + @SystemApi + public static final String NAMESPACE_SWCODEC_NATIVE = "swcodec_native"; + + + /** * Namespace for System UI related features. * * @hide diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 4dfbb6fa2d05..f367409b49e1 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8505,6 +8505,15 @@ public final class Settings { "one_handed_tutorial_show_count"; /** + * Indicates whether transform is enabled. + * <p> + * Type: int (0 for false, 1 for true) + * + * @hide + */ + public static final String TRANSFORM_ENABLED = "transform_enabled"; + + /** * The current night mode that has been selected by the user. Owned * and controlled by UiModeManagerService. Constants are as per * UiModeManager. diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 8a4812a42c8a..3da107534b55 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -5304,6 +5304,13 @@ public final class Telephony { public static final String COLUMN_RCS_CONFIG = "rcs_config"; /** + * TelephonyProvider column name for device to device sharing status. + * + * @hide + */ + public static final String COLUMN_D2D_STATUS_SHARING = "d2d_sharing_status"; + + /** * TelephonyProvider column name for VoIMS provisioning. Default is 0. * <P>Type: INTEGER </P> * diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS index cbb86de4785f..a86984f44a41 100644 --- a/core/java/android/view/OWNERS +++ b/core/java/android/view/OWNERS @@ -78,3 +78,7 @@ per-file SyncRtSurfaceTransactionApplier.java = file:/services/core/java/com/and per-file ViewRootInsetsControllerHost.java = file:/services/core/java/com/android/server/wm/OWNERS per-file Window*.java = file:/services/core/java/com/android/server/wm/OWNERS per-file Window*.aidl = file:/services/core/java/com/android/server/wm/OWNERS + +# Scroll Capture +per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS +per-file *CaptureHelper*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS diff --git a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java index 26af61520593..b76ef0fd4ed8 100644 --- a/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java +++ b/core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java @@ -28,11 +28,9 @@ import android.content.Intent; import android.content.pm.ResolveInfo; import android.os.Message; import android.os.UserHandle; -import android.provider.DeviceConfig; import android.util.Log; import com.android.internal.app.ResolverActivity.ResolvedComponentInfo; -import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import java.util.ArrayList; import java.util.HashMap; @@ -62,11 +60,6 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator // back to using the ResolverRankerService. private ResolverRankerServiceResolverComparator mResolverRankerService; - private boolean mAppendDirectShareEnabled = DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.APPEND_DIRECT_SHARE_ENABLED, - true); - AppPredictionServiceResolverComparator( Context context, Intent intent, @@ -183,9 +176,6 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator if (mResolverRankerService != null) { return mResolverRankerService.getScore(name); } - if (mAppendDirectShareEnabled && !mTargetScores.isEmpty()) { - return mTargetScores.get(name); - } Integer rank = mTargetRanks.get(name); if (rank == null) { Log.w(TAG, "Score requested for unknown component. Did you call compute yet?"); diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 6cfd49888fac..b720f4cffb7a 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -256,15 +256,6 @@ public class ChooserActivity extends ResolverActivity implements SystemUiDeviceConfigFlags.HASH_SALT_MAX_DAYS, DEFAULT_SALT_EXPIRATION_DAYS); - private boolean mAppendDirectShareEnabled = DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.APPEND_DIRECT_SHARE_ENABLED, - true); - private boolean mChooserTargetRankingEnabled = DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.CHOOSER_TARGET_RANKING_ENABLED, - true); - private Bundle mReplacementExtras; private IntentSender mChosenComponentSender; private IntentSender mRefinementIntentSender; @@ -472,16 +463,10 @@ public class ChooserActivity extends ResolverActivity implements private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT = 4; private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED = 5; private static final int LIST_VIEW_UPDATE_MESSAGE = 6; - private static final int CHOOSER_TARGET_RANKING_SCORE = 7; private static final int WATCHDOG_TIMEOUT_MAX_MILLIS = 10000; private static final int WATCHDOG_TIMEOUT_MIN_MILLIS = 3000; - private static final int DEFAULT_DIRECT_SHARE_TIMEOUT_MILLIS = 1500; - private int mDirectShareTimeout = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.SHARE_SHEET_DIRECT_SHARE_TIMEOUT, - DEFAULT_DIRECT_SHARE_TIMEOUT_MILLIS); - private boolean mMinTimeoutPassed = false; private void removeAllMessages() { @@ -491,7 +476,6 @@ public class ChooserActivity extends ResolverActivity implements removeMessages(CHOOSER_TARGET_SERVICE_RESULT); removeMessages(SHORTCUT_MANAGER_SHARE_TARGET_RESULT); removeMessages(SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED); - removeMessages(CHOOSER_TARGET_RANKING_SCORE); } private void restartServiceRequestTimer() { @@ -501,14 +485,13 @@ public class ChooserActivity extends ResolverActivity implements if (DEBUG) { Log.d(TAG, "queryTargets setting watchdog timer for " - + mDirectShareTimeout + "-" + WATCHDOG_TIMEOUT_MAX_MILLIS + "ms"); } sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_MIN_TIMEOUT, WATCHDOG_TIMEOUT_MIN_MILLIS); sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_MAX_TIMEOUT, - mAppendDirectShareEnabled ? mDirectShareTimeout : WATCHDOG_TIMEOUT_MAX_MILLIS); + WATCHDOG_TIMEOUT_MAX_MILLIS); } private void maybeStopServiceRequestTimer() { @@ -608,17 +591,6 @@ public class ChooserActivity extends ResolverActivity implements getChooserActivityLogger().logSharesheetDirectLoadComplete(); break; - case CHOOSER_TARGET_RANKING_SCORE: - if (DEBUG) Log.d(TAG, "CHOOSER_TARGET_RANKING_SCORE"); - final ChooserTargetRankingInfo scoreInfo = (ChooserTargetRankingInfo) msg.obj; - ChooserListAdapter adapterForUserHandle = - mChooserMultiProfilePagerAdapter.getListAdapterForUserHandle( - scoreInfo.userHandle); - if (adapterForUserHandle != null) { - adapterForUserHandle.addChooserTargetRankingScore(scoreInfo.scores); - } - break; - default: super.handleMessage(msg); } @@ -878,24 +850,14 @@ public class ChooserActivity extends ResolverActivity implements final List<ShortcutManager.ShareShortcutInfo> shareShortcutInfos = new ArrayList<>(); - // Separate ChooserTargets ranking scores and ranked Shortcuts. List<AppTarget> shortcutResults = new ArrayList<>(); - List<AppTarget> chooserTargetScores = new ArrayList<>(); for (AppTarget appTarget : resultList) { if (appTarget.getShortcutInfo() == null) { continue; } - if (appTarget.getShortcutInfo().getId().equals(CHOOSER_TARGET)) { - chooserTargetScores.add(appTarget); - } else { - shortcutResults.add(appTarget); - } + shortcutResults.add(appTarget); } resultList = shortcutResults; - if (mChooserTargetRankingEnabled) { - sendChooserTargetRankingScore(chooserTargetScores, - chooserListAdapter.getUserHandle()); - } for (AppTarget appTarget : resultList) { shareShortcutInfos.add(new ShortcutManager.ShareShortcutInfo( appTarget.getShortcutInfo(), @@ -2148,14 +2110,6 @@ public class ChooserActivity extends ResolverActivity implements return true; } - private void sendChooserTargetRankingScore(List<AppTarget> chooserTargetScores, - UserHandle userHandle) { - final Message msg = Message.obtain(); - msg.what = ChooserHandler.CHOOSER_TARGET_RANKING_SCORE; - msg.obj = new ChooserTargetRankingInfo(chooserTargetScores, userHandle); - mChooserHandler.sendMessage(msg); - } - private void sendShareShortcutInfoList( List<ShortcutManager.ShareShortcutInfo> resultList, ChooserListAdapter chooserListAdapter, @@ -2165,10 +2119,10 @@ public class ChooserActivity extends ResolverActivity implements + " resultList.size()=" + resultList.size() + " appTargets.size()=" + appTargets.size()); } - + Context selectedProfileContext = createContextAsUser(userHandle, 0 /* flags */); for (int i = resultList.size() - 1; i >= 0; i--) { final String packageName = resultList.get(i).getTargetComponent().getPackageName(); - if (!isPackageEnabled(packageName)) { + if (!isPackageEnabled(selectedProfileContext, packageName)) { resultList.remove(i); if (appTargets != null) { appTargets.remove(i); @@ -2220,13 +2174,13 @@ public class ChooserActivity extends ResolverActivity implements mChooserHandler.sendMessage(msg); } - private boolean isPackageEnabled(String packageName) { + private boolean isPackageEnabled(Context context, String packageName) { if (TextUtils.isEmpty(packageName)) { return false; } ApplicationInfo appInfo; try { - appInfo = getPackageManager().getApplicationInfo(packageName, 0); + appInfo = context.getPackageManager().getApplicationInfo(packageName, 0); } catch (NameNotFoundException e) { return false; } @@ -2376,9 +2330,6 @@ public class ChooserActivity extends ResolverActivity implements } private void sendImpressionToAppPredictor(TargetInfo targetInfo, ChooserListAdapter adapter) { - if (!mChooserTargetRankingEnabled) { - return; - } AppPredictor directShareAppPredictor = getAppPredictorForDirectShareIfEnabled( mChooserMultiProfilePagerAdapter.getCurrentUserHandle()); if (directShareAppPredictor == null) { @@ -2399,11 +2350,6 @@ public class ChooserActivity extends ResolverActivity implements targetIds.add(new AppTargetId( String.format("%s/%s/%s", shortcutId, componentName.flattenToString(), SHORTCUT_TARGET))); - } else { - String titleHash = ChooserUtil.md5(chooserTarget.getTitle().toString()); - targetIds.add(new AppTargetId( - String.format("%s/%s/%s", titleHash, componentName.flattenToString(), - CHOOSER_TARGET))); } } directShareAppPredictor.notifyLaunchLocationShown(LAUNCH_LOCATION_DIRECT_SHARE, targetIds); @@ -2423,29 +2369,6 @@ public class ChooserActivity extends ResolverActivity implements if (mDirectShareAppTargetCache != null) { appTarget = mDirectShareAppTargetCache.get(chooserTarget); } - if (mChooserTargetRankingEnabled && appTarget == null) { - // Send ChooserTarget sharing info to AppPredictor. - ComponentName componentName = mChooserTargetComponentNameCache.getOrDefault( - chooserTarget.getComponentName(), chooserTarget.getComponentName()); - try { - appTarget = new AppTarget.Builder( - new AppTargetId(componentName.flattenToString()), - new ShortcutInfo.Builder( - createPackageContextAsUser( - componentName.getPackageName(), - 0 /* flags */, - getUser()), - CHOOSER_TARGET) - .setActivity(componentName) - .setShortLabel(ChooserUtil.md5(chooserTarget.getTitle().toString())) - .build()) - .setClassName(componentName.getClassName()) - .build(); - } catch (NameNotFoundException e) { - Log.e(TAG, "Could not look up service " + componentName - + "; component name not found"); - } - } // This is a direct share click that was provided by the APS if (appTarget != null) { directShareAppPredictor.notifyAppTargetEvent( @@ -3971,9 +3894,7 @@ public class ChooserActivity extends ResolverActivity implements // until they start to scroll ChooserListAdapter adapter = mChooserMultiProfilePagerAdapter.getActiveListAdapter(); - int validTargets = - mAppendDirectShareEnabled ? adapter.getNumServiceTargetsForExpand() - : adapter.getSelectableServiceTargetCount(); + int validTargets = adapter.getSelectableServiceTargetCount(); if (validTargets <= maxTargetsPerRow) { mHideDirectShareExpansion = true; return; diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java index 570066807f16..cc2b12a99d79 100644 --- a/core/java/com/android/internal/app/ChooserListAdapter.java +++ b/core/java/com/android/internal/app/ChooserListAdapter.java @@ -21,7 +21,6 @@ import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FRO import android.app.ActivityManager; import android.app.prediction.AppPredictor; -import android.app.prediction.AppTarget; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -37,7 +36,6 @@ import android.os.UserManager; import android.provider.DeviceConfig; import android.service.chooser.ChooserTarget; import android.util.Log; -import android.util.Pair; import android.view.View; import android.view.ViewGroup; @@ -53,21 +51,13 @@ import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; public class ChooserListAdapter extends ResolverListAdapter { private static final String TAG = "ChooserListAdapter"; private static final boolean DEBUG = false; - private boolean mAppendDirectShareEnabled = DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.APPEND_DIRECT_SHARE_ENABLED, - true); - private boolean mEnableStackedApps = true; public static final int NO_POSITION = -1; @@ -79,8 +69,6 @@ public class ChooserListAdapter extends ResolverListAdapter { private static final int MAX_SUGGESTED_APP_TARGETS = 4; private static final int MAX_CHOOSER_TARGETS_PER_APP = 2; - private static final int MAX_SERVICE_TARGET_APP = 8; - private static final int DEFAULT_DIRECT_SHARE_RANKING_SCORE = 1000; /** {@link #getBaseScore} */ public static final float CALLER_TARGET_SCORE_BOOST = 900.f; @@ -94,17 +82,11 @@ public class ChooserListAdapter extends ResolverListAdapter { private int mNumShortcutResults = 0; private Map<DisplayResolveInfo, LoadIconTask> mIconLoaders = new HashMap<>(); + private boolean mApplySharingAppLimits; // Reserve spots for incoming direct share targets by adding placeholders private ChooserTargetInfo mPlaceHolderTargetInfo = new ChooserActivity.PlaceHolderTargetInfo(); - private int mValidServiceTargetsNum = 0; - private int mAvailableServiceTargetsNum = 0; - private final Map<ComponentName, Pair<List<ChooserTargetInfo>, Integer>> - mParkingDirectShareTargets = new HashMap<>(); - private final Map<ComponentName, Map<String, Integer>> mChooserTargetScores = new HashMap<>(); - private Set<ComponentName> mPendingChooserTargetService = new HashSet<>(); - private Set<ComponentName> mShortcutComponents = new HashSet<>(); private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>(); private final List<DisplayResolveInfo> mCallerTargets = new ArrayList<>(); @@ -183,6 +165,10 @@ public class ChooserListAdapter extends ResolverListAdapter { if (mCallerTargets.size() == MAX_SUGGESTED_APP_TARGETS) break; } } + mApplySharingAppLimits = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI, + true); } AppPredictor getAppPredictor() { @@ -209,9 +195,6 @@ public class ChooserListAdapter extends ResolverListAdapter { void refreshListView() { if (mListViewDataChanged) { - if (mAppendDirectShareEnabled) { - appendServiceTargetsWithQuota(); - } super.notifyDataSetChanged(); } mListViewDataChanged = false; @@ -221,10 +204,6 @@ public class ChooserListAdapter extends ResolverListAdapter { private void createPlaceHolders() { mNumShortcutResults = 0; mServiceTargets.clear(); - mValidServiceTargetsNum = 0; - mParkingDirectShareTargets.clear(); - mPendingChooserTargetService.clear(); - mShortcutComponents.clear(); for (int i = 0; i < mChooserListCommunicator.getMaxRankedTargets(); i++) { mServiceTargets.add(mPlaceHolderTargetInfo); } @@ -517,33 +496,30 @@ public class ChooserListAdapter extends ResolverListAdapter { + targets.size() + " targets"); } - if (mAppendDirectShareEnabled) { - parkTargetIntoMemory(origTarget, targets, targetType, directShareToShortcutInfos, - pendingChooserTargetServiceConnections); - return; - } if (targets.size() == 0) { return; } - final float baseScore = getBaseScore(origTarget, targetType); Collections.sort(targets, mBaseTargetComparator); - final boolean isShortcutResult = (targetType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER || targetType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE); final int maxTargets = isShortcutResult ? mMaxShortcutTargetsPerApp : MAX_CHOOSER_TARGETS_PER_APP; + final int targetsLimit = mApplySharingAppLimits ? Math.min(targets.size(), maxTargets) + : targets.size(); float lastScore = 0; boolean shouldNotify = false; - for (int i = 0, count = Math.min(targets.size(), maxTargets); i < count; i++) { + for (int i = 0, count = targetsLimit; i < count; i++) { final ChooserTarget target = targets.get(i); float targetScore = target.getScore(); - targetScore *= baseScore; - if (i > 0 && targetScore >= lastScore) { - // Apply a decay so that the top app can't crowd out everything else. - // This incents ChooserTargetServices to define what's truly better. - targetScore = lastScore * 0.95f; + if (mApplySharingAppLimits) { + targetScore *= baseScore; + if (i > 0 && targetScore >= lastScore) { + // Apply a decay so that the top app can't crowd out everything else. + // This incents ChooserTargetServices to define what's truly better. + targetScore = lastScore * 0.95f; + } } UserHandle userHandle = getUserHandle(); Context contextAsUser = mContext.createContextAsUser(userHandle, 0 /* flags */); @@ -561,7 +537,8 @@ public class ChooserListAdapter extends ResolverListAdapter { Log.d(TAG, " => " + target.toString() + " score=" + targetScore + " base=" + target.getScore() + " lastScore=" + lastScore - + " baseScore=" + baseScore); + + " baseScore=" + baseScore + + " applyAppLimit=" + mApplySharingAppLimits); } lastScore = targetScore; @@ -573,217 +550,13 @@ public class ChooserListAdapter extends ResolverListAdapter { } /** - * Store ChooserTarget ranking scores info wrapped in {@code targets}. - */ - public void addChooserTargetRankingScore(List<AppTarget> targets) { - Log.i(TAG, "addChooserTargetRankingScore " + targets.size() + " targets score."); - for (AppTarget target : targets) { - if (target.getShortcutInfo() == null) { - continue; - } - ShortcutInfo shortcutInfo = target.getShortcutInfo(); - if (!shortcutInfo.getId().equals(ChooserActivity.CHOOSER_TARGET) - || shortcutInfo.getActivity() == null) { - continue; - } - ComponentName componentName = shortcutInfo.getActivity(); - if (!mChooserTargetScores.containsKey(componentName)) { - mChooserTargetScores.put(componentName, new HashMap<>()); - } - mChooserTargetScores.get(componentName).put(shortcutInfo.getShortLabel().toString(), - target.getRank()); - } - mChooserTargetScores.keySet().forEach(key -> rankTargetsWithinComponent(key)); - } - - /** - * Rank chooserTargets of the given {@code componentName} in mParkingDirectShareTargets as per - * available scores stored in mChooserTargetScores. - */ - private void rankTargetsWithinComponent(ComponentName componentName) { - if (!mParkingDirectShareTargets.containsKey(componentName) - || !mChooserTargetScores.containsKey(componentName)) { - return; - } - Map<String, Integer> scores = mChooserTargetScores.get(componentName); - Collections.sort(mParkingDirectShareTargets.get(componentName).first, (o1, o2) -> { - // The score has been normalized between 0 and 2000, the default is 1000. - int score1 = scores.getOrDefault( - ChooserUtil.md5(o1.getChooserTarget().getTitle().toString()), - DEFAULT_DIRECT_SHARE_RANKING_SCORE); - int score2 = scores.getOrDefault( - ChooserUtil.md5(o2.getChooserTarget().getTitle().toString()), - DEFAULT_DIRECT_SHARE_RANKING_SCORE); - return score2 - score1; - }); - } - - /** - * Park {@code targets} into memory for the moment to surface them later when view is refreshed. - * Components pending on ChooserTargetService query are also recorded. - */ - private void parkTargetIntoMemory(DisplayResolveInfo origTarget, List<ChooserTarget> targets, - @ChooserActivity.ShareTargetType int targetType, - Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos, - List<ChooserActivity.ChooserTargetServiceConnection> - pendingChooserTargetServiceConnections) { - ComponentName origComponentName = origTarget != null ? origTarget.getResolvedComponentName() - : !targets.isEmpty() ? targets.get(0).getComponentName() : null; - Log.i(TAG, - "parkTargetIntoMemory " + origComponentName + ", " + targets.size() + " targets"); - mPendingChooserTargetService = pendingChooserTargetServiceConnections.stream() - .map(ChooserActivity.ChooserTargetServiceConnection::getComponentName) - .filter(componentName -> !componentName.equals(origComponentName)) - .collect(Collectors.toSet()); - // Park targets in memory - if (!targets.isEmpty()) { - final boolean isShortcutResult = - (targetType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER - || targetType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE); - Context contextAsUser = mContext.createContextAsUser(getUserHandle(), - 0 /* flags */); - List<ChooserTargetInfo> parkingTargetInfos = targets.stream() - .map(target -> - new SelectableTargetInfo( - contextAsUser, origTarget, target, target.getScore(), - mSelectableTargetInfoCommunicator, - (isShortcutResult ? directShareToShortcutInfos.get(target) - : null)) - ) - .collect(Collectors.toList()); - Pair<List<ChooserTargetInfo>, Integer> parkingTargetInfoPair = - mParkingDirectShareTargets.getOrDefault(origComponentName, - new Pair<>(new ArrayList<>(), 0)); - for (ChooserTargetInfo target : parkingTargetInfos) { - if (!checkDuplicateTarget(target, parkingTargetInfoPair.first) - && !checkDuplicateTarget(target, mServiceTargets)) { - parkingTargetInfoPair.first.add(target); - mAvailableServiceTargetsNum++; - } - } - mParkingDirectShareTargets.put(origComponentName, parkingTargetInfoPair); - rankTargetsWithinComponent(origComponentName); - if (isShortcutResult) { - mShortcutComponents.add(origComponentName); - } - } - notifyDataSetChanged(); - } - - /** - * Append targets of top ranked share app into direct share row with quota limit. Remove - * appended ones from memory. - */ - private void appendServiceTargetsWithQuota() { - int maxRankedTargets = mChooserListCommunicator.getMaxRankedTargets(); - List<ComponentName> topComponentNames = getTopComponentNames(maxRankedTargets); - float totalScore = 0f; - for (ComponentName component : topComponentNames) { - if (!mPendingChooserTargetService.contains(component) - && !mParkingDirectShareTargets.containsKey(component)) { - continue; - } - totalScore += super.getScore(component); - } - boolean shouldWaitPendingService = false; - for (ComponentName component : topComponentNames) { - if (!mPendingChooserTargetService.contains(component) - && !mParkingDirectShareTargets.containsKey(component)) { - continue; - } - float score = super.getScore(component); - int quota = Math.round(maxRankedTargets * score / totalScore); - if (mPendingChooserTargetService.contains(component) && quota >= 1) { - shouldWaitPendingService = true; - } - if (!mParkingDirectShareTargets.containsKey(component)) { - continue; - } - // Append targets into direct share row as per quota. - Pair<List<ChooserTargetInfo>, Integer> parkingTargetsItem = - mParkingDirectShareTargets.get(component); - List<ChooserTargetInfo> parkingTargets = parkingTargetsItem.first; - int insertedNum = parkingTargetsItem.second; - while (insertedNum < quota && !parkingTargets.isEmpty()) { - if (!checkDuplicateTarget(parkingTargets.get(0), mServiceTargets)) { - mServiceTargets.add(mValidServiceTargetsNum, parkingTargets.get(0)); - mValidServiceTargetsNum++; - insertedNum++; - } - parkingTargets.remove(0); - } - Log.i(TAG, " appendServiceTargetsWithQuota component=" + component - + " appendNum=" + (insertedNum - parkingTargetsItem.second)); - if (DEBUG) { - Log.d(TAG, " appendServiceTargetsWithQuota component=" + component - + " score=" + score - + " totalScore=" + totalScore - + " quota=" + quota); - } - mParkingDirectShareTargets.put(component, new Pair<>(parkingTargets, insertedNum)); - } - if (!shouldWaitPendingService) { - fillAllServiceTargets(); - } - } - - /** - * Append all remaining targets (parking in memory) into direct share row as per their ranking. - */ - private void fillAllServiceTargets() { - if (mParkingDirectShareTargets.isEmpty()) { - return; - } - Log.i(TAG, " fillAllServiceTargets"); - List<ComponentName> topComponentNames = getTopComponentNames(MAX_SERVICE_TARGET_APP); - // Append all remaining targets of top recommended components into direct share row. - for (ComponentName component : topComponentNames) { - if (!mParkingDirectShareTargets.containsKey(component)) { - continue; - } - mParkingDirectShareTargets.get(component).first.stream() - .filter(target -> !checkDuplicateTarget(target, mServiceTargets)) - .forEach(target -> { - mServiceTargets.add(mValidServiceTargetsNum, target); - mValidServiceTargetsNum++; - }); - mParkingDirectShareTargets.remove(component); - } - // Append all remaining shortcuts targets into direct share row. - mParkingDirectShareTargets.entrySet().stream() - .filter(entry -> mShortcutComponents.contains(entry.getKey())) - .map(entry -> entry.getValue()) - .map(pair -> pair.first) - .forEach(targets -> { - for (ChooserTargetInfo target : targets) { - if (!checkDuplicateTarget(target, mServiceTargets)) { - mServiceTargets.add(mValidServiceTargetsNum, target); - mValidServiceTargetsNum++; - } - } - }); - mParkingDirectShareTargets.clear(); - } - - private boolean checkDuplicateTarget(ChooserTargetInfo target, - List<ChooserTargetInfo> destination) { - // Check for duplicates and abort if found - for (ChooserTargetInfo otherTargetInfo : destination) { - if (target.isSimilar(otherTargetInfo)) { - return true; - } - } - return false; - } - - /** * The return number have to exceed a minimum limit to make direct share area expandable. When * append direct share targets is enabled, return count of all available targets parking in the * memory; otherwise, it is shortcuts count which will help reduce the amount of visible * shuffling due to older-style direct share targets. */ int getNumServiceTargetsForExpand() { - return mAppendDirectShareEnabled ? mAvailableServiceTargetsNum : mNumShortcutResults; + return mNumShortcutResults; } /** @@ -801,16 +574,11 @@ public class ChooserListAdapter extends ResolverListAdapter { if (target == null) { return CALLER_TARGET_SCORE_BOOST; } - - if (targetType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE) { - return SHORTCUT_TARGET_SCORE_BOOST; - } - float score = super.getScore(target); - if (targetType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER) { + if (targetType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER + || targetType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE) { return score * SHORTCUT_TARGET_SCORE_BOOST; } - return score; } @@ -820,9 +588,6 @@ public class ChooserListAdapter extends ResolverListAdapter { */ public void completeServiceTargetLoading() { mServiceTargets.removeIf(o -> o instanceof ChooserActivity.PlaceHolderTargetInfo); - if (mAppendDirectShareEnabled) { - fillAllServiceTargets(); - } if (mServiceTargets.isEmpty()) { mServiceTargets.add(new ChooserActivity.EmptyTargetInfo()); } diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index ee988781e51d..e1f9fc35a8e8 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -415,6 +415,12 @@ public final class SystemUiDeviceConfigFlags { public static final String CHOOSER_TARGET_RANKING_ENABLED = "chooser_target_ranking_enabled"; /** + * (boolean) Whether dark launch of remote prediction service is enabled. + */ + public static final String DARK_LAUNCH_REMOTE_PREDICTION_SERVICE_ENABLED = + "dark_launch_remote_prediction_service_enabled"; + + /** * (boolean) Whether to enable pinch resizing for PIP. */ public static final String PIP_PINCH_RESIZE = "pip_pinch_resize"; @@ -473,6 +479,14 @@ public final class SystemUiDeviceConfigFlags { */ public static final String SHARE_USE_SERVICE_TARGETS = "share_use_service_targets"; + /** + * (boolean) If true, SysUI provides guardrails for app usage of Direct Share by enforcing + * limits on number of targets per app & adjusting scores for apps providing many targets. If + * false, this step is skipped. This should be true unless the ranking provider configured by + * [some other flag] is expected to manage these incentives. + */ + public static final String APPLY_SHARING_APP_LIMITS_IN_SYSUI = + "apply_sharing_app_limits_in_sysui"; private SystemUiDeviceConfigFlags() { } diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java index 14b870575769..30a35367d6f5 100644 --- a/core/java/com/android/internal/os/BinderCallsStats.java +++ b/core/java/com/android/internal/os/BinderCallsStats.java @@ -57,6 +57,7 @@ public class BinderCallsStats implements BinderInternal.Observer { public static final boolean DEFAULT_TRACK_SCREEN_INTERACTIVE = false; public static final boolean DEFAULT_TRACK_DIRECT_CALLING_UID = true; public static final boolean DEFAULT_IGNORE_BATTERY_STATUS = false; + public static final boolean DEFAULT_COLLECT_LATENCY_DATA = false; public static final int MAX_BINDER_CALL_STATS_COUNT_DEFAULT = 1500; private static final String DEBUG_ENTRY_PREFIX = "__DEBUG_"; @@ -97,11 +98,13 @@ public class BinderCallsStats implements BinderInternal.Observer { private boolean mTrackDirectCallingUid = DEFAULT_TRACK_DIRECT_CALLING_UID; private boolean mTrackScreenInteractive = DEFAULT_TRACK_SCREEN_INTERACTIVE; private boolean mIgnoreBatteryStatus = DEFAULT_IGNORE_BATTERY_STATUS; + private boolean mCollectLatencyData = DEFAULT_COLLECT_LATENCY_DATA; private CachedDeviceState.Readonly mDeviceState; private CachedDeviceState.TimeInStateStopwatch mBatteryStopwatch; private static final int CALL_STATS_OBSERVER_DEBOUNCE_MILLIS = 5000; + private BinderLatencyObserver mLatencyObserver; private BinderInternal.CallStatsObserver mCallStatsObserver; private ArraySet<Integer> mSendUidsToObserver = new ArraySet<>(32); private final Handler mCallStatsObserverHandler; @@ -153,11 +156,16 @@ public class BinderCallsStats implements BinderInternal.Observer { public Handler getHandler() { return new Handler(Looper.getMainLooper()); } + + public BinderLatencyObserver getLatencyObserver() { + return new BinderLatencyObserver(new BinderLatencyObserver.Injector()); + } } public BinderCallsStats(Injector injector) { this.mRandom = injector.getRandomGenerator(); this.mCallStatsObserverHandler = injector.getHandler(); + this.mLatencyObserver = injector.getLatencyObserver(); } public void setDeviceState(@NonNull CachedDeviceState.Readonly deviceState) { @@ -207,7 +215,10 @@ public class BinderCallsStats implements BinderInternal.Observer { if (mRecordingAllTransactionsForUid || s.recordedCall) { s.cpuTimeStarted = getThreadTimeMicro(); s.timeStarted = getElapsedRealtimeMicro(); + } else if (mCollectLatencyData) { + s.timeStarted = getElapsedRealtimeMicro(); } + return s; } @@ -232,6 +243,10 @@ public class BinderCallsStats implements BinderInternal.Observer { private void processCallEnded(CallSession s, int parcelRequestSize, int parcelReplySize, int workSourceUid) { + if (mCollectLatencyData) { + mLatencyObserver.callEnded(s); + } + UidEntry uidEntry = null; final boolean recordCall; if (s.recordedCall) { @@ -757,6 +772,17 @@ public class BinderCallsStats implements BinderInternal.Observer { } } + /** Whether to collect latency histograms. */ + public void setCollectLatencyData(boolean collectLatencyData) { + mCollectLatencyData = collectLatencyData; + } + + /** Whether to collect latency histograms. */ + @VisibleForTesting + public boolean getCollectLatencyData() { + return mCollectLatencyData; + } + public void reset() { synchronized (mLock) { mCallStatsCount = 0; @@ -768,6 +794,8 @@ public class BinderCallsStats implements BinderInternal.Observer { mBatteryStopwatch.reset(); } mRecordingAllTransactionsForUid = false; + // Do not reset the latency observer as binder stats and latency will be pushed to WW + // at different intervals so the resets should not be coupled. } } @@ -1009,6 +1037,10 @@ public class BinderCallsStats implements BinderInternal.Observer { return mExceptionCounts; } + public BinderLatencyObserver getLatencyObserver() { + return mLatencyObserver; + } + @VisibleForTesting public static <T> List<T> getHighestValues(List<T> list, ToDoubleFunction<T> toDouble, double percentile) { diff --git a/core/java/com/android/internal/os/BinderLatencyBuckets.java b/core/java/com/android/internal/os/BinderLatencyBuckets.java new file mode 100644 index 000000000000..bdee4ca8a6b8 --- /dev/null +++ b/core/java/com/android/internal/os/BinderLatencyBuckets.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.os; + +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.ArrayList; +import java.util.Collections; + +/** + * Generates the bucket thresholds (with a custom logarithmic scale) for a histogram to store + * latency samples in. + */ +public class BinderLatencyBuckets { + private static final String TAG = "BinderLatencyBuckets"; + private ArrayList<Integer> mBuckets; + + /** + * @param bucketCount the number of buckets the histogram should have + * @param firstBucketSize the size of the first bucket (used to avoid excessive small buckets) + * @param scaleFactor the rate in which each consecutive bucket increases (before rounding) + */ + public BinderLatencyBuckets(int bucketCount, int firstBucketSize, float scaleFactor) { + mBuckets = new ArrayList<>(bucketCount - 1); + mBuckets.add(firstBucketSize); + + // Last value and the target are disjoint as we never want to create buckets smaller than 1. + double lastTarget = firstBucketSize; + int lastValue = firstBucketSize; + + // First bucket is already created and the last bucket is anything greater than the final + // bucket in the list, so create 'bucketCount' - 2 buckets. + for (int i = 1; i < bucketCount - 1; i++) { + // Increase the target bucket limit value by the scale factor. + double nextTarget = lastTarget * scaleFactor; + + if (nextTarget > Integer.MAX_VALUE || lastValue == Integer.MAX_VALUE) { + // Do not throw an exception here as this should not affect binder calls. + Slog.w(TAG, "Attempted to create a bucket larger than maxint"); + return; + } + + if ((int) nextTarget > lastValue) { + // Convert the target bucket limit value to an integer. + mBuckets.add((int) nextTarget); + lastValue = (int) nextTarget; + } else { + // Avoid creating redundant buckets, so bucket size should be 1 at a minimum. + mBuckets.add(lastValue + 1); + lastValue = lastValue + 1; + } + lastTarget = nextTarget; + } + } + + /** Gets the bucket index to insert the provided sample in. */ + public int sampleToBucket(int sample) { + if (sample > mBuckets.get(mBuckets.size() - 1)) { + return mBuckets.size(); + } + + // Binary search returns the element index if it is contained in the list - in this case the + // correct bucket is the index after as we use [minValue, maxValue) for bucket boundaries. + // Otherwise, it returns (-(insertion point) - 1), where insertion point is the point where + // to insert the element so that the array remains sorted - in this case the bucket index + // is the insertion point. + int searchResult = Collections.binarySearch(mBuckets, sample); + return searchResult < 0 ? -(1 + searchResult) : searchResult + 1; + } + + @VisibleForTesting + public ArrayList<Integer> getBuckets() { + return mBuckets; + } +} diff --git a/core/java/com/android/internal/os/BinderLatencyObserver.java b/core/java/com/android/internal/os/BinderLatencyObserver.java new file mode 100644 index 000000000000..59cc66d79bce --- /dev/null +++ b/core/java/com/android/internal/os/BinderLatencyObserver.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.os; + +import android.annotation.Nullable; +import android.os.Binder; +import android.os.SystemClock; +import android.util.ArrayMap; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.BinderInternal.CallSession; + +import java.util.Random; + +/** Collects statistics about Binder call latency per calling API and method. */ +public class BinderLatencyObserver { + private static final String TAG = "BinderLatencyObserver"; + public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 10; + + // Histogram buckets parameters. + public static final int BUCKET_COUNT_DEFAULT = 100; + public static final int FIRST_BUCKET_SIZE_DEFAULT = 5; + public static final float BUCKET_SCALE_FACTOR_DEFAULT = 1.125f; + + @GuardedBy("mLock") + private final ArrayMap<LatencyDims, int[]> mLatencyHistograms = new ArrayMap<>(); + private final Object mLock = new Object(); + + // Sampling period to control how often to track CPU usage. 1 means all calls, 100 means ~1 out + // of 100 requests. + private int mPeriodicSamplingInterval = PERIODIC_SAMPLING_INTERVAL_DEFAULT; + + private int mBucketCount = BUCKET_COUNT_DEFAULT; + private int mFirstBucketSize = FIRST_BUCKET_SIZE_DEFAULT; + private float mBucketScaleFactor = BUCKET_SCALE_FACTOR_DEFAULT; + + private final Random mRandom; + private BinderLatencyBuckets mLatencyBuckets; + + /** Injector for {@link BinderLatencyObserver}. */ + public static class Injector { + public Random getRandomGenerator() { + return new Random(); + } + } + + public BinderLatencyObserver(Injector injector) { + mRandom = injector.getRandomGenerator(); + mLatencyBuckets = new BinderLatencyBuckets( + mBucketCount, mFirstBucketSize, mBucketScaleFactor); + } + + /** Should be called when a Binder call completes, will store latency data. */ + public void callEnded(@Nullable CallSession s) { + if (s == null || s.exceptionThrown || !shouldKeepSample()) { + return; + } + + LatencyDims dims = new LatencyDims(s.binderClass, s.transactionCode); + long callDuration = getElapsedRealtimeMicro() - s.timeStarted; + + // Find the bucket this sample should go to. + int bucketIdx = mLatencyBuckets.sampleToBucket( + callDuration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) callDuration); + + synchronized (mLock) { + int[] buckets = mLatencyHistograms.get(dims); + if (buckets == null) { + buckets = new int[mBucketCount]; + mLatencyHistograms.put(dims, buckets); + } + + // Increment the correct bucket. + if (buckets[bucketIdx] < Integer.MAX_VALUE) { + buckets[bucketIdx] += 1; + } + } + } + + protected long getElapsedRealtimeMicro() { + return SystemClock.elapsedRealtimeNanos() / 1000; + } + + protected boolean shouldKeepSample() { + return mRandom.nextInt() % mPeriodicSamplingInterval == 0; + } + + /** Updates the sampling interval. */ + public void setSamplingInterval(int samplingInterval) { + if (samplingInterval <= 0) { + Slog.w(TAG, "Ignored invalid sampling interval (value must be positive): " + + samplingInterval); + return; + } + + synchronized (mLock) { + if (samplingInterval != mPeriodicSamplingInterval) { + mPeriodicSamplingInterval = samplingInterval; + reset(); + } + } + } + + /** Updates the histogram buckets parameters. */ + public void setHistogramBucketsParams( + int bucketCount, int firstBucketSize, float bucketScaleFactor) { + synchronized (mLock) { + if (bucketCount != mBucketCount || firstBucketSize != mFirstBucketSize + || bucketScaleFactor != mBucketScaleFactor) { + mBucketCount = bucketCount; + mFirstBucketSize = firstBucketSize; + mBucketScaleFactor = bucketScaleFactor; + mLatencyBuckets = new BinderLatencyBuckets( + mBucketCount, mFirstBucketSize, mBucketScaleFactor); + reset(); + } + } + } + + /** Resets the sample collection. */ + public void reset() { + synchronized (mLock) { + mLatencyHistograms.clear(); + } + } + + /** Container for binder latency information. */ + public static class LatencyDims { + // Binder interface descriptor. + private Class<? extends Binder> mBinderClass; + // Binder transaction code. + private int mTransactionCode; + // Cached hash code, 0 if not set yet. + private int mHashCode = 0; + + public LatencyDims(Class<? extends Binder> binderClass, int transactionCode) { + this.mBinderClass = binderClass; + this.mTransactionCode = transactionCode; + } + + public Class<? extends Binder> getBinderClass() { + return mBinderClass; + } + + public int getTransactionCode() { + return mTransactionCode; + } + + @Override + public boolean equals(final Object other) { + if (other == null || !(other instanceof LatencyDims)) { + return false; + } + LatencyDims o = (LatencyDims) other; + return mTransactionCode == o.getTransactionCode() && mBinderClass == o.getBinderClass(); + } + + @Override + public int hashCode() { + if (mHashCode != 0) { + return mHashCode; + } + int hash = mTransactionCode; + hash = 31 * hash + mBinderClass.hashCode(); + mHashCode = hash; + return hash; + } + } + + @VisibleForTesting + public ArrayMap<LatencyDims, int[]> getLatencyHistograms() { + return mLatencyHistograms; + } +} diff --git a/core/java/com/android/internal/view/OWNERS b/core/java/com/android/internal/view/OWNERS index 851d1f37522a..eb2478f6550a 100644 --- a/core/java/com/android/internal/view/OWNERS +++ b/core/java/com/android/internal/view/OWNERS @@ -18,3 +18,7 @@ per-file AppearanceRegion = file:/services/core/java/com/android/server/wm/OWNER per-file BaseIWIndow.java = file:/services/core/java/com/android/server/wm/OWNERS per-file RotationPolicy.java = file:/services/core/java/com/android/server/wm/OWNERS per-file WindowManagerPolicyThread.java = file:/services/core/java/com/android/server/wm/OWNERS + +# Scroll Capture +per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS +per-file *CaptureHelper*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS diff --git a/core/jni/OWNERS b/core/jni/OWNERS index f6629fd250f6..c0c4b7054674 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -42,6 +42,9 @@ per-file android_os_HwParcel* = file:platform/system/libhwbinder:/OWNERS per-file android_os_HwRemoteBinder* = file:platform/system/libhwbinder:/OWNERS per-file EphemeralStorage* = file:platform/system/libhwbinder:/OWNERS +# Sensor +per-file android_hardware_SensorManager* = arthuri@google.com, bduddie@google.com, stange@google.com + per-file *Zygote* = file:/ZYGOTE_OWNERS per-file fd_utils.* = file:/ZYGOTE_OWNERS per-file Android.bp = file:platform/build/soong:/OWNERS diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 836074f1d5f7..0bed29b7ba28 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -184,6 +184,17 @@ static constexpr int PROCESS_PRIORITY_MIN = 19; /** The numeric value for the normal priority a process should have. */ static constexpr int PROCESS_PRIORITY_DEFAULT = 0; +/** Exponential back off parameters for storage dir check. */ +static constexpr unsigned int STORAGE_DIR_CHECK_RETRY_MULTIPLIER = 2; +static constexpr unsigned int STORAGE_DIR_CHECK_INIT_INTERVAL_US = 50; +static constexpr unsigned int STORAGE_DIR_CHECK_MAX_INTERVAL_US = 1000; +/** + * Lower bound time we allow storage dir check to sleep. + * If it exceeds 2s, PROC_START_TIMEOUT_MSG will kill the starting app anyway, + * so it's fine to assume max retries is 5 mins. + */ +static constexpr int STORAGE_DIR_CHECK_TIMEOUT_US = 1000 * 1000 * 60 * 5; + /** * A helper class containing accounting information for USAPs. */ @@ -1458,6 +1469,31 @@ static void isolateJitProfile(JNIEnv* env, jobjectArray pkg_data_info_list, } } +static void WaitUntilDirReady(const std::string& target, fail_fn_t fail_fn) { + unsigned int sleepIntervalUs = STORAGE_DIR_CHECK_INIT_INTERVAL_US; + + // This is just an approximate value as it doesn't need to be very accurate. + unsigned int sleepTotalUs = 0; + + const char* dir_path = target.c_str(); + while (sleepTotalUs < STORAGE_DIR_CHECK_TIMEOUT_US) { + if (access(dir_path, F_OK) == 0) { + return; + } + // Failed, so we add exponential backoff and retry + usleep(sleepIntervalUs); + sleepTotalUs += sleepIntervalUs; + sleepIntervalUs = std::min<unsigned int>( + sleepIntervalUs * STORAGE_DIR_CHECK_RETRY_MULTIPLIER, + STORAGE_DIR_CHECK_MAX_INTERVAL_US); + } + // Last chance and get the latest errno if it fails. + if (access(dir_path, F_OK) == 0) { + return; + } + fail_fn(CREATE_ERROR("Error dir is not ready %s: %s", dir_path, strerror(errno))); +} + static void BindMountStorageToLowerFs(const userid_t user_id, const uid_t uid, const char* dir_name, const char* package, fail_fn_t fail_fn) { bool hasSdcardFs = IsSdcardfsUsed(); @@ -1468,6 +1504,10 @@ static void BindMountStorageToLowerFs(const userid_t user_id, const uid_t uid, source = StringPrintf("/mnt/pass_through/%d/emulated/%d/%s/%s", user_id, user_id, dir_name, package); } + + // Directory might be not ready, as prepareStorageDirs() is running asynchronously in ProcessList, + // so wait until dir is created. + WaitUntilDirReady(source, fail_fn); std::string target = StringPrintf("/storage/emulated/%d/%s/%s", user_id, dir_name, package); // As the parent is mounted as tmpfs, we need to create the target dir here. diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 991f5dec9f2d..8f6fa7c56ee9 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -5595,6 +5595,10 @@ <!-- Attribution for Gnss Time Update service. --> <attribution android:tag="GnssTimeUpdateService" android:label="@string/gnss_time_update_service"/> + <!-- Attribution for MusicRecognitionManagerService. + <p>Not for use by third-party applications.</p> --> + <attribution android:tag="MusicRecognitionManagerService" + android:label="@string/music_recognition_manager_service"/> <application android:process="system" android:persistent="true" diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 7d7b73166170..f48fc67cdff5 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Skemerdiens"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Tydsonebespeurder (geen konnektiwiteit nie)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS-tydopdateringdiens"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Jou toestel sal uitgevee word"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Die administrasieprogram kan nie gebruik word nie. Jou toestel sal nou uitgevee word.\n\nKontak jou organisasie se administrateur as jy vrae het."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Druk is gedeaktiveer deur <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 254ca9cfad36..59b40852eb31 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"የውጋገን አገልግሎት"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"የሰዓት ሰቅ አንባቢ (ግንኙነት የለም)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"የGNSS ጊዜ ዝመኔ አገልግሎት"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"የእርስዎ መሣሪያ ይደመሰሳል"</string> <string name="factory_reset_message" msgid="2657049595153992213">"የአስተዳዳሪ መተግበሪያ ስራ ላይ ሊውል አይችልም። የእርስዎን መሣሪያ አሁን ይደመሰሳል።\n\nጥያቄዎች ካለዎት የድርጅትዎን አስተዳዳሪ ያነጋግሩ።"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ማተም በ<xliff:g id="OWNER_APP">%s</xliff:g> ተሰናክሏል።"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 89ed573fd1f0..a419bec778b6 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -212,6 +212,8 @@ <string name="twilight_service" msgid="8964898045693187224">"خدمة الغسق"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"أداة التعرّف على المنطقة الزمنية (ليس هناك حاجة للاتصال بالشبكة)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"خدمة تعديل وقت GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"سيتم محو بيانات جهازك."</string> <string name="factory_reset_message" msgid="2657049595153992213">"تعذّر استخدام تطبيق المشرف. سيتم محو بيانات جهازك الآن.\n\nإذا كانت لديك أسئلة، اتصل بمشرف مؤسستك."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"تم إيقاف الطباعة بواسطة <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 67d2ce05a348..f4242a676924 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight সেৱা"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"সময় মণ্ডল চিনাক্তকাৰী (সংযোগ নাই)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS সময় আপডে’ট প্ৰদান কৰা সেৱা"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"আপোনাৰ ডিভাইচৰ ডেটা মচা হ\'ব"</string> <string name="factory_reset_message" msgid="2657049595153992213">"এই প্ৰশাসক এপটো ব্যৱহাৰ কৰিব নোৱাৰি। এতিয়া আপোনাৰ ডিভাইচটোৰ ডেটা মচা হ\'ব।\n\nআপোনাৰ কিবা প্ৰশ্ন থাকিলে আপোনাৰ প্ৰতিষ্ঠানৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"প্ৰিণ্ট কৰা কাৰ্য <xliff:g id="OWNER_APP">%s</xliff:g>এ অক্ষম কৰি ৰাখিছে।"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 76b5f1b9aded..940bb955809b 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Alaqaranlıq Xidməti"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Saat Qurşağı Aşkarlayıcısı (Bağlantı yoxdur)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS Zaman Güncəlləmə Xidməti"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Cihazınız təmizlənəcəkdir"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Admin tətbiqini istifadə etmək mümkün deyil. Cihaz indi təmizlənəcək.\n\nSualınız varsa, təşkilatın admini ilə əlaqə saxlayın."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Çap <xliff:g id="OWNER_APP">%s</xliff:g> tərəfindən deaktiv edildi."</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 97781c7849a9..a97833ad89e2 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -206,6 +206,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Usluga Sumrak"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detektor vremenske zone (nema internet veze)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS usluga za ažuriranje vremena"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti obrisan"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Ne možete da koristite ovu aplikaciju za administratore. Uređaj će sada biti obrisan.\n\nAko imate pitanja, kontaktirajte administratora organizacije."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Štampanje je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 32672472f145..f2e3e2686c7b 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -208,6 +208,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Служба Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Дэтэктар часавога пояса (няма падключэння)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Служба абнаўлення часу GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Даныя вашай прылады будуць сцерты"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Немагчыма выкарыстоўваць праграму адміністравання. Звесткі на вашай прыладзе будуць выдалены.\n\nКалі ў вас ёсць пытанні, звярніцеся да адміністратара арганізацыі."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Друк адключаны ўладальнікам праграмы <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index ac55c913a64e..52ab24279f40 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Услуга Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Инструмент за установяване на часовата зона (няма връзка)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Услуга на GNSS за актуализиране на часа"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Данните на устройството ви ще бъдат изтрити"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Приложението за администриране не може да се използва. Сега данните на устройството ви ще бъдат изтрити.\n\nАко имате въпроси, свържете се с администратора на организацията си."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Отпечатването е деактивиранo от <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index ff25441fbe7d..d9bb45dc3bb5 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"গোধূলি পরিষেবা"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"টাইম জোন ডিটেক্টর (কানেকশন নেই)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS সময় আপডেট পরিষেবা"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"আপনার ডিভাইসটি মুছে ফেলা হবে"</string> <string name="factory_reset_message" msgid="2657049595153992213">"অ্যাডমিন অ্যাপটি ব্যবহার করা যাবে না। আপনার ডিভাইসে থাকা সবকিছু এখন মুছে ফেলা হবে।\n\nকোনও প্রশ্ন থাকলে আপনার প্রতিষ্ঠানের অ্যাডমিনের সাথে যোগাযোগ করুন।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> প্রিন্টিং বন্ধ রেখেছে।"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 25129e489a05..863e12f1a621 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -206,6 +206,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Usluga Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detektor vremenske zone (nije povezan)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS usluga za ažuriranje vremena"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti izbrisan"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Nije moguće koristiti aplikaciju administratora. Potpuno će se izbrisati podaci na vašem uređaju.\n\nAko imate pitanja, obratite se administratoru svoje organizacije."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Štampanje je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 6f2af9203553..0b7dbbc07418 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Servei Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detector de zona horària (sense connectivitat)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Servei GNSS d\'actualització horària"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"El contingut del dispositiu s\'esborrarà"</string> <string name="factory_reset_message" msgid="2657049595153992213">"No es pot utilitzar l\'aplicació d\'administració. S\'esborraran les dades del dispositiu.\n\nSi tens cap dubte, contacta amb l\'administrador de la teva organització."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ha desactivat la impressió."</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index bd9866279e96..d47e7f95f2e0 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -208,6 +208,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Služba detekce soumraku"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detektor časového pásma (bez připojení)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS – služba pro aktualizaci času"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Zařízení bude vymazáno"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Aplikaci pro správu nelze použít. Zařízení teď bude vymazáno.\n\nV případě dotazů vám pomůže administrátor organizace."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Aplikace <xliff:g id="OWNER_APP">%s</xliff:g> tisk zakazuje."</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 70492e01fc1b..46dfb4162ef3 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Tjenesten Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Tidszoneregistrering (ingen forbindelse)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Tjeneste til opdatering af GNSS-tid"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Enheden slettes"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administrationsappen kan ikke bruges. Enheden vil nu blive ryddet. \n\nKontakt din organisations administrator, hvis du har spørgsmål."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Udskrivning er deaktiveret af <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 6e458fa30fd5..bc08e94ed8c4 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Zeitzonen-Erkennung (keine Verbindung)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS-Zeitaktualisierungsdienst"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Die Daten auf deinem Gerät werden gelöscht."</string> <string name="factory_reset_message" msgid="2657049595153992213">"Die Admin-App kann nicht verwendet werden. Die Daten auf deinem Gerät werden nun gelöscht.\n\nBitte wende dich bei Fragen an den Administrator deiner Organisation."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Drucken wurde von <xliff:g id="OWNER_APP">%s</xliff:g> deaktiviert."</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 920f09eb777d..22bc92f72457 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Υπηρεσία Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Εντοπισμός ζώνης ώρας (χωρίς συνδεσιμότητα)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Υπηρεσία ενημέρωσης ώρας GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Η συσκευή σας θα διαγραφεί"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Δεν είναι δυνατή η χρήση της εφαρμογής διαχειριστή. Η συσκευή σας θα διαγραφεί.\n\nΕάν έχετε ερωτήσεις, επικοινωνήστε με τον διαχειριστή του οργανισμού σας."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Η εκτύπωση απενεργοποιήθηκε από τον χρήστη <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 43a7fb6662d6..689d4fa36c96 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Time zone detector (no connectivity)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS time update service"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 04390c74bb32..b015e47f3485 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Time zone detector (no connectivity)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS time update service"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 84224ed85d10..22d57ff2f636 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Time zone detector (no connectivity)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS time update service"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index d740e01c502e..660c3eba2fe2 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Time zone detector (no connectivity)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS time update service"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index aef32a4d55b6..d50f294e858e 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Time Zone Detector (No connectivity)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS Time Update Service"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organization\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-es-rMX/donottranslate-cldr.xml b/core/res/res/values-es-rMX/donottranslate-cldr.xml new file mode 100755 index 000000000000..db438f22208f --- /dev/null +++ b/core/res/res/values-es-rMX/donottranslate-cldr.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="month_day_year">%-e %B %Y</string> + <string name="time_of_day">%H:%M:%S</string> + <string name="date_and_time">%-e %b %Y, %H:%M:%S</string> + <string name="date_time">%1$s, %2$s</string> +</resources> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 6125c167fa7d..b0610726289f 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Servicio de Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detector de zona horaria (sin conexión)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Servicio de actualización de tiempo GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Se borrarán los datos del dispositivo"</string> <string name="factory_reset_message" msgid="2657049595153992213">"No se puede usar la app de administrador. Ahora se borrará tu dispositivo.\n\nSi tienes preguntas, comunícate con el administrador de tu organización."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> inhabilitó la impresión."</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 0e163d2b263b..fabdbc6c034d 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Servicio de Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detector de zona horaria (sin conexión)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Servicio de actualización de tiempo GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Tu dispositivo se borrará"</string> <string name="factory_reset_message" msgid="2657049595153992213">"No se puede utilizar la aplicación de administración. Se borrarán todos los datos del dispositivo.\n\nSi tienes alguna pregunta, ponte en contacto con el administrador de tu organización."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ha inhabilitado la impresión."</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 9f6df6e8ff35..4c646071eaca 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Teenus Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Ajavööndi tuvastaja (ühenduvus puudub)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS-i aja värskendamise teenus"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Seade kustutatakse"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administraatori rakendust ei saa kasutada. Teie seade tühjendatakse nüüd.\n\nKui teil on küsimusi, võtke ühendust organisatsiooni administraatoriga."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Rakendus <xliff:g id="OWNER_APP">%s</xliff:g> on printimise keelanud."</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 72d083363594..e7dfb20d4330 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Ilunabarreko zerbitzua"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Ordu-zonaren hautemailea (ez zaude konektatuta sarera)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS ordua eguneratzeko zerbitzua"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Gailuko datuak ezabatu egingo dira"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Ezin da erabili administratzeko aplikazioa. Ezabatu egingo da gailuko eduki guztia.\n\nZalantzarik baduzu, jarri erakundeko administratzailearekin harremanetan."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> aplikazioak desgaitu egin du inprimatzeko aukera."</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 76d0c1e794f9..8fc5670f4f94 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"سرویس Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"شناساگر منطقه زمانی (بدون اتصال)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"سرویس بهروزرسانی زمان GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"دستگاهتان پاک خواهد شد"</string> <string name="factory_reset_message" msgid="2657049595153992213">"برنامه سرپرست سیستم را نمیتوان استفاده کرد. دستگاه شما در این لحظه پاک میشود.\n\nاگر سؤالی دارید، با سرپرست سیستم سازمانتان تماس بگیرید."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> چاپ کردن را غیرفعال کرده است."</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 2e0d6cddc3d4..143f5c281d5f 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight-palvelu"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Aikavyöhykkeen tunnistin (ei yhteyttä)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS-ajanpäivityspalvelu"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Laitteen tiedot poistetaan"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Hallintasovellusta ei voi käyttää. Laitteen tiedot pyyhitään.\n\nPyydä ohjeita järjestelmänvalvojaltasi."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> on poistanut tulostuksen käytöstä."</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 1ebc60465f47..7e10df4dd06e 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Service de crépuscule"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Détecteur de fuseau horaire (aucune connectivité)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Service d\'actualisation de l\'heure GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Le contenu de votre appareil sera effacé"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, communiquez avec l\'administrateur de votre organisation."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index ce36dbc9ba21..0a5afd487668 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Service Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Outil de détection du fuseau horaire (aucune connectivité)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Service de mise à jour de l\'heure GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Les données de votre appareil vont être effacées"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, contactez l\'administrateur de votre organisation."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 9d95af8badc2..4ebcb3abdadc 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Servizo Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detector de fuso horario (non require conexión)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Servizo de actualización horaria mediante o GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Borrarase o teu dispositivo"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Non se pode utilizar a aplicación de administración. Borrarase o teu dispositivo.\n\nSe tes preguntas, contacta co administrador da organización."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> desactivou a impresión."</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 334ba2d8b532..133a992fa28d 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"ટ્વાઇલાઇટ સેવા"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"સમય ઝોન શોધવાની સુવિધા (કનેક્ટિવિટી જરૂરી નથી)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS સમય અપડેટ કરવાની સેવા"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"તમારું ઉપકરણ કાઢી નાખવામાં આવશે"</string> <string name="factory_reset_message" msgid="2657049595153992213">"વ્યવસ્થાપક ઍપનો ઉપયોગ કરી શકાશે નહીં. તમારું ઉપકરણ હવે કાઢી નાખવામાં આવશે.\n\nજો તમને પ્રશ્નો હોય, તો તમારી સંસ્થાના વ્યવસ્થાપકનો સંપર્ક કરો."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> દ્વારા પ્રિન્ટ કરવાનું બંધ કરાયું છે."</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 16e848f83d6d..85269a31a070 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"ट्वाइलाइट समय बताने वाली सेवा"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"समय क्षेत्र का पता लगाने वाली सुविधा (ऑफ़लाइन होने पर)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS समय अपडेट सेवा"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"आपके डिवाइस को मिटा दिया जाएगा"</string> <string name="factory_reset_message" msgid="2657049595153992213">"एडमिन ऐप्लिकेशन का इस्तेमाल नहीं किया जा सकता. आपके डिवाइस पर मौजूद डेटा अब मिटा दिया जाएगा.\n\nअगर आप कुछ पूछना चाहते हैं तो, अपने संगठन के एडमिन से संपर्क करें."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ने प्रिंटिंग सुविधा बंद कर दी है."</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 15c36c9ba604..7aca352ad0b3 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -206,6 +206,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Usluga Sumrak"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detektor vremenske zone (nije povezan)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS – usluga ažuriranja vremena"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će se izbrisati"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administratorska aplikacija ne može se upotrebljavati. Uređaj će se izbrisati.\n\nAko imate pitanja, obratite se administratoru organizacije."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Ispis je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index f28f1b66518f..9e8c2f38995f 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight szolgáltatás"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Időzóna-felismerő (Offline)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS időfrissítési szolgáltatás"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"A rendszer törölni fogja eszközét"</string> <string name="factory_reset_message" msgid="2657049595153992213">"A rendszergazdai alkalmazás nem használható. A rendszer most törli az eszközt.\n\nKérdéseivel forduljon szervezete rendszergazdájához."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"A(z) <xliff:g id="OWNER_APP">%s</xliff:g> letiltotta a nyomtatást."</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 959cb572333e..368ef26e4d56 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Մթնշաղի սկիզբը որոշող ծառայություն"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Ժամային գոտու դետեկտոր (աշխատում է առանց ինտերնետի)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Ժամանակի թարմացման GNSS ծառայություն"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Ձեր սարքը ջնջվելու է"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Հնարավոր չէ օգտագործել ադմինիստրատորի հավելվածը։ Ձեր սարքից բոլոր տվյալները կջնջվեն։\n\nՀարցեր ունենալու դեպքում դիմեք ձեր կազմակերպության ադմինիստրատորին։"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Տպումն անջատված է <xliff:g id="OWNER_APP">%s</xliff:g> հավելվածի կողմից։"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 9f692098f12a..7f10e80acdfc 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Layanan Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Pendeteksi Zona Waktu (Tidak ada konektivitas)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Layanan Pembaruan Waktu GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Perangkat akan dihapus"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Aplikasi admin tidak dapat digunakan. Perangkat Anda kini akan dihapus.\n\nJika ada pertanyaan, hubungi admin organisasi."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Fitur pencetakan dinonaktifkan oleh <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 0e11f033b033..4b96c038f67c 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Ljósaskiptaþjónusta"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Tímabeltisgreinir (engin tenging)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Tímastillingarþjónusta hnattræna gervihnattaleiðsögukerfisins (GNSS)"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Tækið verður hreinsað"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Ekki er hægt að nota stjórnunarforritið. Tækinu verður eytt.\n\nEf spurningar vakna skaltu hafa samband við kerfisstjóra fyrirtækisins."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> lokaði á prentun."</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index b41996e4cb58..9c541f493055 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Servizio Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Rilevatore di fuso orario (connessione a Internet non necessaria)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Servizio di aggiornamento dell\'orario GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Il dispositivo verrà resettato"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Impossibile usare l\'app di amministrazione. Il dispositivo verrà resettato.\n\nPer eventuali domande, contatta l\'amministratore della tua organizzazione."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Stampa disattivata da <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index be05cc00c3b0..0c18fa303c2e 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -208,6 +208,8 @@ <string name="twilight_service" msgid="8964898045693187224">"שירות דמדומים"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"מזהה אזור זמן (ללא צורך בקישוריות)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"שירות עדכון הזמן של GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"תתבצע מחיקה של המכשיר"</string> <string name="factory_reset_message" msgid="2657049595153992213">"לא ניתן להשתמש באפליקציה של מנהל המערכת.\n\nאם יש לך שאלות, יש ליצור קשר עם מנהל המערכת של הארגון."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ההדפסה הושבתה על ידי <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index e7c343872b95..1c10c009139d 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"トワイライト サービス"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Time Zone Detector(未接続)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS 時間アップデートサービス"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"デバイスのデータが消去されます"</string> <string name="factory_reset_message" msgid="2657049595153992213">"管理アプリを使用できません。デバイスのデータはこれから消去されます。\n\nご不明な点がある場合は、組織の管理者にお問い合わせください。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」により印刷は無効にされています。"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 3fb6c6954a98..8eea56d0b3b4 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight სერვისი"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"სასაათო სარტყლის დეტექტორი (კავშირის გარეშე)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS დროის განახლების სერვისი"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"თქვენი მოწყობილობა წაიშლება"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ადმინისტრატორის აპის გამოყენება ვერ მოხერხდება. თქვენი მოწყობილობა ახლა ამოიშლება.\n\nთუ შეკითხვები გაქვთ, დაუკავშირდით თქვენი ორგანიზაციის ადმინისტრატორს."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ბეჭდვა გათიშულია <xliff:g id="OWNER_APP">%s</xliff:g>-ის მიერ."</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 4404603f09fc..d95e401093c7 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight қызметі"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Уақыт белдеуін анықтағыш (қосылу мүмкіндігі жоқ)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS уақыт жаңарту жүйесі"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Құрылғыңыздағы деректер өшіріледі"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Әкімші қолданбасын пайдалану мүмкін емес. Қазір құрылғыдағы деректер өшіріледі\n\nСұрақтарыңыз болса, ұйым әкімшісіне хабарласыңыз."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Басып шығаруды <xliff:g id="OWNER_APP">%s</xliff:g> өшірді."</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index fb1155318137..66604ff4d74f 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"សេវាកម្មព្រលប់"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"ឧបករណ៍សម្គាល់ល្វែងម៉ោង (គ្មានការតភ្ជាប់ទេ)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"សេវាកម្មធ្វើបច្ចុប្បន្នភាពពេលវេលា GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"ឧបករណ៍របស់អ្នកនឹងត្រូវបានលុប"</string> <string name="factory_reset_message" msgid="2657049595153992213">"មិនអាចប្រើកម្មវិធីអ្នកគ្រប់គ្រងបានទេ។ ឧបករណ៍របស់អ្នកនឹងលុបឥឡូវនេះ។\n\nប្រសិនបើអ្នកមានសំណួរផ្សេងៗ សូមទាក់ទងទៅអ្នកគ្រប់គ្រងស្ថាប័នរបស់អ្នក។"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ការបោះពុម្ពត្រូវបានបិទដោយ <xliff:g id="OWNER_APP">%s</xliff:g> ។"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index f484344d7891..a3883af8fbfe 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"ಟ್ವಿಲೈಟ್ ಸೇವೆ"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"ಸಮಯವಲಯ ಡಿಟೆಕ್ಟರ್ (ಯಾವುದೇ ಸಂಪರ್ಕ ಕಲ್ಪಿಸುವಿಕೆ ಇಲ್ಲ)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS ಸಮಯದ ಅಪ್ಡೇಟ್ ಸೇವೆ"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ನಿರ್ವಹಣೆ ಅಪ್ಲಿಕೇಶನ್ ಬಳಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ನಿಮ್ಮ ಸಾಧನವನ್ನು ಇದೀಗ ಅಳಿಸಲಾಗುತ್ತದೆ.\n\nನಿಮ್ಮಲ್ಲಿ ಪ್ರಶ್ನೆಗಳಿದ್ದರೆ, ನಿಮ್ಮ ಸಂಸ್ಥೆಯ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ಮೂಲಕ ಪ್ರಿಂಟಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 78cc1b572e04..5db741ebcac7 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"새벽 서비스"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"시간대 감지(연결되지 않음)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS 시간 업데이트 서비스"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"기기가 삭제됩니다."</string> <string name="factory_reset_message" msgid="2657049595153992213">"관리자 앱을 사용할 수 없습니다. 곧 기기가 삭제됩니다.\n\n궁금한 점이 있으면 조직의 관리자에게 문의하세요."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g>에 의해 사용 중지되었습니다."</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 5d8b8980d2f5..31f39f1f0f97 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight кызматы"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Убакыт алкагын аныктагыч (байланыш жок)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS Убакытты жаңыртуу кызматы"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Түзмөгүңүз тазаланат"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Түзмөктү башкаруучу колдонмо жараксыз. Түзмөгүңүз азыр тазаланат.\n\nСуроолоруңуз болсо, ишканаңыздын администраторуна кайрылыңыз."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Басып чыгаруу <xliff:g id="OWNER_APP">%s</xliff:g> тарабынан өчүрүлдү."</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index fcf47edbfc47..fa5450edf40f 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"ບໍລິການ Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"ຕົວກວດຫາເຂດເວລາ (ບໍ່ມີການເຊື່ອມຕໍ່)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"ບໍລິການອັບເດດເວລາ GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"ອຸປະກອນຂອງທ່ານຈະຖືກລຶບ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ບໍ່ສາມາດໃຊ້ແອັບຜູ້ເບິ່ງແຍງລະບົບໄດ້. ອຸປະກອນຂອງທ່ານຈະຖືກລຶບຂໍ້ມູນໃນຕອນນີ້.\n\nຫາກທ່ານມີຄຳຖາມ, ໃຫ້ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບອົງກອນຂອງທ່ານ."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ການພິມຖືກປິດໄວ້ໂດຍ <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 4afef3be17d4..dd269b9d387b 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -208,6 +208,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Paslauga „Twilight“"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Laiko juostos aptikimo priemonė (nėra ryšio)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS laiko atnaujinimo paslauga"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Įrenginys bus ištrintas"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administratoriaus programos negalima naudoti. Dabar įrenginio duomenys bus ištrinti.\n\nJei turite klausimų, susisiekite su organizacijos administratoriumi."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Neleidžiama spausdinti (<xliff:g id="OWNER_APP">%s</xliff:g>)."</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 8fbfb279daf9..da70930c598c 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -206,6 +206,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Krēslas noteikšanas pakalpojums"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Laika joslas noteikšanas rīks (nav savienojuma)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS laika atjaunināšanas pakalpojums"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Jūsu ierīces dati tiks dzēsti"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administratora lietotni nevar izmantot. Ierīcē saglabātie dati tiks dzēsti.\n\nJa jums ir kādi jautājumi, sazinieties ar savas organizācijas administratoru."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Drukāšanu atspējoja <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 9d07234910fe..ce9bdeb37963 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Услуга за самрак"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Откривач на временска зона (не може да се поврзе)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Услуга за ажурирање на времето на GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Уредот ќе се избрише"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Апликацијата на администраторот не може да се користи. Уредот ќе се избрише сега.\n\nАко имате прашања, контактирајте со администраторот на организацијата."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Печатењето е оневозможено од <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 8d91c5182b16..4cd395536ab9 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"സന്ധ്യാസമയത്തെ സേവനം"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"സമയമേഖല കണ്ടെത്താനുള്ള സംവിധാനം (കണക്റ്റിവിറ്റി ഇല്ല)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS സമയ അപ്ഡേറ്റ് സേവനം"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"നിങ്ങളുടെ ഉപകരണം മായ്ക്കും"</string> <string name="factory_reset_message" msgid="2657049595153992213">"അഡ്മിൻ ആപ്പ് ഉപയോഗിക്കാനാകില്ല. നിങ്ങളുടെ ഉപകരണം ഇപ്പോൾ മായ്ക്കപ്പെടും.\n\nനിങ്ങൾക്ക് ചോദ്യങ്ങൾ ഉണ്ടെങ്കിൽ, നിങ്ങളുടെ സ്ഥാപനത്തിന്റെ അഡ്മിനെ ബന്ധപ്പെടുക."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> പ്രിന്റിംഗ് പ്രവർത്തനരഹിതമാക്കി."</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index faec2be635ba..1f49f9cd1208 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight үйлчилгээ"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Цагийн бүс илрүүлэгч (Холболт байхгүй)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS Хугацаа шинэчлэлтийн үйлчилгээ"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Таны төхөөрөмж устах болно."</string> <string name="factory_reset_message" msgid="2657049595153992213">"Админ аппыг ашиглах боломжгүй. Таны төхөөрөмжийг одоо устгана.\n\nХэрэв танд асуулт байгаа бол байгууллагынхаа админтай холбогдоно уу."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> хэвлэх үйлдлийг идэвхгүй болгосон."</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 102c469ad21d..49d056d56318 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"ट्वायलाइट सेवा"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"टाइम झोन डिटेक्टर (कनेक्टिव्हिटी नाही)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS ची वेळ अपडेट करणारी सेवा"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"तुमचे डिव्हाइस मिटविले जाईल"</string> <string name="factory_reset_message" msgid="2657049595153992213">"प्रशासक अॅप वापरता येणार नाही. तुमचे डिव्हाइस आता साफ केले जाईल.\n\nतुम्हाला कुठलेही प्रश्न असल्यास, तुमच्या संस्थेच्या प्रशासकाशी संपर्क साधा."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> नी प्रिंट करणे बंद केले आहे."</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 3bf30638d95a..7bb1bc7104ee 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Perkhidmatan Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Pengesan Zon Waktu (Tiada kesambungan)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Perkhidmatan Kemaskinian Waktu GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Peranti anda akan dipadam"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Apl pentadbir tidak dapat digunakan. Peranti anda akan dipadamkan sekarang.\n\nJika anda ingin mengemukakan soalan, hubungi pentadbir organisasi anda."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Pencetakan dilumpuhkan oleh <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index f301483c6b56..e7c71fa21fa0 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"နေဝင်ဆည်းဆာ ဝန်ဆောင်မှု"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"ဒေသစံတော်ချိန် ရှာဖွေစနစ် (ချိတ်ဆက်နိုင်မှု မလိုပါ)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS အချိန်အပ်ဒိတ် ဝန်ဆောင်မှု"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"သင့်ကိရိယာအား ပယ်ဖျက်လိမ့်မည်"</string> <string name="factory_reset_message" msgid="2657049595153992213">"စီမံခန့်ခွဲမှု အက်ပ်ကို သုံး၍မရပါ။ သင်၏ စက်ပစ္စည်းအတွင်းရှိ အရာများကို ဖျက်လိုက်ပါမည်\n\nမေးစရာများရှိပါက သင့်အဖွဲ့အစည်း၏ စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> က ပုံနှိပ်ထုတ်ယူခြင်းကို ပိတ်ထားသည်။"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 07cf9c06f8fe..89ef8a3cc57f 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Tidssoneoppdagelse (ingen tilkobling)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS-tjeneste for tidsoppdatering"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Enheten blir slettet"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administratorappen kan ikke brukes. Enheten din blir nå tømt.\n\nTa kontakt med administratoren for organisasjonen din hvis du har spørsmål."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> har slått av utskrift."</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 6295d4455ac2..0b319cce389e 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"ट्वाइलाइट सेवा"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"समय क्षेत्र पत्ता लगाउने सुविधा (नेटवर्क कनेक्सन नहुँदा)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS को समय अपडेट गर्ने सेवा"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"तपाईंको यन्त्र मेटिनेछ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"प्रशासकको एप प्रयोग गर्न मिल्दैन। तपाईंको यन्त्रको डेटा अब मेटाइने छ।\n\nतपाईंसँग प्रश्नहरू भएका खण्डमा आफ्नो संगठनका प्रशासकसँग सम्पर्क गर्नुहोस्।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ले छाप्ने कार्यलाई असक्षम पार्यो।"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 46880ea78016..e2409eaee62e 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Service voor schemering"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Tijdzonedetector (Geen verbinding)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Updateservice voor GNSS-tijd"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Je apparaat wordt gewist"</string> <string name="factory_reset_message" msgid="2657049595153992213">"De beheer-app kan niet worden gebruikt. Je apparaat wordt nu gewist.\n\nNeem contact op met de beheerder van je organisatie als je vragen hebt."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Afdrukken uitgeschakeld door <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 7d65cde300bd..f845cedd0cf8 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"ଟ୍ୱିଲାଇଟ୍ ସର୍ଭିସ୍"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"ଟାଇମ୍ ଜୋନ୍ ଡିଟେକ୍ଟର୍ (କୌଣସି ସଂଯୋଗ ନାହିଁ)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS ସମୟ ଅପଡେଟ୍ ସେବା"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"ଆପଣଙ୍କ ଡିଭାଇସ୍ ବର୍ତ୍ତମାନ ଲିଭାଯିବ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ଆଡମିନ୍ ଆପ୍ ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ। ଆପଣଙ୍କ ଡିଭାଇସ୍ର ସମସ୍ତ ଡାଟାକୁ ବର୍ତ୍ତମାନ ଲିଭାଇଦିଆଯିବ। \n\nଯଦି ଆପଣଙ୍କର କୌଣସି ପ୍ରଶ୍ନ ରହିଥାଏ, ଆପଣଙ୍କ ସଂସ୍ଥାର ଆଡମିନ୍ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ଦ୍ଵାରା ପ୍ରିଣ୍ଟିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 26861dd06e34..026734c8da66 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"ਟਵੀਲਾਈਟ ਸੇਵਾ"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"ਸਮਾਂ ਖੇਤਰ ਦਾ ਪਤਾ ਲਗਾਉਣ ਦੀ ਸੁਵਿਧਾ (ਕੋਈ ਕਨੈਕਟੀਵਿਟੀ ਨਹੀਂ)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS ਸਮਾਂ ਅੱਪਡੇਟ ਸੇਵਾ"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਮਿਟਾਇਆ ਜਾਏਗਾ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਵਰਤੀ ਨਹੀਂ ਜਾ ਸਕਦੀ। ਹੁਣ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦਾ ਡਾਟਾ ਮਿਟਾਇਆ ਜਾਵੇਗਾ।\n\nਜੇਕਰ ਤੁਹਾਡੇ ਕੋਲ ਕੋਈ ਸਵਾਲ ਹਨ, ਤਾਂ ਆਪਣੀ ਸੰਸਥਾ ਦੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ਵੱਲੋਂ ਪ੍ਰਿੰਟ ਕਰਨਾ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 4b183205b14c..99b2aab0d81d 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -208,6 +208,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Usługa Zmierzch"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Wykrywanie strefy czasowej (brak połączenia)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Usługa synchronizacji czasu na podstawie sygnału GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Twoje urządzenie zostanie wyczyszczone"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Nie można użyć aplikacji administratora. Dane z urządzenia zostaną wykasowane.\n\nJeśli masz pytania, skontaktuj się z administratorem organizacji."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Drukowanie wyłączone przez: <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 7d028f91b23f..862b9816f972 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Serviço de crepúsculo"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detector de fuso horário (sem conectividade)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Serviço de atualização de horário do Sistema Global de Navegação por Satélites (GNSS, na sigla em inglês)"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Seu dispositivo será limpo"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Não é possível usar o aplicativo para administrador. Seu dispositivo passará por uma limpeza agora.\n\nEm caso de dúvidas, entre em contato com o administrador da sua organização."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index a01db5e3fca6..19733b6d55f3 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Serviço de crepúsculo"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detetor do fuso horário (sem conetividade)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Serviço de atualização da hora GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"O seu dispositivo será apagado"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Não é possível utilizar a app de administrador. O seu dispositivo será agora apagado.\n\nSe tiver questões, contacte o administrador da entidade."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 7d028f91b23f..862b9816f972 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Serviço de crepúsculo"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detector de fuso horário (sem conectividade)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Serviço de atualização de horário do Sistema Global de Navegação por Satélites (GNSS, na sigla em inglês)"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Seu dispositivo será limpo"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Não é possível usar o aplicativo para administrador. Seu dispositivo passará por uma limpeza agora.\n\nEm caso de dúvidas, entre em contato com o administrador da sua organização."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index e8c553908c29..c75b260b914f 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -206,6 +206,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Serviciul Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detector de fus orar (fără conexiune)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Serviciul de actualizare a orei bazat pe GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Datele de pe dispozitiv vor fi șterse"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Aplicația de administrare nu poate fi utilizată. Dispozitivul va fi șters.\n\nDacă aveți întrebări, contactați administratorul organizației dvs."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printare dezactivată de <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 48f96ef3d289..f297e1e462c6 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -208,6 +208,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Сервис для определения наступления сумерек"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Определитель часового пояса (работает без Интернета)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Синхронизация времени с помощью ГНСС"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Все данные с устройства будут удалены"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Невозможно использовать приложение для администрирования. С устройства будут удалены все данные.\n\nЕсли у вас возникли вопросы, обратитесь к администратору."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Функция печати отключена приложением \"<xliff:g id="OWNER_APP">%s</xliff:g>\""</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index e01a1c446614..417ce982eb25 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"ඇඳිරි සේවාව"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"වේලා කලාප අනාවරකය (සම්බන්ධතාවක් නොමැත)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS වේලා යාවත්කාලීන සේවාව"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"ඔබගේ උපාංගය මකා දැමෙනු ඇත"</string> <string name="factory_reset_message" msgid="2657049595153992213">"පරිපාලක යෙදුම භාවිතා කළ නොහැකිය. ඔබේ උපාංගය දැන් මකා දමනු ඇත.\n\nඔබට ප්රශ්න තිබේ නම්, ඔබේ සංවිධානයේ පරිපාලකට අමතන්න."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> විසින් මුද්රණය කිරීම අබල කර ඇත."</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index f645fe10f3bc..7d87136f5d8b 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -208,6 +208,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Služba stmievania"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detektor časového pásma (bez pripojenia)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Služba na aktualizáciu času globálneho družicového polohového systému"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Vaše zariadenie bude vymazané"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Daná aplikácia na správu sa nedá použiť. Vaše zariadenie bude vymazané.\n\nV prípade otázok kontaktujte správcu organizácie."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Tlač zakázala aplikácia <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 97de6a370883..6aeac96f8ac2 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -208,6 +208,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Storitev Somrak"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Zaznavanje časovnega pasu (brez povezave)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Storitev posodobitve ure po sistemu GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Podatki v napravi bodo izbrisani"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Skrbniške aplikacije ni mogoče uporabljati. Podatki v napravi bodo izbrisani.\n\nČe imate vprašanja, se obrnite na skrbnika organizacije."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Tiskanje je onemogočil pravilnik <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index a78ff777258e..ab71512fb705 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Shërbimi i muzgut"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Zbuluesi i brezit orar (nuk nevojitet lidhja)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Shërbimi i përditësimit të kohës GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Pajisja do të spastrohet"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Aplikacioni i administratorit nuk mund të përdoret. Pajisja jote tani do të fshihet.\n\nNëse ke pyetje, kontakto me administratorin e organizatës."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printimi është çaktivizuar nga <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 04bc35f5a2d1..34fb8eb65ed0 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -206,6 +206,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Услуга Сумрак"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Детектор временске зоне (нема интернет везе)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS услуга за ажурирање времена"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Уређај ће бити обрисан"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Не можете да користите ову апликацију за администраторе. Уређај ће сада бити обрисан.\n\nАко имате питања, контактирајте администратора организације."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Штампање је онемогућила апликација <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 5ab243a042e1..9eca4237a35b 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Tidszondetektering (ingen anslutning)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Tjänst för uppdatering av GNSS-tid"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Enheten kommer att rensas"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Det går inte att använda administratörsappen. Enheten rensas.\n\nKontakta organisationens administratör om du har några frågor."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Utskrift har inaktiverats av <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 00477d1b1f5f..c4700dce6f07 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Kitambua Saa za Eneo (Hakuna muunganisho)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Huduma ya Kusasisha Saa za GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Data iliyomo kwenye kifaa chako itafutwa"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Huwezi kutumia programu ya msimamizi. Sasa data iliyo kwenye kifaa chako itafutwa.\n\nIkiwa una maswali yoyote, wasiliana na msimamizi wa shirika lako."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Kipengele cha kuchapisha kimezimwa na <xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 6325c191eea3..5463179bde98 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight சேவை"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"நேர மண்டல டிடெக்டர் (இணைப்பு இல்லை)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS நேரப் புதுப்பிப்புச் சேவை"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"சாதனத் தரவு அழிக்கப்படும்"</string> <string name="factory_reset_message" msgid="2657049595153992213">"நிர்வாகி ஆப்ஸை உபயோகிக்க முடியாது. இப்போது, உங்கள் சாதனம் ஆரம்ப நிலைக்கு மீட்டமைக்கப்படும்.\n\nஏதேனும் கேள்விகள் இருப்பின், உங்கள் நிறுவனத்தின் நிர்வாகியைத் தொடர்புகொள்ளவும்."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"பிரிண்ட் செய்வதை <xliff:g id="OWNER_APP">%s</xliff:g> தடுத்துள்ளது."</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index c2a5d42b6a25..4e697dd4627b 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"ట్విలైట్ సర్వీస్"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"టైమ్ జోన్ డిటెక్టర్ (కనెక్టివిటీ లేదు)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS సమయ అప్డేట్ సర్వీస్"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"మీ పరికరంలోని డేటా తొలగించబడుతుంది"</string> <string name="factory_reset_message" msgid="2657049595153992213">"నిర్వాహక యాప్ ఉపయోగించడం సాధ్యపడదు. మీ పరికరంలోని డేటా ఇప్పుడు తొలగించబడుతుంది.\n\nమీకు ప్రశ్నలు ఉంటే, మీ సంస్థ యొక్క నిర్వాహకులను సంప్రదించండి."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ముద్రణ <xliff:g id="OWNER_APP">%s</xliff:g> ద్వారా నిలిపివేయబడింది."</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index a5cfe4028a39..98085c804fc2 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"ตัวตรวจจับเขตเวลา (ไม่มีการเชื่อมต่อ)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"บริการอัปเดตเวลาของ GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"ระบบจะลบข้อมูลในอุปกรณ์ของคุณ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ใช้แอปผู้ดูแลระบบนี้ไม่ได้ ขณะนี้ระบบจะลบข้อมูลในอุปกรณ์ของคุณ\n\nโปรดติดต่อผู้ดูแลระบบขององค์กรหากมีคำถาม"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ปิดใช้การพิมพ์แล้ว"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 4829cefe1940..66737877aacd 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Serbisyo ng Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Detector ng Time Zone (Walang koneksyon)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Serbisyo sa Pag-update ng Oras ng GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Buburahin ang iyong device"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Hindi magamit ang admin app. Mabubura na ang iyong device.\n\nKung mayroon kang mga tanong, makipag-ugnayan sa admin ng iyong organisasyon."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Na-disable ng <xliff:g id="OWNER_APP">%s</xliff:g> ang pag-print."</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 186ffa7c8206..9f0173322fbf 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Alacakaranlık Hizmeti"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Zaman Dilimi Algılayıcı (Bağlantı yok)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS Zaman Güncelleme Hizmeti"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Cihazınız silinecek"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Yönetim uygulaması kullanılamıyor. Cihazınız şimdi silinecek.\n\nSorularınız varsa kuruluşunuzun yöneticisine başvurun."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Yazdırma işlemi <xliff:g id="OWNER_APP">%s</xliff:g> tarafından devre dışı bırakıldı."</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 7049a2e11110..096a79f17180 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -208,6 +208,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Сервіс \"Сутінки\""</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Визначення часового поясу (без Інтернету)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Сервіс оновлення часу GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"З вашого пристрою буде стерто всі дані"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Не можна запускати додаток для адміністраторів. Буде відновлено заводські налаштування пристрою.\n\nЯкщо у вас є запитання, зв’яжіться з адміністратором своєї організації."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Додаток <xliff:g id="OWNER_APP">%s</xliff:g> вимкнув друк."</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 615e2fa4a831..b694a7c30151 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"شفقی سروس"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"ٹائم زون ڈیٹیکٹر (کوئی کنیکٹوٹی نہیں ہے)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS کی ٹائم اپ ڈیٹ سروس"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"آپ کا آلہ صاف کر دیا جائے گا"</string> <string name="factory_reset_message" msgid="2657049595153992213">"منتظم کی ایپ استعمال نہیں کی جا سکتی۔ آپ کا آلہ اب مٹا دیا جائے گا۔\n\nاگر آپ کے سوالات ہیں تو اپنی تنظیم کے منتظم سے رابطہ کریں۔"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> نے پرنٹنگ کو غیر فعال کر دیا ہے۔"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index 0bcba068ffa3..113909c6a172 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight xizmati"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Vaqt mintaqasini aniqlagich (Oflayn)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS yordamida vaqtni yangilash xizmati"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Qurilmangizdagi ma’lumotlar o‘chirib tashlanadi"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administrator ilovasini ishlatib bo‘lmaydi. Qurilmada barcha ma’lumotlar o‘chirib tashlanadi.\n\nSavollaringiz bo‘lsa, administrator bilan bog‘laning."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Chop etish funksiyasi <xliff:g id="OWNER_APP">%s</xliff:g> tomonidan faolsizlantirilgan."</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 11644d6dba9a..c459a3232d32 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Dịch vụ Twilight"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Trình phát hiện múi giờ (Không có kết nối)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Dịch vụ cập nhật thời gian GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Thiết bị của bạn sẽ bị xóa"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Không thể sử dụng ứng dụng quản trị. Thiết bị của bạn sẽ bị xóa ngay bây giờ.\n\nHãy liên hệ với quản trị viên của tổ chức nếu bạn có thắc mắc."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> đã tắt tính năng in."</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index ec455bc07ab0..150fa2588e3a 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight 服务"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"时区检测器(无网络连接)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS 时间更新服务"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"系统将清空您的设备"</string> <string name="factory_reset_message" msgid="2657049595153992213">"无法使用管理应用,系统现在将清空您的设备。\n\n如有疑问,请与您所在单位的管理员联系。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"“<xliff:g id="OWNER_APP">%s</xliff:g>”已停用打印功能。"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 16b9b0fe31e4..48c688a4d068 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"暮光服務"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"時區偵測器 (沒有連線)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS 時間更新服務"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"您的裝置將被清除"</string> <string name="factory_reset_message" msgid="2657049595153992213">"無法使用管理員應用程式。系統會現在清除您的裝置。\n\n如有任何疑問,請聯絡您的機構管理員。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」暫停了列印。"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 90fe15d144c4..2e0283764378 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Twilight 服務"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"時區偵測器 (不必連上網路)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS 時間更新服務"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"你的裝置資料將遭到清除"</string> <string name="factory_reset_message" msgid="2657049595153992213">"無法使用管理應用程式,系統現在將清除你裝置中的資料。\n\n如有任何問題,請與貴機構的管理員聯絡。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」已停用列印功能。"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 1089f1e4b1c5..0cbfa545c29f 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -204,6 +204,8 @@ <string name="twilight_service" msgid="8964898045693187224">"Isevisi Yangovivi"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Isitholi Sezoni Yesikhathi (Akukho ukuxhumana)"</string> <string name="gnss_time_update_service" msgid="9039489496037616095">"Isevisi Ebuyekeziwe Yesikhathi se-GNSS"</string> + <!-- no translation found for music_recognition_manager_service (7481956037950276359) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"Idivayisi yakho izosulwa"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Uhlelo lokusebenza lomlawuli alikwazi ukusetshenziswa. Idivayisi yakho manje izosuswa.\n\nUma unemibuzo, xhumana nomlawuli wezinhlangano zakho."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Ukuphrinta kukhutshazwe nge-<xliff:g id="OWNER_APP">%s</xliff:g>."</string> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 293018d881d8..297f6cb4aac5 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3182,6 +3182,26 @@ </public-group> <!-- =============================================================== + Resources added in version T of the platform + + NOTE: add <public> elements within a <public-group> like so: + + <public-group type="attr" first-id="0x01010531"> + <public name="exampleAttr1" /> + <public name="exampleAttr2" /> + </public-group> + + To add a new public-group block, choose an id value that is 1 greater + than the last of that item above. For example, the last "attr" id + value above is 0x01010530, so the public-group of attrs below has + the id value of 0x01010531. + =============================================================== --> + <eat-comment /> + + <public-group type="attr" first-id="0x01010640"> + </public-group> + + <!-- =============================================================== DO NOT ADD UN-GROUPED ITEMS HERE Any new items (attrs, styles, ids, etc.) *must* be added in a diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 2ffa29b53331..132b72b3047d 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -453,6 +453,9 @@ <!-- Attribution for Gnss Time Update service. [CHAR LIMIT=NONE]--> <string name="gnss_time_update_service">GNSS Time Update Service</string> + <!-- Attribution for MusicRecognitionManagerService. [CHAR LIMIT=NONE]--> + <string name="music_recognition_manager_service">Music Recognition Manager Service</string> + <!-- Factory reset warning dialog strings--> <skip /> <!-- Shows up in the dialog's title to warn about an impeding factory reset. [CHAR LIMIT=NONE] --> <string name="factory_reset_warning">Your device will be erased</string> diff --git a/core/tests/coretests/src/android/view/OWNERS b/core/tests/coretests/src/android/view/OWNERS index 80165f065995..fa1aa5eab26c 100644 --- a/core/tests/coretests/src/android/view/OWNERS +++ b/core/tests/coretests/src/android/view/OWNERS @@ -9,3 +9,6 @@ per-file *Focus* = file:/services/core/java/com/android/server/wm/OWNERS per-file *Insets* = file:/services/core/java/com/android/server/wm/OWNERS per-file *View* = file:/services/core/java/com/android/server/wm/OWNERS per-file *Visibility* = file:/services/core/java/com/android/server/wm/OWNERS + +# Scroll Capture +per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS 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 d9012f649dd3..4c58ad3d7f8d 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -154,8 +154,8 @@ public class ChooserActivityTest { sOverrides.reset(); sOverrides.createPackageManager = mPackageManagerOverride; DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.APPEND_DIRECT_SHARE_ENABLED, - Boolean.toString(false), + SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI, + Boolean.toString(true), true /* makeDefault*/); } @@ -1017,7 +1017,7 @@ public class ChooserActivityTest { assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_DEFAULT), is(testBaseScore)); assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_CHOOSER_TARGET), is(testBaseScore)); assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE), - is(SHORTCUT_TARGET_SCORE_BOOST)); + is(testBaseScore * SHORTCUT_TARGET_SCORE_BOOST)); assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER), is(testBaseScore * SHORTCUT_TARGET_SCORE_BOOST)); } @@ -1262,6 +1262,126 @@ public class ChooserActivityTest { .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(0)); } + @Test + public void testShortcutTargetWithApplyAppLimits() throws InterruptedException { + // Set up resources + sOverrides.resources = Mockito.spy( + InstrumentationRegistry.getInstrumentation().getContext().getResources()); + when(sOverrides.resources.getInteger(R.integer.config_maxShortcutTargetsPerApp)) + .thenReturn(1); + Intent sendIntent = createSendTextIntent(); + // We need app targets for direct targets to get displayed + List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); + when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); + // Create direct share target + List<ChooserTarget> serviceTargets = createDirectShareTargets(2, + resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName); + ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0); + + // Start activity + final ChooserWrapperActivity activity = mActivityRule + .launchActivity(Intent.createChooser(sendIntent, null)); + + // Insert the direct share target + Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>(); + List<ShareShortcutInfo> shortcutInfos = createShortcuts(activity); + directShareToShortcutInfos.put(serviceTargets.get(0), + shortcutInfos.get(0).getShortcutInfo()); + directShareToShortcutInfos.put(serviceTargets.get(1), + shortcutInfos.get(1).getShortcutInfo()); + InstrumentationRegistry.getInstrumentation().runOnMainSync( + () -> activity.getAdapter().addServiceResults( + activity.createTestDisplayResolveInfo(sendIntent, + ri, + "testLabel", + "testInfo", + sendIntent, + /* resolveInfoPresentationGetter */ null), + serviceTargets, + TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE, + directShareToShortcutInfos, + List.of()) + ); + // Thread.sleep shouldn't be a thing in an integration test but it's + // necessary here because of the way the code is structured + // TODO: restructure the tests b/129870719 + Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS); + + assertThat("Chooser should have 3 targets (2 apps, 1 direct)", + activity.getAdapter().getCount(), is(3)); + assertThat("Chooser should have exactly one selectable direct target", + activity.getAdapter().getSelectableServiceTargetCount(), is(1)); + assertThat("The resolver info must match the resolver info used to create the target", + activity.getAdapter().getItem(0).getResolveInfo(), is(ri)); + assertThat("The display label must match", + activity.getAdapter().getItem(0).getDisplayLabel(), is("testTitle0")); + } + + @Test + public void testShortcutTargetWithoutApplyAppLimits() throws InterruptedException { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI, + Boolean.toString(false), + true /* makeDefault*/); + // Set up resources + sOverrides.resources = Mockito.spy( + InstrumentationRegistry.getInstrumentation().getContext().getResources()); + when(sOverrides.resources.getInteger(R.integer.config_maxShortcutTargetsPerApp)) + .thenReturn(1); + Intent sendIntent = createSendTextIntent(); + // We need app targets for direct targets to get displayed + List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); + when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); + // Create direct share target + List<ChooserTarget> serviceTargets = createDirectShareTargets(2, + resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName); + ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0); + + // Start activity + final ChooserWrapperActivity activity = mActivityRule + .launchActivity(Intent.createChooser(sendIntent, null)); + + // Insert the direct share target + Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>(); + List<ShareShortcutInfo> shortcutInfos = createShortcuts(activity); + directShareToShortcutInfos.put(serviceTargets.get(0), + shortcutInfos.get(0).getShortcutInfo()); + directShareToShortcutInfos.put(serviceTargets.get(1), + shortcutInfos.get(1).getShortcutInfo()); + InstrumentationRegistry.getInstrumentation().runOnMainSync( + () -> activity.getAdapter().addServiceResults( + activity.createTestDisplayResolveInfo(sendIntent, + ri, + "testLabel", + "testInfo", + sendIntent, + /* resolveInfoPresentationGetter */ null), + serviceTargets, + TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE, + directShareToShortcutInfos, + List.of()) + ); + // Thread.sleep shouldn't be a thing in an integration test but it's + // necessary here because of the way the code is structured + // TODO: restructure the tests b/129870719 + Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS); + + assertThat("Chooser should have 4 targets (2 apps, 2 direct)", + activity.getAdapter().getCount(), is(4)); + assertThat("Chooser should have exactly two selectable direct target", + activity.getAdapter().getSelectableServiceTargetCount(), is(2)); + assertThat("The resolver info must match the resolver info used to create the target", + activity.getAdapter().getItem(0).getResolveInfo(), is(ri)); + assertThat("The display label must match", + activity.getAdapter().getItem(0).getDisplayLabel(), is("testTitle0")); + assertThat("The display label must match", + activity.getAdapter().getItem(1).getDisplayLabel(), is("testTitle1")); + } + // This test is too long and too slow and should not be taken as an example for future tests. @Test public void testDirectTargetLoggingWithAppTargetNotRankedPortrait() diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java index 561c549676da..78901683eca1 100644 --- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java @@ -923,6 +923,34 @@ public class BinderCallsStatsTest { } } + @Test + public void testLatencyCollectionEnabled() { + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.setCollectLatencyData(true); + + Binder binder = new Binder(); + CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); + bcs.time += 10; + bcs.elapsedTime += 20; + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); + + assertEquals(1, bcs.getLatencyObserver().getLatencyHistograms().size()); + } + + @Test + public void testLatencyCollectionDisabledByDefault() { + TestBinderCallsStats bcs = new TestBinderCallsStats(); + assertEquals(false, bcs.getCollectLatencyData()); + + Binder binder = new Binder(); + CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID); + bcs.time += 10; + bcs.elapsedTime += 20; + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); + + assertEquals(0, bcs.getLatencyObserver().getLatencyHistograms().size()); + } + private static class TestHandler extends Handler { ArrayList<Runnable> mRunnables = new ArrayList<>(); @@ -963,6 +991,10 @@ public class BinderCallsStatsTest { public Handler getHandler() { return mHandler; } + + public BinderLatencyObserver getLatencyObserver() { + return new BinderLatencyObserverTest.TestBinderLatencyObserver(); + } }); setSamplingInterval(1); setAddDebugEntries(false); diff --git a/core/tests/coretests/src/com/android/internal/os/BinderLatencyBucketsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderLatencyBucketsTest.java new file mode 100644 index 000000000000..00443a967c79 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/BinderLatencyBucketsTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertEquals; + +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidJUnit4.class) +@Presubmit +public class BinderLatencyBucketsTest { + @Test + public void testBucketThresholds() { + BinderLatencyBuckets latencyBuckets = new BinderLatencyBuckets(10, 2, 1.45f); + assertThat(latencyBuckets.getBuckets()) + .containsExactly(2, 3, 4, 6, 8, 12, 18, 26, 39) + .inOrder(); + } + + @Test + public void testSampleAssignment() { + BinderLatencyBuckets latencyBuckets = new BinderLatencyBuckets(10, 2, 1.45f); + assertEquals(0, latencyBuckets.sampleToBucket(0)); + assertEquals(0, latencyBuckets.sampleToBucket(1)); + assertEquals(1, latencyBuckets.sampleToBucket(2)); + assertEquals(2, latencyBuckets.sampleToBucket(3)); + assertEquals(3, latencyBuckets.sampleToBucket(4)); + assertEquals(5, latencyBuckets.sampleToBucket(9)); + assertEquals(6, latencyBuckets.sampleToBucket(13)); + assertEquals(7, latencyBuckets.sampleToBucket(25)); + assertEquals(9, latencyBuckets.sampleToBucket(100)); + } + + @Test + public void testMaxIntBuckets() { + BinderLatencyBuckets latencyBuckets = new BinderLatencyBuckets(5, Integer.MAX_VALUE / 2, 2); + assertThat(latencyBuckets.getBuckets()) + .containsExactly(Integer.MAX_VALUE / 2, Integer.MAX_VALUE - 1) + .inOrder(); + + assertEquals(0, latencyBuckets.sampleToBucket(0)); + assertEquals(0, latencyBuckets.sampleToBucket(Integer.MAX_VALUE / 2 - 1)); + assertEquals(1, latencyBuckets.sampleToBucket(Integer.MAX_VALUE - 2)); + assertEquals(2, latencyBuckets.sampleToBucket(Integer.MAX_VALUE)); + } +} diff --git a/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java b/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java new file mode 100644 index 000000000000..f65fb9583d6c --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/BinderLatencyObserverTest.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertEquals; + +import android.os.Binder; +import android.platform.test.annotations.Presubmit; +import android.util.ArrayMap; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.os.BinderInternal.CallSession; +import com.android.internal.os.BinderLatencyObserver.LatencyDims; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.Random; + +@SmallTest +@RunWith(AndroidJUnit4.class) +@Presubmit +public class BinderLatencyObserverTest { + @Test + public void testLatencyCollectionWithMultipleClasses() { + TestBinderLatencyObserver blo = new TestBinderLatencyObserver(); + blo.setHistogramBucketsParams(5, 5, 1.125f); + + Binder binder = new Binder(); + CallSession callSession = new CallSession(); + callSession.binderClass = binder.getClass(); + callSession.transactionCode = 1; + blo.callEnded(callSession); + blo.callEnded(callSession); + blo.callEnded(callSession); + callSession.transactionCode = 2; + blo.callEnded(callSession); + blo.callEnded(callSession); + + ArrayMap<LatencyDims, int[]> latencyHistograms = blo.getLatencyHistograms(); + assertEquals(2, latencyHistograms.keySet().size()); + assertThat(latencyHistograms.get(new LatencyDims(binder.getClass(), 1))) + .asList().containsExactly(2, 0, 1, 0, 0).inOrder(); + assertThat(latencyHistograms.get(new LatencyDims(binder.getClass(), 2))) + .asList().containsExactly(0, 0, 0, 0, 2).inOrder(); + } + + @Test + public void testSampling() { + TestBinderLatencyObserver blo = new TestBinderLatencyObserver(); + blo.setSamplingInterval(2); + blo.setHistogramBucketsParams(5, 5, 1.125f); + + Binder binder = new Binder(); + CallSession callSession = new CallSession(); + callSession.binderClass = binder.getClass(); + callSession.transactionCode = 1; + blo.callEnded(callSession); + callSession.transactionCode = 2; + blo.callEnded(callSession); + + ArrayMap<LatencyDims, int[]> latencyHistograms = blo.getLatencyHistograms(); + assertEquals(1, latencyHistograms.size()); + LatencyDims dims = latencyHistograms.keySet().iterator().next(); + assertEquals(binder.getClass(), dims.getBinderClass()); + assertEquals(1, dims.getTransactionCode()); + assertThat(latencyHistograms.get(dims)).asList().containsExactly(1, 0, 0, 0, 0).inOrder(); + } + + @Test + public void testTooCallLengthOverflow() { + TestBinderLatencyObserver blo = new TestBinderLatencyObserver(); + blo.setElapsedTime(2L + (long) Integer.MAX_VALUE); + blo.setHistogramBucketsParams(5, 5, 1.125f); + + Binder binder = new Binder(); + CallSession callSession = new CallSession(); + callSession.binderClass = binder.getClass(); + callSession.transactionCode = 1; + blo.callEnded(callSession); + + // The long call should be capped to maxint (to not overflow) and placed in the last bucket. + assertThat(blo.getLatencyHistograms() + .get(new LatencyDims(binder.getClass(), 1))) + .asList().containsExactly(0, 0, 0, 0, 1) + .inOrder(); + } + + @Test + public void testHistogramBucketOverflow() { + TestBinderLatencyObserver blo = new TestBinderLatencyObserver(); + blo.setHistogramBucketsParams(3, 5, 1.125f); + + Binder binder = new Binder(); + CallSession callSession = new CallSession(); + callSession.binderClass = binder.getClass(); + callSession.transactionCode = 1; + blo.callEnded(callSession); + + LatencyDims dims = new LatencyDims(binder.getClass(), 1); + // Fill the buckets with maxint. + Arrays.fill(blo.getLatencyHistograms().get(dims), Integer.MAX_VALUE); + assertThat(blo.getLatencyHistograms().get(dims)) + .asList().containsExactly(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); + // Try to add another sample. + blo.callEnded(callSession); + // Make sure the buckets don't overflow. + assertThat(blo.getLatencyHistograms().get(dims)) + .asList().containsExactly(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + public static class TestBinderLatencyObserver extends BinderLatencyObserver { + private long mElapsedTime = 0; + + TestBinderLatencyObserver() { + // Make random generator not random. + super(new Injector() { + public Random getRandomGenerator() { + return new Random() { + int mCallCount = 0; + + public int nextInt() { + return mCallCount++; + } + }; + } + }); + setSamplingInterval(1); + } + + @Override + protected long getElapsedRealtimeMicro() { + mElapsedTime += 2; + return mElapsedTime; + } + + public void setElapsedTime(long time) { + mElapsedTime = time; + } + } +} diff --git a/core/tests/coretests/src/com/android/internal/view/OWNERS b/core/tests/coretests/src/com/android/internal/view/OWNERS new file mode 100644 index 000000000000..1dad10de5ac7 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/view/OWNERS @@ -0,0 +1,3 @@ +# Scroll Capture +per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS +per-file *CaptureHelper*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp index 89644e2320c1..35c00f290f2b 100644 --- a/data/etc/car/Android.bp +++ b/data/etc/car/Android.bp @@ -150,6 +150,7 @@ prebuilt_etc { sub_dir: "permissions", src: "com.android.car.rotary.xml", filename_from_src: true, + system_ext_specific: true, } prebuilt_etc { diff --git a/data/etc/car/com.android.car.activityresolver.xml b/data/etc/car/com.android.car.activityresolver.xml index d48bc15b1678..927c7387b175 100644 --- a/data/etc/car/com.android.car.activityresolver.xml +++ b/data/etc/car/com.android.car.activityresolver.xml @@ -19,3 +19,4 @@ <permission name="android.permission.MANAGE_USERS"/> </privapp-permissions> </permissions> + diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index c49fe8563dab..427f4a357f64 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -369,6 +369,8 @@ applications that come with the platform <!-- Needed for test only --> <permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD" /> <permission name="android.permission.POWER_SAVER" /> + <!-- Needed for CTS tests --> + <permission name="android.permission.READ_ACTIVE_EMERGENCY_SESSION"/> <permission name="android.permission.READ_CARRIER_APP_INFO"/> <permission name="android.permission.READ_FRAME_BUFFER"/> <permission name="android.permission.READ_LOWPAN_CREDENTIAL"/> diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/UnattributedNoteOpCallChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/UnattributedNoteOpCallChecker.java new file mode 100644 index 000000000000..d39978f54ebc --- /dev/null +++ b/errorprone/java/com/google/errorprone/bugpatterns/android/UnattributedNoteOpCallChecker.java @@ -0,0 +1,62 @@ +/* + * 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.google.errorprone.bugpatterns.android; + +import static com.google.errorprone.BugPattern.SeverityLevel.WARNING; +import static com.google.errorprone.matchers.Matchers.instanceMethod; +import static com.google.errorprone.matchers.Matchers.methodInvocation; + +import com.google.auto.service.AutoService; +import com.google.errorprone.BugPattern; +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker; +import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher; +import com.google.errorprone.matchers.Description; +import com.google.errorprone.matchers.Matcher; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.MethodInvocationTree; + +@AutoService(BugChecker.class) +@BugPattern( + name = "AndroidFrameworkUnattributedNoteOpCall", + summary = "Verifies that a noteOp() call is attributed", + severity = WARNING) +public final class UnattributedNoteOpCallChecker extends BugChecker + implements MethodInvocationTreeMatcher { + + private static final Matcher<ExpressionTree> UNATTRIBUTED_NOTEOP_CALL_1 = methodInvocation( + instanceMethod().onExactClass("android.app.AppOpsManager") + .withSignature("noteOp(int,int,java.lang.String)")); + private static final Matcher<ExpressionTree> UNATTRIBUTED_NOTEOP_CALL_2 = methodInvocation( + instanceMethod().onExactClass("android.app.AppOpsManager") + .withSignature("noteOp(java.lang.String,int,java.lang.String)")); + private static final Matcher<ExpressionTree> UNATTRIBUTED_NOTEOP_CALL_3 = methodInvocation( + instanceMethod().onExactClass("android.app.AppOpsManager") + .withSignature("noteOp(int)")); + + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + if (UNATTRIBUTED_NOTEOP_CALL_1.matches(tree, state) + || UNATTRIBUTED_NOTEOP_CALL_2.matches(tree, state) + || UNATTRIBUTED_NOTEOP_CALL_3.matches(tree, state)) { + return buildDescription(tree) + .setMessage("Unattributed noteOp call! Please use noteOp(int, String, String, String) or noteOp(int, CallerIdentity)") + .build(); + } + return Description.NO_MATCH; + } +} diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/UnattributedNoteOpCallCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/UnattributedNoteOpCallCheckerTest.java new file mode 100644 index 000000000000..4a559c205ca6 --- /dev/null +++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/UnattributedNoteOpCallCheckerTest.java @@ -0,0 +1,57 @@ +/* + * 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.google.errorprone.bugpatterns.android; + +import com.google.errorprone.CompilationTestHelper; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class UnattributedNoteOpCallCheckerTest { + private CompilationTestHelper mCompilationHelper; + + @Before + public void setUp() { + mCompilationHelper = CompilationTestHelper.newInstance( + UnattributedNoteOpCallChecker.class, getClass()); + } + + @Test + public void testNoteOp() { + mCompilationHelper + .addSourceFile("/android/app/AppOpsManager.java") + .addSourceLines("Example.java", + "import android.app.AppOpsManager;", + "public class Example {", + " void example() {", + " AppOpsManager mAppOps = new AppOpsManager();", + " mAppOps.noteOp(\"foo\", 0, \"bar\", \"baz\", \"qux\");", + " mAppOps.noteOp(0, 0, \"bar\", \"baz\", \"qux\");", + " // BUG: Diagnostic contains:", + " mAppOps.noteOp(1, 2, \"foo\");", + " // BUG: Diagnostic contains:", + " mAppOps.noteOp(\"foo\", 1, \"bar\");", + " // BUG: Diagnostic contains:", + " mAppOps.noteOp(1);", + " }", + "}") + .doTest(); + } +} diff --git a/errorprone/tests/res/android/app/AppOpsManager.java b/errorprone/tests/res/android/app/AppOpsManager.java new file mode 100644 index 000000000000..cccdfd8eb933 --- /dev/null +++ b/errorprone/tests/res/android/app/AppOpsManager.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 android.app; + +public class AppOpsManager { + + public int noteOp(String op, int uid, String packageName) { + throw new UnsupportedOperationException(); + } + + public int noteOp(int op) { + throw new UnsupportedOperationException(); + } + + public int noteOp(int op, int uid, String packageName) { + throw new UnsupportedOperationException(); + } + + public int noteOp(String op, int uid, String packageName, + String attributionTag, String message) { + throw new UnsupportedOperationException(); + } + + public int noteOp(int op, int uid, String packageName, + String attributionTag, String message) { + throw new UnsupportedOperationException(); + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 5fc7c987899f..4f1cc8c6ecd7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -277,7 +277,6 @@ public class OneHandedController { final int yOffSet = Math.round(getDisplaySize().height() * mOffSetFraction); mDisplayAreaOrganizer.scheduleOffset(0, yOffSet); mTimeoutHandler.resetTimer(); - mOneHandedUiEventLogger.writeEvent( OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_GESTURE_IN); } @@ -288,6 +287,9 @@ public class OneHandedController { if (mDisplayAreaOrganizer.isInOneHanded()) { mDisplayAreaOrganizer.scheduleOffset(0, 0); mTimeoutHandler.removeTimer(); + // Log metrics for Gesture navigation mode. + mOneHandedUiEventLogger.writeEvent( + OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT); } } diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index d663c52b2c08..f0cba4455610 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -648,6 +648,7 @@ cc_test { "tests/unit/CommonPoolTests.cpp", "tests/unit/DamageAccumulatorTests.cpp", "tests/unit/DeferredLayerUpdaterTests.cpp", + "tests/unit/EglManagerTests.cpp", "tests/unit/FatVectorTests.cpp", "tests/unit/GraphicsStatsServiceTests.cpp", "tests/unit/LayerUpdateQueueTests.cpp", diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index 3aa5b4bf72f8..ca5f853066f2 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -17,8 +17,10 @@ #pragma once #include "pipeline/skia/SkiaDisplayList.h" +#include "canvas/CanvasOpBuffer.h" #include <memory> +#include <variant> namespace android { namespace uirenderer { @@ -28,29 +30,25 @@ class Tree; }; typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; -/** - * Data structure that holds the list of commands used in display list stream - */ -//using DisplayList = skiapipeline::SkiaDisplayList; -class DisplayList { +class SkiaDisplayListWrapper { public: // Constructs an empty (invalid) DisplayList - explicit DisplayList() {} + explicit SkiaDisplayListWrapper() {} // Constructs a DisplayList from a SkiaDisplayList - explicit DisplayList(std::unique_ptr<skiapipeline::SkiaDisplayList> impl) + explicit SkiaDisplayListWrapper(std::unique_ptr<skiapipeline::SkiaDisplayList> impl) : mImpl(std::move(impl)) {} // Move support - DisplayList(DisplayList&& other) : mImpl(std::move(other.mImpl)) {} - DisplayList& operator=(DisplayList&& other) { + SkiaDisplayListWrapper(SkiaDisplayListWrapper&& other) : mImpl(std::move(other.mImpl)) {} + SkiaDisplayListWrapper& operator=(SkiaDisplayListWrapper&& other) { mImpl = std::move(other.mImpl); return *this; } // No copy support - DisplayList(const DisplayList& other) = delete; - DisplayList& operator=(const DisplayList&) = delete; + SkiaDisplayListWrapper(const SkiaDisplayListWrapper& other) = delete; + SkiaDisplayListWrapper& operator=(const SkiaDisplayListWrapper&) = delete; void updateChildren(std::function<void(RenderNode*)> updateFn) { mImpl->updateChildren(std::move(updateFn)); @@ -137,7 +135,7 @@ public: void applyColorTransform(ColorTransform transform) { if (mImpl) { - mImpl->mDisplayList.applyColorTransform(transform); + mImpl->applyColorTransform(transform); } } @@ -145,5 +143,172 @@ private: std::unique_ptr<skiapipeline::SkiaDisplayList> mImpl; }; + +/** + * Data structure that holds the list of commands used in display list stream + */ +//using DisplayList = skiapipeline::SkiaDisplayList; +class MultiDisplayList { +private: + using SkiaDisplayList = skiapipeline::SkiaDisplayList; + + struct EmptyList { + bool hasText() const { return false; } + void updateChildren(std::function<void(RenderNode*)> updateFn) {} + bool isEmpty() const { return true; } + bool containsProjectionReceiver() const { return false; } + bool hasVectorDrawables() const { return false; } + size_t getUsedSize() const { return 0; } + size_t getAllocatedSize() const { return 0; } + void output(std::ostream& output, uint32_t level) const { } + bool hasFunctor() const { return false; } + bool prepareListAndChildren( + TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, + std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) { + return false; + } + void syncContents(const WebViewSyncData& data) { } + void applyColorTransform(ColorTransform transform) { } + }; + + std::variant<EmptyList, std::unique_ptr<SkiaDisplayList>, CanvasOpBuffer> mImpls; + + template <typename T> + static constexpr T& get(T& t) { return t; } + template <typename T> + static constexpr const T& get(const T& t) { return t; } + + template <typename T> + static constexpr T& get(std::unique_ptr<T>& t) { return *t; } + template <typename T> + static constexpr const T& get(const std::unique_ptr<T>& t) { return *t; } + + template <typename T> + auto apply(T&& t) { + return std::visit([&t](auto& it) -> auto { + return t(get(it)); + }, mImpls); + } + + template <typename T> + auto apply(T&& t) const { + return std::visit([&t](const auto& it) -> auto { + return t(get(it)); + }, mImpls); + } + +public: + // Constructs an empty (invalid) DisplayList + explicit MultiDisplayList() {} + + // Constructs a DisplayList from a SkiaDisplayList + explicit MultiDisplayList(std::unique_ptr<SkiaDisplayList> impl) + : mImpls(std::move(impl)) {} + + explicit MultiDisplayList(CanvasOpBuffer&& opBuffer) : mImpls(std::move(opBuffer)) {} + + // Move support + MultiDisplayList(MultiDisplayList&& other) : mImpls(std::move(other.mImpls)) {} + MultiDisplayList& operator=(MultiDisplayList&& other) { + mImpls = std::move(other.mImpls); + return *this; + } + + // No copy support + MultiDisplayList(const MultiDisplayList& other) = delete; + MultiDisplayList& operator=(const MultiDisplayList&) = delete; + + void updateChildren(std::function<void(RenderNode*)> updateFn) { + apply([&](auto& it) { it.updateChildren(std::move(updateFn)); }); + } + + [[nodiscard]] explicit operator bool() const { + return isValid(); + } + + // If true this DisplayList contains a backing content, even if that content is empty + // If false, there this DisplayList is in an "empty" state + [[nodiscard]] bool isValid() const { + return mImpls.index() != 0; + } + + [[nodiscard]] bool isEmpty() const { + return apply([](const auto& it) -> auto { return it.isEmpty(); }); + } + + [[nodiscard]] bool hasContent() const { + return !isEmpty(); + } + + [[nodiscard]] bool containsProjectionReceiver() const { + return apply([](const auto& it) -> auto { return it.containsProjectionReceiver(); }); + } + + [[nodiscard]] SkiaDisplayList* asSkiaDl() { + return std::get<1>(mImpls).get(); + } + + [[nodiscard]] const SkiaDisplayList* asSkiaDl() const { + return std::get<1>(mImpls).get(); + } + + [[nodiscard]] bool hasVectorDrawables() const { + return apply([](const auto& it) -> auto { return it.hasVectorDrawables(); }); + } + + void clear(RenderNode* owningNode = nullptr) { + if (owningNode && mImpls.index() == 1) { + auto& skiaDl = std::get<1>(mImpls); + if (skiaDl->reuseDisplayList(owningNode)) { + skiaDl.release(); + } + } + mImpls = EmptyList{}; + } + + [[nodiscard]] size_t getUsedSize() const { + return apply([](const auto& it) -> auto { return it.getUsedSize(); }); + } + + [[nodiscard]] size_t getAllocatedSize() const { + return apply([](const auto& it) -> auto { return it.getAllocatedSize(); }); + } + + void output(std::ostream& output, uint32_t level) const { + apply([&](const auto& it) { it.output(output, level); }); + } + + [[nodiscard]] bool hasFunctor() const { + return apply([](const auto& it) -> auto { return it.hasFunctor(); }); + } + + bool prepareListAndChildren( + TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, + std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) { + return apply([&](auto& it) -> auto { + return it.prepareListAndChildren(observer, info, functorsNeedLayer, std::move(childFn)); + }); + } + + void syncContents(const WebViewSyncData& data) { + apply([&](auto& it) { it.syncContents(data); }); + } + + [[nodiscard]] bool hasText() const { + return apply([](const auto& it) -> auto { return it.hasText(); }); + } + + void applyColorTransform(ColorTransform transform) { + apply([=](auto& it) { it.applyColorTransform(transform); }); + } + + [[nodiscard]] CanvasOpBuffer& asOpBuffer() { + return std::get<CanvasOpBuffer>(mImpls); + } +}; + +// For now stick to the original single-type container to avoid any regressions +using DisplayList = SkiaDisplayListWrapper; + } // namespace uirenderer } // namespace android diff --git a/libs/hwui/canvas/CanvasFrontend.h b/libs/hwui/canvas/CanvasFrontend.h index d749d2f2596b..f9a610129d3a 100644 --- a/libs/hwui/canvas/CanvasFrontend.h +++ b/libs/hwui/canvas/CanvasFrontend.h @@ -147,8 +147,7 @@ class CanvasFrontend final : public CanvasStateHelper { public: template<class... Args> CanvasFrontend(int width, int height, Args&&... args) : CanvasStateHelper(width, height), - mReceiver(std::forward<Args>(args)...) { } - ~CanvasFrontend() = default; + mReceiver(std::in_place, std::forward<Args>(args)...) { } void save(SaveFlags::Flags flags = SaveFlags::MatrixClip) { if (internalSave(flagsToSaveEntry(flags))) { @@ -186,7 +185,10 @@ public: submit(std::move(op)); } - const CanvasOpReceiver& receiver() const { return *mReceiver; } + const CanvasOpReceiver& receiver() const { + LOG_ALWAYS_FATAL_IF(!mReceiver.has_value()); + return *mReceiver; + } CanvasOpReceiver finish() { auto ret = std::move(mReceiver.value()); @@ -205,6 +207,7 @@ private: template <CanvasOpType T> void submit(CanvasOp<T>&& op) { + LOG_ALWAYS_FATAL_IF(!mReceiver.has_value()); mReceiver->push_container(CanvasOpContainer(std::move(op), transform())); } }; diff --git a/libs/hwui/canvas/CanvasOpBuffer.cpp b/libs/hwui/canvas/CanvasOpBuffer.cpp index 7054e47eac89..6089c572b0d5 100644 --- a/libs/hwui/canvas/CanvasOpBuffer.cpp +++ b/libs/hwui/canvas/CanvasOpBuffer.cpp @@ -22,4 +22,32 @@ namespace android::uirenderer { template class OpBuffer<CanvasOpType, CanvasOpContainer>; +void CanvasOpBuffer::updateChildren(std::function<void(RenderNode*)> updateFn) { + // TODO: Do we need a fast-path for finding children? + if (mHas.children) { + for (auto& iter : filter<CanvasOpType::DrawRenderNode>()) { + updateFn(iter->renderNode.get()); + } + } +} + +void CanvasOpBuffer::output(std::ostream& output, uint32_t level) const { + LOG_ALWAYS_FATAL("TODO"); +} + +bool CanvasOpBuffer::prepareListAndChildren( + TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, + std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) { + LOG_ALWAYS_FATAL("TODO"); + return false; +} + +void CanvasOpBuffer::syncContents(const WebViewSyncData& data) { + LOG_ALWAYS_FATAL("TODO"); +} + +void CanvasOpBuffer::applyColorTransform(ColorTransform transform) { + LOG_ALWAYS_FATAL("TODO"); +} + } // namespace android::uirenderer diff --git a/libs/hwui/canvas/CanvasOpBuffer.h b/libs/hwui/canvas/CanvasOpBuffer.h index 07e079a7d57f..af797ca8288b 100644 --- a/libs/hwui/canvas/CanvasOpBuffer.h +++ b/libs/hwui/canvas/CanvasOpBuffer.h @@ -19,10 +19,17 @@ #include <SkMatrix.h> #include "CanvasOpTypes.h" +#include "CanvasTransform.h" #include "OpBuffer.h" +#include "TreeInfo.h" +#include "private/hwui/WebViewFunctor.h" + +#include <functional> namespace android::uirenderer { +class RenderNode; + template <CanvasOpType T> struct CanvasOp; @@ -53,12 +60,74 @@ public: }; extern template class OpBuffer<CanvasOpType, CanvasOpContainer>; -class CanvasOpBuffer final : public OpBuffer<CanvasOpType, CanvasOpContainer> { +class CanvasOpBuffer final : private OpBuffer<CanvasOpType, CanvasOpContainer> { +private: + using SUPER = OpBuffer<CanvasOpType, CanvasOpContainer>; + public: + // Expose select superclass methods publicly + using SUPER::for_each; + using SUPER::size; + using SUPER::resize; + template <CanvasOpType T> void push(CanvasOp<T>&& op) { push_container(CanvasOpContainer<T>(std::move(op))); } + + template <CanvasOpType T> + void push_container(CanvasOpContainer<T>&& op) { + if constexpr (IsDrawOp(T)) { + mHas.content = true; + } + if constexpr (T == CanvasOpType::DrawRenderNode) { + mHas.children = true; + // use staging property, since recording on UI thread + if (op->renderNode->stagingProperties().isProjectionReceiver()) { + mHas.projectionReceiver = true; + } + } + SUPER::push_container(std::move(op)); + } + + void clear() { + mHas = Contains{}; + SUPER::clear(); + } + + void updateChildren(std::function<void(RenderNode*)> updateFn); + bool prepareListAndChildren( + TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, + std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn); + void syncContents(const WebViewSyncData& data); + void applyColorTransform(ColorTransform transform); + + [[nodiscard]] bool isEmpty() const { return !mHas.content; } + [[nodiscard]] bool hasText() const { return mHas.text; } + [[nodiscard]] bool hasVectorDrawables() const { return mHas.vectorDrawable; } + [[nodiscard]] bool containsProjectionReceiver() const { return mHas.projectionReceiver; } + [[nodiscard]] bool hasFunctor() const { return mHas.functor; } + + [[nodiscard]] size_t getUsedSize() const { + return size(); + } + + [[nodiscard]] size_t getAllocatedSize() const { + return capacity(); + } + + void output(std::ostream& output, uint32_t level) const; + +private: + struct Contains { + bool content : 1 = false; + bool children : 1 = false; + bool projectionReceiver : 1 = false; + bool text : 1 = false; + bool vectorDrawable : 1 = false; + bool functor : 1 = false; + }; + Contains mHas; }; } // namespace android::uirenderer diff --git a/libs/hwui/canvas/CanvasOpRasterizer.cpp b/libs/hwui/canvas/CanvasOpRasterizer.cpp index 0093c38cf8a8..9297604197c0 100644 --- a/libs/hwui/canvas/CanvasOpRasterizer.cpp +++ b/libs/hwui/canvas/CanvasOpRasterizer.cpp @@ -33,21 +33,15 @@ void rasterizeCanvasBuffer(const CanvasOpBuffer& source, SkCanvas* destination) SkMatrix& currentGlobalTransform = globalMatrixStack.emplace_back(SkMatrix::I()); source.for_each([&]<CanvasOpType T>(const CanvasOpContainer<T> * op) { - if constexpr ( - T == CanvasOpType::BeginZ || - T == CanvasOpType::EndZ || - T == CanvasOpType::DrawLayer - ) { - // Do beginZ or endZ - LOG_ALWAYS_FATAL("TODO"); - return; - } else { + if constexpr (CanvasOpTraits::can_draw<CanvasOp<T>>) { // Generic OP // First apply the current transformation destination->setMatrix(SkMatrix::Concat(currentGlobalTransform, op->transform())); // Now draw it (*op)->draw(destination); + return; } + LOG_ALWAYS_FATAL("TODO, unable to rasterize %d", static_cast<int>(T)); }); } diff --git a/libs/hwui/canvas/CanvasOpTypes.h b/libs/hwui/canvas/CanvasOpTypes.h index cde50bd66a15..b55ef9d5537c 100644 --- a/libs/hwui/canvas/CanvasOpTypes.h +++ b/libs/hwui/canvas/CanvasOpTypes.h @@ -35,7 +35,8 @@ enum class CanvasOpType : int8_t { ClipPath, // Drawing ops - DrawColor, + DRAW_OP_BEGIN, + DrawColor = DRAW_OP_BEGIN, DrawRect, DrawRegion, DrawRoundRect, @@ -59,10 +60,16 @@ enum class CanvasOpType : int8_t { DrawImageLattice, DrawPicture, DrawLayer, + DrawRenderNode, + DRAW_OP_END = DrawRenderNode, // TODO: Rest COUNT // must be last }; +static constexpr bool IsDrawOp(CanvasOpType t) { + return CanvasOpType::DRAW_OP_BEGIN <= t && t <= CanvasOpType::DRAW_OP_END; +} + } // namespace android::uirenderer
\ No newline at end of file diff --git a/libs/hwui/canvas/CanvasOps.h b/libs/hwui/canvas/CanvasOps.h index 86b1ac71f692..855cd0d6436b 100644 --- a/libs/hwui/canvas/CanvasOps.h +++ b/libs/hwui/canvas/CanvasOps.h @@ -24,13 +24,15 @@ #include <SkImage.h> #include <SkPicture.h> #include <SkRuntimeEffect.h> -#include <hwui/Bitmap.h> + #include <log/log.h> -#include "CanvasProperty.h" -#include "Points.h" +#include "hwui/Bitmap.h" +#include "CanvasProperty.h" #include "CanvasOpTypes.h" #include "Layer.h" +#include "Points.h" +#include "RenderNode.h" #include <experimental/type_traits> #include <utility> @@ -450,6 +452,11 @@ struct CanvasOp<CanvasOpType::DrawLayer> { sp<Layer> layer; }; +template<> +struct CanvasOp<CanvasOpType::DrawRenderNode> { + sp<RenderNode> renderNode; +}; + // cleanup our macros #undef ASSERT_DRAWABLE diff --git a/libs/hwui/canvas/OpBuffer.h b/libs/hwui/canvas/OpBuffer.h index 1237d69a3c24..8b5cdbbec958 100644 --- a/libs/hwui/canvas/OpBuffer.h +++ b/libs/hwui/canvas/OpBuffer.h @@ -64,7 +64,7 @@ public: static constexpr auto STARTING_SIZE = PadAlign(sizeof(BufferHeader)); using ItemHeader = OpBufferItemHeader<ItemTypes>; - OpBuffer() = default; + explicit OpBuffer() = default; // Prevent copying by default OpBuffer(const OpBuffer&) = delete; @@ -135,7 +135,7 @@ public: template <typename F> void for_each(F&& f) const { - for_each(std::forward<F>(f), ItemTypesSequence{}); + do_for_each(std::forward<F>(f), ItemTypesSequence{}); } void clear(); @@ -225,7 +225,7 @@ private: } template <typename F, std::size_t... I> - void for_each(F&& f, std::index_sequence<I...>) const { + void do_for_each(F&& f, std::index_sequence<I...>) const { // Validate we're not empty if (isEmpty()) return; diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index 483264f95e60..1136e58e43d8 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -16,6 +16,8 @@ #pragma once +#include <deque> + #include "RecordingCanvas.h" #include "RenderNodeDrawable.h" #include "TreeInfo.h" @@ -23,8 +25,6 @@ #include "utils/LinearAllocator.h" #include "utils/Pair.h" -#include <deque> - namespace android { namespace uirenderer { @@ -46,8 +46,10 @@ class FunctorDrawable; class SkiaDisplayList { public: - size_t getUsedSize() { return allocator.usedSize() + mDisplayList.usedSize(); } - size_t getAllocatedSize() { return allocator.allocatedSize() + mDisplayList.allocatedSize(); } + size_t getUsedSize() const { return allocator.usedSize() + mDisplayList.usedSize(); } + size_t getAllocatedSize() const { + return allocator.allocatedSize() + mDisplayList.allocatedSize(); + } ~SkiaDisplayList() { /* Given that we are using a LinearStdAllocator to store some of the @@ -109,6 +111,10 @@ public: */ void syncContents(const WebViewSyncData& data); + void applyColorTransform(ColorTransform transform) { + mDisplayList.applyColorTransform(transform); + } + /** * ONLY to be called by RenderNode::prepareTree in order to prepare this * list while the UI thread is blocked. Here we can upload mutable bitmaps @@ -154,12 +160,12 @@ public: std::deque<RenderNodeDrawable> mChildNodes; std::deque<FunctorDrawable*> mChildFunctors; std::vector<SkImage*> mMutableImages; + private: std::vector<Pair<VectorDrawableRoot*, SkMatrix>> mVectorDrawables; + public: - void appendVD(VectorDrawableRoot* r) { - appendVD(r, SkMatrix::I()); - } + void appendVD(VectorDrawableRoot* r) { appendVD(r, SkMatrix::I()); } void appendVD(VectorDrawableRoot* r, const SkMatrix& mat) { mVectorDrawables.push_back(Pair<VectorDrawableRoot*, SkMatrix>(r, mat)); diff --git a/libs/hwui/tests/unit/CanvasFrontendTests.cpp b/libs/hwui/tests/unit/CanvasFrontendTests.cpp index 05b11795d90d..4ddcf6f6ac8a 100644 --- a/libs/hwui/tests/unit/CanvasFrontendTests.cpp +++ b/libs/hwui/tests/unit/CanvasFrontendTests.cpp @@ -124,12 +124,12 @@ TEST(CanvasFrontend, transform) { TEST(CanvasFrontend, drawOpTransform) { CanvasFrontend<CanvasOpBuffer> opCanvas(100, 100); - const auto& receiver = opCanvas.receiver(); + const auto &receiver = opCanvas.receiver(); auto makeDrawRect = [] { return CanvasOp<CanvasOpType::DrawRect>{ - .rect = SkRect::MakeWH(50, 50), - .paint = SkPaint(SkColors::kBlack), + .rect = SkRect::MakeWH(50, 50), + .paint = SkPaint(SkColors::kBlack), }; }; @@ -167,14 +167,14 @@ TEST(CanvasFrontend, drawOpTransform) { { // First result should be identity - const auto& result = transforms[0]; + const auto &result = transforms[0]; EXPECT_EQ(SkMatrix::kIdentity_Mask, result.getType()); EXPECT_EQ(SkMatrix::I(), result); } { // Should be translate 10, 10 - const auto& result = transforms[1]; + const auto &result = transforms[1]; EXPECT_EQ(SkMatrix::kTranslate_Mask, result.getType()); SkMatrix m; m.setTranslate(10, 10); @@ -183,7 +183,7 @@ TEST(CanvasFrontend, drawOpTransform) { { // Should be translate 10, 10 + scale 2, 4 - const auto& result = transforms[2]; + const auto &result = transforms[2]; EXPECT_EQ(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask, result.getType()); SkMatrix m; m.setTranslate(10, 10); @@ -193,7 +193,7 @@ TEST(CanvasFrontend, drawOpTransform) { { // Should be translate 10, 10 + translate 20, 15 - const auto& result = transforms[3]; + const auto &result = transforms[3]; EXPECT_EQ(SkMatrix::kTranslate_Mask, result.getType()); SkMatrix m; m.setTranslate(30, 25); @@ -202,9 +202,9 @@ TEST(CanvasFrontend, drawOpTransform) { { // Should be translate 10, 10 + translate 20, 15 + rotate 90 - const auto& result = transforms[4]; + const auto &result = transforms[4]; EXPECT_EQ(SkMatrix::kTranslate_Mask | SkMatrix::kAffine_Mask | SkMatrix::kScale_Mask, - result.getType()); + result.getType()); SkMatrix m; m.setTranslate(30, 25); m.preRotate(90.f); diff --git a/libs/hwui/tests/unit/CanvasOpTests.cpp b/libs/hwui/tests/unit/CanvasOpTests.cpp index 54970df534b9..a718d46c735f 100644 --- a/libs/hwui/tests/unit/CanvasOpTests.cpp +++ b/libs/hwui/tests/unit/CanvasOpTests.cpp @@ -149,7 +149,7 @@ TEST(CanvasOp, simpleDrawPoints) { CanvasOpBuffer buffer; EXPECT_EQ(buffer.size(), 0); size_t numPts = 3; - auto pts = sk_ref_sp( + auto pts = sk_sp<Points>( new Points({ {32, 16}, {48, 48}, @@ -192,7 +192,7 @@ TEST(CanvasOp, simpleDrawLines) { CanvasOpBuffer buffer; EXPECT_EQ(buffer.size(), 0); size_t numPts = 3; - auto pts = sk_ref_sp( + auto pts = sk_sp<Points>( new Points({ {32, 16}, {48, 48}, diff --git a/libs/hwui/tests/unit/EglManagerTests.cpp b/libs/hwui/tests/unit/EglManagerTests.cpp new file mode 100644 index 000000000000..f7f240663397 --- /dev/null +++ b/libs/hwui/tests/unit/EglManagerTests.cpp @@ -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. + */ + +#include <gtest/gtest.h> + +#include "renderthread/EglManager.h" +#include "tests/common/TestContext.h" + +using namespace android; +using namespace android::uirenderer; +using namespace android::uirenderer::renderthread; +using namespace android::uirenderer::test; + +TEST(EglManager, doesSurfaceLeak) { + EglManager eglManager; + eglManager.initialize(); + + ASSERT_TRUE(eglManager.hasEglContext()); + + auto colorSpace = SkColorSpace::MakeSRGB(); + for (int i = 0; i < 100; i++) { + TestContext context; + auto result = + eglManager.createSurface(context.surface().get(), ColorMode::Default, colorSpace); + EXPECT_TRUE(result); + EGLSurface surface = result.unwrap(); + eglManager.destroySurface(surface); + } + + eglManager.destroy(); +}
\ No newline at end of file diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp index 6dd57b19a41b..8c999c41bf7b 100644 --- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp +++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp @@ -404,6 +404,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) { EXPECT_TRUE(pipeline->isSurfaceReady()); renderThread.destroyRenderingContext(); EXPECT_FALSE(pipeline->isSurfaceReady()); + LOG_ALWAYS_FATAL_IF(pipeline->isSurfaceReady()); } RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, pictureCallback) { diff --git a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl index 726af7681979..57f525b7f224 100644 --- a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl +++ b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl @@ -28,22 +28,29 @@ oneway interface ISoundTriggerCallback { * Invoked whenever a recognition event is triggered (typically, on recognition, but also in * case of external aborting of a recognition or a forced recognition event - see the status * code in the event for determining). + * In case of abortion, the caller may retry after the next onRecognitionAvailabilityChange() + * callback. */ void onRecognition(int modelHandle, in RecognitionEvent event); /** * Invoked whenever a phrase recognition event is triggered (typically, on recognition, but * also in case of external aborting of a recognition or a forced recognition event - see the * status code in the event for determining). + * In case of abortion, the caller may retry after the next onRecognitionAvailabilityChange() + * callback. */ void onPhraseRecognition(int modelHandle, in PhraseRecognitionEvent event); /** - * Notifies the client the recognition has become available after previously having been - * unavailable, or vice versa. This method will always be invoked once immediately after - * attachment, and then every time there is a change in availability. - * When availability changes from available to unavailable, all active recognitions are aborted, - * and this event will be sent in addition to the abort event. + * Notifies the client that some start/load operations that have previously failed for resource + * reasons (threw a ServiceSpecificException(RESOURCE_CONTENTION) or have been preempted) may + * now succeed. This is not a guarantee, but a hint for the client to retry. */ - void onRecognitionAvailabilityChange(boolean available); + void onResourcesAvailable(); + /** + * Notifies the client that a model had been preemptively unloaded by the service. + * The caller may retry after the next onRecognitionAvailabilityChange() callback. + */ + void onModelUnloaded(int modelHandle); /** * Notifies the client that the associated module has crashed and restarted. The module instance * is no longer usable and will throw a ServiceSpecificException with a Status.DEAD_OBJECT code diff --git a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl index c4a57857dd3d..d211e96ace92 100644 --- a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl +++ b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl @@ -75,6 +75,9 @@ interface ISoundTriggerModule { * Once a recognition event is passed to the client, the recognition automatically become * inactive, unless the event is of the RecognitionStatus.FORCED kind. Client can also shut down * the recognition explicitly, via stopRecognition. + * + * May throw a ServiceSpecificException with an RESOURCE_CONTENTION status to indicate that + * resources required for starting the model are currently consumed by other clients. */ void startRecognition(int modelHandle, in RecognitionConfig config); diff --git a/media/java/android/media/AudioProfile.java b/media/java/android/media/AudioProfile.java index 3cd615b658b2..9774e8032c95 100644 --- a/media/java/android/media/AudioProfile.java +++ b/media/java/android/media/AudioProfile.java @@ -18,6 +18,9 @@ package android.media; import android.annotation.NonNull; +import java.util.Arrays; +import java.util.stream.Collectors; + /** * An AudioProfile is specific to an audio format and lists supported sampling rates and * channel masks for that format. An {@link AudioDeviceInfo} has a list of supported AudioProfiles. @@ -63,4 +66,29 @@ public class AudioProfile { public @NonNull int[] getSampleRates() { return mSamplingRates; } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("{"); + sb.append(AudioFormat.toLogFriendlyEncoding(mFormat)); + if (mSamplingRates != null && mSamplingRates.length > 0) { + sb.append(", sampling rates=").append(Arrays.toString(mSamplingRates)); + } + if (mChannelMasks != null && mChannelMasks.length > 0) { + sb.append(", channel masks=").append(toHexString(mChannelMasks)); + } + if (mChannelIndexMasks != null && mChannelIndexMasks.length > 0) { + sb.append(", channel index masks=").append(Arrays.toString(mChannelIndexMasks)); + } + sb.append("}"); + return sb.toString(); + } + + private static String toHexString(int[] ints) { + if (ints == null || ints.length == 0) { + return ""; + } + return Arrays.stream(ints).mapToObj(anInt -> String.format("0x%02X, ", anInt)) + .collect(Collectors.joining()); + } } diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index cf31e4141a6d..d231c5f54f9b 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -25,7 +25,6 @@ import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.hardware.HardwareBuffer; import android.media.MediaCodecInfo.CodecCapabilities; -import android.media.metrics.PlaybackComponent; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -1539,7 +1538,7 @@ import java.util.concurrent.locks.ReentrantLock; </tbody> </table> */ -final public class MediaCodec implements PlaybackComponent { +final public class MediaCodec { /** * Per buffer metadata includes an offset and size specifying @@ -1682,7 +1681,6 @@ final public class MediaCodec implements PlaybackComponent { private MediaCodecInfo mCodecInfo; private final Object mCodecInfoLock = new Object(); private MediaCrypto mCrypto; - private String mPlaybackId; private static final int EVENT_CALLBACK = 1; private static final int EVENT_SET_CALLBACK = 2; @@ -1693,23 +1691,6 @@ final public class MediaCodec implements PlaybackComponent { private static final int CB_ERROR = 3; private static final int CB_OUTPUT_FORMAT_CHANGE = 4; - - /** - * @hide - */ - @Override - public void setPlaybackId(@NonNull String playbackId) { - // TODO: add a native method to pass the ID to the native code for logging. - mPlaybackId = playbackId; - } - /** - * @hide - */ - @Override - public String getPlaybackId() { - return mPlaybackId; - } - private class EventHandler extends Handler { private MediaCodec mCodec; diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java index 8f603300dc11..209f0c02e66d 100644 --- a/media/java/android/media/MediaExtractor.java +++ b/media/java/android/media/MediaExtractor.java @@ -22,6 +22,7 @@ import android.annotation.Nullable; import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; +import android.media.metrics.PlaybackComponent; import android.net.Uri; import android.os.IBinder; import android.os.IHwBinder; @@ -40,6 +41,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.UUID; import java.util.stream.Collectors; @@ -73,8 +75,10 @@ import java.util.stream.Collectors; * <p>This class requires the {@link android.Manifest.permission#INTERNET} permission * when used with network-based content. */ -final public class MediaExtractor { +public final class MediaExtractor implements PlaybackComponent { + public MediaExtractor() { + mPlaybackId = ""; native_setup(); } @@ -767,6 +771,18 @@ final public class MediaExtractor { */ public native boolean hasCacheReachedEndOfStream(); + @Override + public void setPlaybackId(@NonNull String playbackId) { + mPlaybackId = Objects.requireNonNull(playbackId); + native_setPlaybackId(playbackId); + } + + @NonNull + @Override + public String getPlaybackId() { + return mPlaybackId; + } + /** * Return Metrics data about the current media container. * @@ -784,6 +800,7 @@ final public class MediaExtractor { return bundle; } + private native void native_setPlaybackId(String playbackId); private native PersistableBundle native_getMetrics(); private static native final void native_init(); @@ -796,6 +813,7 @@ final public class MediaExtractor { } private MediaCas mMediaCas; + private String mPlaybackId; private long mNativeContext; diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index f8a642a68dd7..1242c069ca44 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -215,6 +215,15 @@ public final class MediaFormat { private Map<String, Object> mMap; /** + * A key describing the log session ID for MediaCodec. The log session ID is a random 32-byte + * hexadecimal string that is used to associate metrics from multiple media codec instances + * to the same playback or recording session. + * The associated value is a string. + * @hide + */ + public static final String LOG_SESSION_ID = "log-session-id"; + + /** * A key describing the mime type of the MediaFormat. * The associated value is a string. */ @@ -479,6 +488,8 @@ public final class MediaFormat { * <li>The timestampUs shall be monotonically increasing.</li> * <li>The timestampUs shall fall within the time span of the video track.</li> * <li>The first timestampUs should match that of the first video sample.</li> + * + * @hide */ public static final String KEY_SLOW_MOTION_MARKERS = "slow-motion-markers"; diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 9176dae8609f..1b32b5b746a2 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -19,7 +19,6 @@ package android.media; import static android.Manifest.permission.BIND_IMS_SERVICE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -4300,7 +4299,7 @@ public class MediaPlayer extends PlayerBase @RequiresPermission(BIND_IMS_SERVICE) public void setOnRtpRxNoticeListener( @NonNull Context context, - @NonNull @CallbackExecutor Executor executor, + @NonNull Executor executor, @NonNull OnRtpRxNoticeListener listener) { Objects.requireNonNull(context); Preconditions.checkArgument( diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 49a4cc6239bb..27e9bfef8913 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -149,6 +149,19 @@ public class MediaRecorder implements AudioRouting, } /** + * Sets the log session ID for MediaRecorder. + * + * <p>The log session ID is a random 32-byte hexadecimal string that is used for monitoring the + * MediaRecorder performance.</p> + * + * @param id the global ID for monitoring the MediaRecorder performance + * @hide + */ + public void setLogSessionId(@NonNull String id) { + setParameter("log-session-id=" + id); + } + + /** * Sets a {@link android.hardware.Camera} to use for recording. * * <p>Use this function to switch quickly between preview and capture mode without a teardown of diff --git a/media/java/android/media/musicrecognition/IMusicRecognitionAttributionTagCallback.aidl b/media/java/android/media/musicrecognition/IMusicRecognitionAttributionTagCallback.aidl new file mode 100644 index 000000000000..ceef73cd194a --- /dev/null +++ b/media/java/android/media/musicrecognition/IMusicRecognitionAttributionTagCallback.aidl @@ -0,0 +1,10 @@ +package android.media.musicrecognition; + +/** + * Interface from {@link MusicRecognitionService} to system to pass attribution tag. + * + * @hide + */ +oneway interface IMusicRecognitionAttributionTagCallback { + void onAttributionTag(in String attributionTag); +}
\ No newline at end of file diff --git a/media/java/android/media/musicrecognition/IMusicRecognitionService.aidl b/media/java/android/media/musicrecognition/IMusicRecognitionService.aidl index 26543ed8bf8c..c970161a115b 100644 --- a/media/java/android/media/musicrecognition/IMusicRecognitionService.aidl +++ b/media/java/android/media/musicrecognition/IMusicRecognitionService.aidl @@ -4,6 +4,7 @@ import android.media.AudioFormat; import android.os.ParcelFileDescriptor; import android.os.IBinder; import android.media.musicrecognition.IMusicRecognitionServiceCallback; +import android.media.musicrecognition.IMusicRecognitionAttributionTagCallback; /** * Interface from the system to a {@link MusicRecognitionService}. @@ -15,4 +16,6 @@ oneway interface IMusicRecognitionService { in ParcelFileDescriptor fd, in AudioFormat audioFormat, in IMusicRecognitionServiceCallback callback); + + void getAttributionTag(in IMusicRecognitionAttributionTagCallback callback); }
\ No newline at end of file diff --git a/media/java/android/media/musicrecognition/IMusicRecognitionServiceCallback.aidl b/media/java/android/media/musicrecognition/IMusicRecognitionServiceCallback.aidl index 15215c4e15f1..10a65545cc7e 100644 --- a/media/java/android/media/musicrecognition/IMusicRecognitionServiceCallback.aidl +++ b/media/java/android/media/musicrecognition/IMusicRecognitionServiceCallback.aidl @@ -4,7 +4,7 @@ import android.os.Bundle; import android.media.MediaMetadata; /** - * Interface from a {@MusicRecognitionService} the system. + * Interface from a {@MusicRecognitionService} to the system. * * @hide */ diff --git a/media/java/android/media/musicrecognition/MusicRecognitionService.java b/media/java/android/media/musicrecognition/MusicRecognitionService.java index 04b4c39bf0fa..385aff01d45a 100644 --- a/media/java/android/media/musicrecognition/MusicRecognitionService.java +++ b/media/java/android/media/musicrecognition/MusicRecognitionService.java @@ -90,7 +90,7 @@ public abstract class MusicRecognitionService extends Service { try { callback.onRecognitionSucceeded(result, extras); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } } @@ -99,11 +99,18 @@ public abstract class MusicRecognitionService extends Service { try { callback.onRecognitionFailed(failureCode); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } } })); } + + @Override + public void getAttributionTag( + IMusicRecognitionAttributionTagCallback callback) throws RemoteException { + String tag = MusicRecognitionService.this.getAttributionTag(); + callback.onAttributionTag(tag); + } }; @Override diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java index 6b329f8ec694..b1baf94f844b 100644 --- a/media/java/android/media/tv/TvView.java +++ b/media/java/android/media/tv/TvView.java @@ -23,6 +23,8 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.content.Context; import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.content.res.XmlResourceParser; import android.graphics.Canvas; import android.graphics.PorterDuff; import android.graphics.Rect; @@ -39,6 +41,7 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.Pair; +import android.util.Xml; import android.view.InputEvent; import android.view.KeyEvent; import android.view.MotionEvent; @@ -99,6 +102,7 @@ public class TvView extends ViewGroup { private int mSurfaceWidth; private int mSurfaceHeight; private final AttributeSet mAttrs; + private final XmlResourceParser mParser; private final int mDefStyleAttr; private int mWindowZOrder; private boolean mUseRequestedSurfaceLayout; @@ -168,7 +172,16 @@ public class TvView extends ViewGroup { public TvView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - mAttrs = attrs; + int sourceResId = Resources.getAttributeSetSourceResId(attrs); + if (sourceResId != Resources.ID_NULL) { + Log.d(TAG, "Build local AttributeSet"); + mParser = context.getResources().getXml(sourceResId); + mAttrs = Xml.asAttributeSet(mParser); + } else { + Log.d(TAG, "Use passed in AttributeSet"); + mParser = null; + mAttrs = attrs; + } mDefStyleAttr = defStyleAttr; resetSurfaceView(); mTvInputManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE); diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java index ee70714ce763..e8ef46499dc8 100644 --- a/media/java/android/service/media/MediaBrowserService.java +++ b/media/java/android/service/media/MediaBrowserService.java @@ -46,6 +46,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -112,21 +113,34 @@ public abstract class MediaBrowserService extends Service { /** * All the info about a connection. */ - private class ConnectionRecord implements IBinder.DeathRecipient { - String pkg; - int uid; - int pid; - Bundle rootHints; - IMediaBrowserServiceCallbacks callbacks; - BrowserRoot root; - HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap<>(); + private static class ConnectionRecord implements IBinder.DeathRecipient { + public final MediaBrowserService service; + public final String pkg; + public final int pid; + public final int uid; + public final Bundle rootHints; + public final IMediaBrowserServiceCallbacks callbacks; + public final BrowserRoot root; + public final HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap<>(); + + ConnectionRecord( + MediaBrowserService service, String pkg, int pid, int uid, Bundle rootHints, + IMediaBrowserServiceCallbacks callbacks, BrowserRoot root) { + this.service = service; + this.pkg = pkg; + this.pid = pid; + this.uid = uid; + this.rootHints = rootHints; + this.callbacks = callbacks; + this.root = root; + } @Override public void binderDied() { - mHandler.post(new Runnable() { + service.mHandler.post(new Runnable() { @Override public void run() { - mConnections.remove(callbacks.asBinder()); + service.mConnections.remove(callbacks.asBinder()); } }); } @@ -199,39 +213,46 @@ public abstract class MediaBrowserService extends Service { } } - private class ServiceBinder extends IMediaBrowserService.Stub { + private static class ServiceBinder extends IMediaBrowserService.Stub { + private WeakReference<MediaBrowserService> mService; + + private ServiceBinder(MediaBrowserService service) { + mService = new WeakReference(service); + } + @Override public void connect(final String pkg, final Bundle rootHints, final IMediaBrowserServiceCallbacks callbacks) { + MediaBrowserService service = mService.get(); + if (service == null) { + return; + } final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); - if (!isValidPackage(pkg, uid)) { + if (!service.isValidPackage(pkg, uid)) { throw new IllegalArgumentException("Package/uid mismatch: uid=" + uid + " package=" + pkg); } - mHandler.post(new Runnable() { + service.mHandler.post(new Runnable() { @Override public void run() { final IBinder b = callbacks.asBinder(); // Clear out the old subscriptions. We are getting new ones. - mConnections.remove(b); - - final ConnectionRecord connection = new ConnectionRecord(); - connection.pkg = pkg; - connection.pid = pid; - connection.uid = uid; - connection.rootHints = rootHints; - connection.callbacks = callbacks; + service.mConnections.remove(b); - mCurConnection = connection; - connection.root = MediaBrowserService.this.onGetRoot(pkg, uid, rootHints); - mCurConnection = null; + // Temporarily sets a placeholder ConnectionRecord to make + // getCurrentBrowserInfo() work in onGetRoot(). + service.mCurConnection = + new ConnectionRecord( + service, pkg, pid, uid, rootHints, callbacks, null); + BrowserRoot root = service.onGetRoot(pkg, uid, rootHints); + service.mCurConnection = null; // If they didn't return something, don't allow this client. - if (connection.root == null) { + if (root == null) { Log.i(TAG, "No root for client " + pkg + " from service " + getClass().getName()); try { @@ -242,16 +263,19 @@ public abstract class MediaBrowserService extends Service { } } else { try { - mConnections.put(b, connection); + ConnectionRecord connection = + new ConnectionRecord( + service, pkg, pid, uid, rootHints, callbacks, root); + service.mConnections.put(b, connection); b.linkToDeath(connection, 0); - if (mSession != null) { + if (service.mSession != null) { callbacks.onConnect(connection.root.getRootId(), - mSession, connection.root.getExtras()); + service.mSession, connection.root.getExtras()); } } catch (RemoteException ex) { Log.w(TAG, "Calling onConnect() failed. Dropping client. " + "pkg=" + pkg); - mConnections.remove(b); + service.mConnections.remove(b); } } } @@ -260,13 +284,18 @@ public abstract class MediaBrowserService extends Service { @Override public void disconnect(final IMediaBrowserServiceCallbacks callbacks) { - mHandler.post(new Runnable() { + MediaBrowserService service = mService.get(); + if (service == null) { + return; + } + + service.mHandler.post(new Runnable() { @Override public void run() { final IBinder b = callbacks.asBinder(); // Clear out the old subscriptions. We are getting new ones. - final ConnectionRecord old = mConnections.remove(b); + final ConnectionRecord old = service.mConnections.remove(b); if (old != null) { // TODO old.callbacks.asBinder().unlinkToDeath(old, 0); @@ -283,20 +312,25 @@ public abstract class MediaBrowserService extends Service { @Override public void addSubscription(final String id, final IBinder token, final Bundle options, final IMediaBrowserServiceCallbacks callbacks) { - mHandler.post(new Runnable() { + MediaBrowserService service = mService.get(); + if (service == null) { + return; + } + + service.mHandler.post(new Runnable() { @Override public void run() { final IBinder b = callbacks.asBinder(); // Get the record for the connection - final ConnectionRecord connection = mConnections.get(b); + final ConnectionRecord connection = service.mConnections.get(b); if (connection == null) { Log.w(TAG, "addSubscription for callback that isn't registered id=" + id); return; } - MediaBrowserService.this.addSubscription(id, connection, token, options); + service.addSubscription(id, connection, token, options); } }); } @@ -310,18 +344,23 @@ public abstract class MediaBrowserService extends Service { @Override public void removeSubscription(final String id, final IBinder token, final IMediaBrowserServiceCallbacks callbacks) { - mHandler.post(new Runnable() { + MediaBrowserService service = mService.get(); + if (service == null) { + return; + } + + service.mHandler.post(new Runnable() { @Override public void run() { final IBinder b = callbacks.asBinder(); - ConnectionRecord connection = mConnections.get(b); + ConnectionRecord connection = service.mConnections.get(b); if (connection == null) { Log.w(TAG, "removeSubscription for callback that isn't registered id=" + id); return; } - if (!MediaBrowserService.this.removeSubscription(id, connection, token)) { + if (!service.removeSubscription(id, connection, token)) { Log.w(TAG, "removeSubscription called for " + id + " which is not subscribed"); } @@ -332,16 +371,21 @@ public abstract class MediaBrowserService extends Service { @Override public void getMediaItem(final String mediaId, final ResultReceiver receiver, final IMediaBrowserServiceCallbacks callbacks) { - mHandler.post(new Runnable() { + MediaBrowserService service = mService.get(); + if (service == null) { + return; + } + + service.mHandler.post(new Runnable() { @Override public void run() { final IBinder b = callbacks.asBinder(); - ConnectionRecord connection = mConnections.get(b); + ConnectionRecord connection = service.mConnections.get(b); if (connection == null) { Log.w(TAG, "getMediaItem for callback that isn't registered id=" + mediaId); return; } - performLoadItem(mediaId, connection, receiver); + service.performLoadItem(mediaId, connection, receiver); } }); } @@ -350,7 +394,7 @@ public abstract class MediaBrowserService extends Service { @Override public void onCreate() { super.onCreate(); - mBinder = new ServiceBinder(); + mBinder = new ServiceBinder(this); } @Override diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp index 6a622c5a1566..91178e53e97b 100644 --- a/media/jni/android_media_MediaExtractor.cpp +++ b/media/jni/android_media_MediaExtractor.cpp @@ -282,7 +282,6 @@ status_t JMediaExtractor::getMetrics(Parcel *reply) const { return status; } - status_t JMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) { return mImpl->getSampleMeta(sampleMeta); } @@ -295,6 +294,10 @@ status_t JMediaExtractor::getAudioPresentations(size_t trackIdx, AudioPresentationCollection *presentations) const { return mImpl->getAudioPresentations(trackIdx, presentations); } + +status_t JMediaExtractor::setPlaybackId(const String8 &playbackId) { + return mImpl->setPlaybackId(playbackId); +} } // namespace android //////////////////////////////////////////////////////////////////////////////// @@ -920,6 +923,23 @@ android_media_MediaExtractor_native_getMetrics(JNIEnv * env, jobject thiz) return mybundle; } +static void +android_media_MediaExtractor_native_setPlaybackId( + JNIEnv * env, jobject thiz, jstring playbackIdJString) +{ + ALOGV("android_media_MediaExtractor_native_setPlaybackId"); + + sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); + if (extractor == nullptr) { + jniThrowException(env, "java/lang/IllegalStateException", nullptr); + } + + const char* playbackId = env->GetStringUTFChars(playbackIdJString, nullptr); + if (extractor->setPlaybackId(String8(playbackId)) != OK) { + ALOGE("setPlaybackId failed"); + } + env->ReleaseStringUTFChars(playbackIdJString, playbackId); +} static const JNINativeMethod gMethods[] = { { "release", "()V", (void *)android_media_MediaExtractor_release }, @@ -990,6 +1010,9 @@ static const JNINativeMethod gMethods[] = { {"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaExtractor_native_getMetrics}, + { "native_setPlaybackId", "(Ljava/lang/String;)V", + (void *)android_media_MediaExtractor_native_setPlaybackId}, + { "native_getAudioPresentations", "(I)Ljava/util/List;", (void *)android_media_MediaExtractor_getAudioPresentations }, }; diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h index f5ba92e38455..9aaa643a2f37 100644 --- a/media/jni/android_media_MediaExtractor.h +++ b/media/jni/android_media_MediaExtractor.h @@ -70,6 +70,8 @@ struct JMediaExtractor : public RefBase { status_t getAudioPresentations(size_t trackIdx, AudioPresentationCollection *presentations) const; + status_t setPlaybackId(const String8& playbackId); + protected: virtual ~JMediaExtractor(); diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml index ed120b53d636..cdf4851a3e3d 100644 --- a/packages/CompanionDeviceManager/res/values-af/strings.xml +++ b/packages/CompanionDeviceManager/res/values-af/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"toestel"</string> <string name="profile_name_watch" msgid="576290739483672360">"horlosie"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Stel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> om jou <xliff:g id="PROFILE_NAME">%2$s</xliff:g> te bestuur – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Jy het <xliff:g id="APP_NAME">%1$s</xliff:g> nodig om jou <xliff:g id="PROFILE_NAME">%2$s</xliff:g> te bestuur. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Ja"</string> + <string name="consent_no" msgid="1335543792857823917">"Nee, dankie"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml index 76f68e7ee495..a03ea0dfcd4c 100644 --- a/packages/CompanionDeviceManager/res/values-am/strings.xml +++ b/packages/CompanionDeviceManager/res/values-am/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"መሣሪያ"</string> <string name="profile_name_watch" msgid="576290739483672360">"ሰዓት"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> የእርስዎን <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> እንዲያስተዳድር ያቀናብሩት"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> የእርስዎን <xliff:g id="PROFILE_NAME">%2$s</xliff:g> ለማስተዳደር ያስፈልጋል። <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"አዎ"</string> + <string name="consent_no" msgid="1335543792857823917">"አይ፣ አመሰግናለሁ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml index 92783a529cfc..970c46bd6133 100644 --- a/packages/CompanionDeviceManager/res/values-ar/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"جهاز"</string> <string name="profile_name_watch" msgid="576290739483672360">"ساعة"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"اضبط <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> لإدارة <xliff:g id="PROFILE_NAME">%2$s</xliff:g> على <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"يجب توفّر تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> لإدارة <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"نعم"</string> + <string name="consent_no" msgid="1335543792857823917">"لا، شكرًا"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml index 34ce062e0f4a..477844c2a477 100644 --- a/packages/CompanionDeviceManager/res/values-as/strings.xml +++ b/packages/CompanionDeviceManager/res/values-as/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইচ"</string> <string name="profile_name_watch" msgid="576290739483672360">"ঘড়ী"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"আপোনাৰ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> পৰিচালনা কৰিবলৈ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ছেট কৰক - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"আপোনাৰ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> পৰিচালনা কৰিবলৈ <xliff:g id="APP_NAME">%1$s</xliff:g>ৰ আৱশ্যক। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"হয়"</string> + <string name="consent_no" msgid="1335543792857823917">"নালাগে, ধন্যবাদ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml index b07cad615d57..f10c639a0368 100644 --- a/packages/CompanionDeviceManager/res/values-az/strings.xml +++ b/packages/CompanionDeviceManager/res/values-az/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string> <string name="profile_name_watch" msgid="576290739483672360">"izləyin"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> profilinizin <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tərəfindən idarə olunmasını ayarlayın - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> profilinizi idarə etmək üçün <xliff:g id="APP_NAME">%1$s</xliff:g> tələb olunur. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Bəli"</string> + <string name="consent_no" msgid="1335543792857823917">"Xeyr, çox sağolun"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml index edeaa7785e36..e8542f364027 100644 --- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string> <string name="profile_name_watch" msgid="576290739483672360">"sat"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Podesite aplikaciju <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja profilom <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je neophodna za upravljanje profilom <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Da"</string> + <string name="consent_no" msgid="1335543792857823917">"Ne, hvala"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml index 9410d686133b..13be6f245ac0 100644 --- a/packages/CompanionDeviceManager/res/values-be/strings.xml +++ b/packages/CompanionDeviceManager/res/values-be/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"прылада"</string> <string name="profile_name_watch" msgid="576290739483672360">"гадзіннік"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Дазвольце праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> кіраваць прыладай \"<xliff:g id="PROFILE_NAME">%2$s</xliff:g>\" – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Для кіравання прыладай \"<xliff:g id="PROFILE_NAME">%2$s</xliff:g>\" патрабуецца праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\". <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Так"</string> + <string name="consent_no" msgid="1335543792857823917">"Не, дзякуй"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml index 4457dbd2cb3a..3bda5e6104c8 100644 --- a/packages/CompanionDeviceManager/res/values-bg/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string> <string name="profile_name_watch" msgid="576290739483672360">"часовник"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Задайте <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да управлява устройството ви (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"За управление на <xliff:g id="PROFILE_NAME">%2$s</xliff:g> се изисква <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Да"</string> + <string name="consent_no" msgid="1335543792857823917">"Не, благодаря"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml index 4aa7e74e5432..d3bc5152af9a 100644 --- a/packages/CompanionDeviceManager/res/values-bn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইস"</string> <string name="profile_name_watch" msgid="576290739483672360">"দেখুন"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"আপনার <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ম্যানেজ করার জন্য <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> সেট করুন"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g>-কে আপনার <xliff:g id="PROFILE_NAME">%2$s</xliff:g>.ম্যানেজ করতে দিতে হবে। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"হ্যাঁ"</string> + <string name="consent_no" msgid="1335543792857823917">"না থাক"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml index 8ffa3272fb8c..905b3061ffc6 100644 --- a/packages/CompanionDeviceManager/res/values-bs/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string> <string name="profile_name_watch" msgid="576290739483672360">"sat"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Postavite aplikaciju <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja vašim uređajem <xliff:g id="PROFILE_NAME">%2$s</xliff:g> — <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Potrebna je aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> za upravljanje uređajem <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Da"</string> + <string name="consent_no" msgid="1335543792857823917">"Ne, hvala"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml index c9c186eba741..86dc6940abe2 100644 --- a/packages/CompanionDeviceManager/res/values-ca/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"dispositiu"</string> <string name="profile_name_watch" msgid="576290739483672360">"rellotge"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Defineix que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gestioni el teu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (<strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>)"</string> + <string name="profile_summary" msgid="2009764182871566255">"L\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g> és necessària per gestionar el teu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Sí"</string> + <string name="consent_no" msgid="1335543792857823917">"No, gràcies"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml index b2ac32db2a99..389ccd0ccc95 100644 --- a/packages/CompanionDeviceManager/res/values-cs/strings.xml +++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"zařízení"</string> <string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Nastavit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ke správě tohoto zařízení: <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Ke správě profilu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> je potřeba aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Ano"</string> + <string name="consent_no" msgid="1335543792857823917">"Ne, díky"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml index bc67948c3ecf..5a31f9bba4b6 100644 --- a/packages/CompanionDeviceManager/res/values-da/strings.xml +++ b/packages/CompanionDeviceManager/res/values-da/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"enhed"</string> <string name="profile_name_watch" msgid="576290739483672360">"ur"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Angiv <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> til administration af: <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> er nødvendig for at administrere: <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Ja"</string> + <string name="consent_no" msgid="1335543792857823917">"Nej tak"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml index 1c7ec74f4494..b643eb2936ce 100644 --- a/packages/CompanionDeviceManager/res/values-de/strings.xml +++ b/packages/CompanionDeviceManager/res/values-de/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string> <string name="profile_name_watch" msgid="576290739483672360">"Smartwatch"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> zum Verwalten deines Geräts (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) festlegen – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> ist erforderlich, um dein Gerät (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) zu verwalten. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Ja"</string> + <string name="consent_no" msgid="1335543792857823917">"Nein danke"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml index fed516fb04eb..60de2ffe0572 100644 --- a/packages/CompanionDeviceManager/res/values-el/strings.xml +++ b/packages/CompanionDeviceManager/res/values-el/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"συσκευή"</string> <string name="profile_name_watch" msgid="576290739483672360">"ρολόι"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Ορίστε μια εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> για διαχείριση του προφίλ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> απαιτείται για τη διαχείριση του προφίλ <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Ναι"</string> + <string name="consent_no" msgid="1335543792857823917">"Όχι, ευχαριστώ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml index 4fd057f3e7e4..2fed1ae7fec3 100644 --- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml @@ -20,12 +20,8 @@ <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="profile_name_watch" msgid="576290739483672360">"watch"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Set <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Yes"</string> + <string name="consent_no" msgid="1335543792857823917">"No, thanks"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml index 4fd057f3e7e4..2fed1ae7fec3 100644 --- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml @@ -20,12 +20,8 @@ <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="profile_name_watch" msgid="576290739483672360">"watch"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Set <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Yes"</string> + <string name="consent_no" msgid="1335543792857823917">"No, thanks"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml index 4fd057f3e7e4..2fed1ae7fec3 100644 --- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml @@ -20,12 +20,8 @@ <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="profile_name_watch" msgid="576290739483672360">"watch"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Set <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Yes"</string> + <string name="consent_no" msgid="1335543792857823917">"No, thanks"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml index 4fd057f3e7e4..2fed1ae7fec3 100644 --- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml @@ -20,12 +20,8 @@ <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="profile_name_watch" msgid="576290739483672360">"watch"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Set <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Yes"</string> + <string name="consent_no" msgid="1335543792857823917">"No, thanks"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml index 0e3902c50aea..f3c4b1dcb434 100644 --- a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml @@ -20,12 +20,8 @@ <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by <strong><xliff:g id="APP_NAME">%2$s</xliff:g></strong>"</string> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="profile_name_watch" msgid="576290739483672360">"watch"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Set <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> is needed to manage your <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Yes"</string> + <string name="consent_no" msgid="1335543792857823917">"No thanks"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml index 6b903c609fe9..4fbb57ed9440 100644 --- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml +++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="profile_name_watch" msgid="576290739483672360">"reloj"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Configura <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> para administrar <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Se requiere <xliff:g id="APP_NAME">%1$s</xliff:g> para administrar tu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Sí"</string> + <string name="consent_no" msgid="1335543792857823917">"No, gracias"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml index 0a2906a97a39..5ca9305ce4d6 100644 --- a/packages/CompanionDeviceManager/res/values-es/strings.xml +++ b/packages/CompanionDeviceManager/res/values-es/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="profile_name_watch" msgid="576290739483672360">"reloj"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Haz que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gestione tu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Se necesita <xliff:g id="APP_NAME">%1$s</xliff:g> para gestionar tu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Sí"</string> + <string name="consent_no" msgid="1335543792857823917">"No, gracias"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml index 4958a17206f7..357f05237b85 100644 --- a/packages/CompanionDeviceManager/res/values-et/strings.xml +++ b/packages/CompanionDeviceManager/res/values-et/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"seade"</string> <string name="profile_name_watch" msgid="576290739483672360">"käekell"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Määrake rakendus <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> haldama teie seadet <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> on vajalik teie seadme <xliff:g id="PROFILE_NAME">%2$s</xliff:g> haldamiseks. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Jah"</string> + <string name="consent_no" msgid="1335543792857823917">"Tänan, ei"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml index 2a61fd519511..14c7154acdd3 100644 --- a/packages/CompanionDeviceManager/res/values-eu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string> <string name="profile_name_watch" msgid="576290739483672360">"erlojua"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Konfiguratu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (<strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>) kudea dezan"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> erabili behar duzu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> kudeatzeko. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Bai"</string> + <string name="consent_no" msgid="1335543792857823917">"Ez"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml index 8d102303d91a..6bb9620f09f7 100644 --- a/packages/CompanionDeviceManager/res/values-fa/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"دستگاه"</string> <string name="profile_name_watch" msgid="576290739483672360">"ساعت"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"تنظیم <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> برای مدیریت کردن <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"برای مدیریت کردن <xliff:g id="PROFILE_NAME">%2$s</xliff:g> به <xliff:g id="APP_NAME">%1$s</xliff:g> نیاز دارید. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"بله"</string> + <string name="consent_no" msgid="1335543792857823917">"نه متشکرم"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml index cfa03af870dc..5a9c1cd66aa8 100644 --- a/packages/CompanionDeviceManager/res/values-fi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"laite"</string> <string name="profile_name_watch" msgid="576290739483672360">"kello"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Aseta <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> profiilin (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) hallinnoijaksi – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> tarvitaan profiilin (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) hallinnointiin. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Kyllä"</string> + <string name="consent_no" msgid="1335543792857823917">"Ei kiitos"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml index d3cfc299c4ce..b31babda1a00 100644 --- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string> <string name="profile_name_watch" msgid="576290739483672360">"montre"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Utiliser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pour gérer votre <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"L\'application <xliff:g id="APP_NAME">%1$s</xliff:g> est requise pour gérer votre <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Oui"</string> + <string name="consent_no" msgid="1335543792857823917">"Non merci"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml index d82e3905c5d1..08c93a2c31c6 100644 --- a/packages/CompanionDeviceManager/res/values-fr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string> <string name="profile_name_watch" msgid="576290739483672360">"montre"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Définir <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pour la gestion de votre <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> est requis pour gérer votre <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Oui"</string> + <string name="consent_no" msgid="1335543792857823917">"Non, merci"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml index 2a85398cf3cc..c95b90e73edc 100644 --- a/packages/CompanionDeviceManager/res/values-gl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="profile_name_watch" msgid="576290739483672360">"reloxo"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Define a aplicación <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> para a xestión do teu perfil (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>): <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Necesítase a aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> para xestionar o teu perfil (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>). <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Si"</string> + <string name="consent_no" msgid="1335543792857823917">"Non, grazas"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml index 6f52403ed416..7e4104208446 100644 --- a/packages/CompanionDeviceManager/res/values-gu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"ડિવાઇસ"</string> <string name="profile_name_watch" msgid="576290739483672360">"સ્માર્ટવૉચ"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"તમારા <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>ને મેનેજ કરવા માટે <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> સેટ કરો"</string> + <string name="profile_summary" msgid="2009764182871566255">"તમારા <xliff:g id="PROFILE_NAME">%2$s</xliff:g>ને મેનેજ કરવા માટે <xliff:g id="APP_NAME">%1$s</xliff:g> જરૂરી છે. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"હા"</string> + <string name="consent_no" msgid="1335543792857823917">"ના, આભાર"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml index 9af99924c76a..ac95cc620bfa 100644 --- a/packages/CompanionDeviceManager/res/values-hi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string> <string name="profile_name_watch" msgid="576290739483672360">"स्मार्टवॉच"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"अपने <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> को प्रबंधित करने के लिए, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को सेट करें"</string> + <string name="profile_summary" msgid="2009764182871566255">"आपके <xliff:g id="PROFILE_NAME">%2$s</xliff:g> को प्रबंधित करने के लिए, <xliff:g id="APP_NAME">%1$s</xliff:g> की ज़रूरत है. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"हां"</string> + <string name="consent_no" msgid="1335543792857823917">"नहीं, रहने दें"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml index fe30ec485169..df8451f5f127 100644 --- a/packages/CompanionDeviceManager/res/values-hr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string> <string name="profile_name_watch" msgid="576290739483672360">"satom"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Postavite aplikaciju <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja vašim profilom <xliff:g id="PROFILE_NAME">%2$s</xliff:g> –- <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> potrebna je za upravljanje vašim <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Da"</string> + <string name="consent_no" msgid="1335543792857823917">"Ne, hvala"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml index 370d4dff6a98..ff1c6c54d7ba 100644 --- a/packages/CompanionDeviceManager/res/values-hu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"eszköz"</string> <string name="profile_name_watch" msgid="576290739483672360">"óra"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"A(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> alkalmazás beállítása a(z) <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (<strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>) kezelésére"</string> + <string name="profile_summary" msgid="2009764182871566255">"Szükség van a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazásra a(z) <xliff:g id="PROFILE_NAME">%2$s</xliff:g> kezeléséhez. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Igen"</string> + <string name="consent_no" msgid="1335543792857823917">"Nem"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml index fee55d0c5396..194223d1d416 100644 --- a/packages/CompanionDeviceManager/res/values-hy/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"սարք"</string> <string name="profile_name_watch" msgid="576290739483672360">"ժամացույց"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Ընտրեք <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածը որպես <xliff:g id="PROFILE_NAME">%2$s</xliff:g>ի կառավարիչ․ <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Ձեր <xliff:g id="PROFILE_NAME">%2$s</xliff:g>ը կառավարելու համար անհրաժեշտ է <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը։ <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Այո"</string> + <string name="consent_no" msgid="1335543792857823917">"Ոչ, շնորհակալություն"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml index 498bf2cd3351..58bf3cb4bca4 100644 --- a/packages/CompanionDeviceManager/res/values-in/strings.xml +++ b/packages/CompanionDeviceManager/res/values-in/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string> <string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Tetapkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengelola <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Perlu <xliff:g id="APP_NAME">%1$s</xliff:g> untuk mengelola <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Ya"</string> + <string name="consent_no" msgid="1335543792857823917">"Tidak"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml index bd12658284ef..cc5b98939b71 100644 --- a/packages/CompanionDeviceManager/res/values-is/strings.xml +++ b/packages/CompanionDeviceManager/res/values-is/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"tæki"</string> <string name="profile_name_watch" msgid="576290739483672360">"úr"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Veita <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> stjórn á <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> er krafist til að stjórna <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Já"</string> + <string name="consent_no" msgid="1335543792857823917">"Nei, takk"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml index 40d43207bced..4cbefd801187 100644 --- a/packages/CompanionDeviceManager/res/values-it/strings.xml +++ b/packages/CompanionDeviceManager/res/values-it/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="profile_name_watch" msgid="576290739483672360">"orologio"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Configura <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> per gestire il tuo <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"È richiesta l\'app <xliff:g id="APP_NAME">%1$s</xliff:g> per gestire il tuo <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Sì"</string> + <string name="consent_no" msgid="1335543792857823917">"No, grazie"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml index 807cdd471642..8663e56ecf14 100644 --- a/packages/CompanionDeviceManager/res/values-iw/strings.xml +++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"מכשיר"</string> <string name="profile_name_watch" msgid="576290739483672360">"שעון"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"הגדרה של <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> לניהול <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> נדרשת לניהול של <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"כן"</string> + <string name="consent_no" msgid="1335543792857823917">"לא תודה"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml index 92022be9fade..ca17336bfb23 100644 --- a/packages/CompanionDeviceManager/res/values-ja/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"デバイス"</string> <string name="profile_name_watch" msgid="576290739483672360">"ウォッチ"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> で <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> を管理するよう設定する"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> を管理するために <xliff:g id="APP_NAME">%1$s</xliff:g> が必要です。<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"はい"</string> + <string name="consent_no" msgid="1335543792857823917">"いいえ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml index 64a79b48ec7e..300c94f63cbe 100644 --- a/packages/CompanionDeviceManager/res/values-ka/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"მოწყობილობა"</string> <string name="profile_name_watch" msgid="576290739483672360">"საათი"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"დააყენეთ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>, რომ მართოს თქვენი <xliff:g id="PROFILE_NAME">%2$s</xliff:g> — <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"თქვენი <xliff:g id="PROFILE_NAME">%2$s</xliff:g>-ის სამართავად საჭიროა <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"დიახ"</string> + <string name="consent_no" msgid="1335543792857823917">"არა, გმადლობთ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml index edd5c0ee9cd0..94d6c3ed2d5f 100644 --- a/packages/CompanionDeviceManager/res/values-kk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"құрылғы"</string> <string name="profile_name_watch" msgid="576290739483672360">"сағат"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>) құрылғысын басқаруға рұқсат беру"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> құрылғысын басқару үшін <xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы керек. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Иә"</string> + <string name="consent_no" msgid="1335543792857823917">"Жоқ, рақмет"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml index 36c02de6790d..db13fe7884af 100644 --- a/packages/CompanionDeviceManager/res/values-km/strings.xml +++ b/packages/CompanionDeviceManager/res/values-km/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"ឧបករណ៍"</string> <string name="profile_name_watch" msgid="576290739483672360">"នាឡិកា"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"កំណត់ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ដើម្បីគ្រប់គ្រង <xliff:g id="PROFILE_NAME">%2$s</xliff:g> របស់អ្នក - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"ចាំបាច់ត្រូវមាន <xliff:g id="APP_NAME">%1$s</xliff:g> ដើម្បីគ្រប់គ្រង <xliff:g id="PROFILE_NAME">%2$s</xliff:g> របស់អ្នក។ <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"បាទ/ចាស"</string> + <string name="consent_no" msgid="1335543792857823917">"ទេ អរគុណ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml index 56c1557e5fef..0225166849fd 100644 --- a/packages/CompanionDeviceManager/res/values-kn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"ಸಾಧನ"</string> <string name="profile_name_watch" msgid="576290739483672360">"ವೀಕ್ಷಿಸಿ"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"ನಿಮ್ಮ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ಅನ್ನು ನಿರ್ವಹಿಸಲು, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಅನ್ನು ನಿರ್ವಹಿಸಿ"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> ಅನ್ನು ನಿರ್ವಹಿಸಲು, <xliff:g id="APP_NAME">%1$s</xliff:g> ಅಗತ್ಯವಿದೆ. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"ಹೌದು"</string> + <string name="consent_no" msgid="1335543792857823917">"ಬೇಡ, ಧನ್ಯವಾದಗಳು"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml index 79c36dd017fa..1363e57e39a3 100644 --- a/packages/CompanionDeviceManager/res/values-ko/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"기기"</string> <string name="profile_name_watch" msgid="576290739483672360">"시계"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <xliff:g id="PROFILE_NAME">%2$s</xliff:g>(<strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>)을(를) 관리하도록 설정"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> 프로필을 관리하려면 <xliff:g id="APP_NAME">%1$s</xliff:g> 앱이 필요합니다. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"예"</string> + <string name="consent_no" msgid="1335543792857823917">"취소"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml index 8a90b3dc7d6a..c01e2350aa04 100644 --- a/packages/CompanionDeviceManager/res/values-ky/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"түзмөк"</string> <string name="profile_name_watch" msgid="576290739483672360">"саат"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> түзмөгүңүздү башкарсын"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> профилиңизди башкаруу үчүн <xliff:g id="APP_NAME">%1$s</xliff:g> керек. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Ооба"</string> + <string name="consent_no" msgid="1335543792857823917">"Жок, рахмат"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml index a6564b347651..68218dd79c50 100644 --- a/packages/CompanionDeviceManager/res/values-lo/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"ອຸປະກອນ"</string> <string name="profile_name_watch" msgid="576290739483672360">"ໂມງ"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"ຕັ້ງ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ເພື່ອຈັດການ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ຂອງທ່ານ"</string> + <string name="profile_summary" msgid="2009764182871566255">"ຕ້ອງໃຊ້ <xliff:g id="APP_NAME">%1$s</xliff:g> ເພື່ອຈັດການ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> ຂອງທ່ານ. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"ແມ່ນແລ້ວ"</string> + <string name="consent_no" msgid="1335543792857823917">"ບໍ່, ຂອບໃຈ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml index 382f1cf69a2d..5fd8280affca 100644 --- a/packages/CompanionDeviceManager/res/values-lt/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"įrenginys"</string> <string name="profile_name_watch" msgid="576290739483672360">"laikrodis"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Nustatyti, kad <xliff:g id="PROFILE_NAME">%2$s</xliff:g> <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> būtų valdomas programos <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Norint valdyti jūsų <xliff:g id="PROFILE_NAME">%2$s</xliff:g>, reikalinga programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Taip"</string> + <string name="consent_no" msgid="1335543792857823917">"Ne, ačiū"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml index 8d70bf788e27..bf036ec70d73 100644 --- a/packages/CompanionDeviceManager/res/values-lv/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"ierīce"</string> <string name="profile_name_watch" msgid="576290739483672360">"pulkstenis"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Lietotnes <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> iestatīšana profila (<xliff:g id="PROFILE_NAME">%2$s</xliff:g> — <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>) pārvaldībai"</string> + <string name="profile_summary" msgid="2009764182871566255">"Lai pārvaldītu profilu (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>), nepieciešama lietotne <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Jā"</string> + <string name="consent_no" msgid="1335543792857823917">"Nē, paldies"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml index 5322e98c37b7..427ca8f940a0 100644 --- a/packages/CompanionDeviceManager/res/values-mk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"уред"</string> <string name="profile_name_watch" msgid="576290739483672360">"часовник"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Поставете ја <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да управува со <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> е потребна за да управува со <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Да"</string> + <string name="consent_no" msgid="1335543792857823917">"Не, фала"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml index a9262c7973fb..a48c45f73ae7 100644 --- a/packages/CompanionDeviceManager/res/values-ml/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"ഉപകരണം"</string> <string name="profile_name_watch" msgid="576290739483672360">"വാച്ച്"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"നിങ്ങളുടെ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> മാനേജ് ചെയ്യുന്നതിന് <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> സജ്ജീകരിക്കുക - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്ന ആപ്പിന് നിങ്ങളുടെ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> മാനേജ് ചെയ്യേണ്ടതുണ്ട്. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"വേണം"</string> + <string name="consent_no" msgid="1335543792857823917">"വേണ്ട"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml index 303286466f4b..7ac20e613185 100644 --- a/packages/CompanionDeviceManager/res/values-mn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"төхөөрөмж"</string> <string name="profile_name_watch" msgid="576290739483672360">"цаг"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g>-аа удирдахын тулд <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-г тохируулна уу - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Таны <xliff:g id="PROFILE_NAME">%2$s</xliff:g>-г удирдахын тулд <xliff:g id="APP_NAME">%1$s</xliff:g> шаардлагатай. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Тийм"</string> + <string name="consent_no" msgid="1335543792857823917">"Үгүй, баярлалаа"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml index 01dae7d3a21e..144698b9bc4e 100644 --- a/packages/CompanionDeviceManager/res/values-mr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"डिव्हाइस"</string> <string name="profile_name_watch" msgid="576290739483672360">"पाहा"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"तुमची <xliff:g id="PROFILE_NAME">%2$s</xliff:g> व्यवस्थापित करण्यासाठी <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> सेट करा - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"तुमची <xliff:g id="PROFILE_NAME">%2$s</xliff:g> व्यवस्थापित करण्यासाठी <xliff:g id="APP_NAME">%1$s</xliff:g> आवश्यक आहे. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"होय"</string> + <string name="consent_no" msgid="1335543792857823917">"नाही, नको"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml index 4e0f58bc2653..7bea2c91fd2d 100644 --- a/packages/CompanionDeviceManager/res/values-ms/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string> <string name="profile_name_watch" msgid="576290739483672360">"jam tangan"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Tetapkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengurus <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> anda"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> diperlukan untuk mengurus <xliff:g id="PROFILE_NAME">%2$s</xliff:g> anda. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Ya"</string> + <string name="consent_no" msgid="1335543792857823917">"Tidak perlu"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml index 050c8ce4364a..9c2783cdcbbb 100644 --- a/packages/CompanionDeviceManager/res/values-my/strings.xml +++ b/packages/CompanionDeviceManager/res/values-my/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"စက်"</string> <string name="profile_name_watch" msgid="576290739483672360">"နာရီ"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"သင်၏ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ကို စီမံခန့်ခွဲရန် <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ကို သတ်မှတ်ပါ"</string> + <string name="profile_summary" msgid="2009764182871566255">"သင်၏ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> ကို စီမံခန့်ခွဲရန် <xliff:g id="APP_NAME">%1$s</xliff:g> ကို လိုအပ်ပါသည်။ <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Yes"</string> + <string name="consent_no" msgid="1335543792857823917">"မလိုပါ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml index a8e22033faed..26fbb0350edc 100644 --- a/packages/CompanionDeviceManager/res/values-nb/strings.xml +++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string> <string name="profile_name_watch" msgid="576290739483672360">"klokke"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Angi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> for å administrere <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> kreves for å administrere <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Ja"</string> + <string name="consent_no" msgid="1335543792857823917">"Nei takk"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml index 45bfb5f469ee..f289b3780672 100644 --- a/packages/CompanionDeviceManager/res/values-ne/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"यन्त्र"</string> <string name="profile_name_watch" msgid="576290739483672360">"घडी"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"आफ्नो <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> व्यवस्थापन गर्न <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> तोक्नुहोस्"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> व्यवस्थापन गर्न <xliff:g id="APP_NAME">%1$s</xliff:g> इन्स्टल गर्नु पर्ने हुन्छ। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"अँ"</string> + <string name="consent_no" msgid="1335543792857823917">"सहमत छुइनँ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml index e7e03904843e..0c9cdffd4e17 100644 --- a/packages/CompanionDeviceManager/res/values-nl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string> <string name="profile_name_watch" msgid="576290739483672360">"horloge"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> instellen om je <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> te beheren"</string> + <string name="profile_summary" msgid="2009764182871566255">"Je hebt <xliff:g id="APP_NAME">%1$s</xliff:g> nodig om je <xliff:g id="PROFILE_NAME">%2$s</xliff:g> te beheren. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Ja"</string> + <string name="consent_no" msgid="1335543792857823917">"Nee, bedankt"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml index 1f516fa4c0d0..c8c680f8f3a9 100644 --- a/packages/CompanionDeviceManager/res/values-or/strings.xml +++ b/packages/CompanionDeviceManager/res/values-or/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"ଡିଭାଇସ୍"</string> <string name="profile_name_watch" msgid="576290739483672360">"ୱାଚ୍"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"ଆପଣଙ୍କ <xliff:g id="PROFILE_NAME">%2$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ସେଟ୍ କରନ୍ତୁ - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"ଆପଣଙ୍କ <xliff:g id="PROFILE_NAME">%2$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆବଶ୍ୟକ। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"ହଁ"</string> + <string name="consent_no" msgid="1335543792857823917">"ନା, ଧନ୍ୟବାଦ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml index 03693dc74274..0da94105a576 100644 --- a/packages/CompanionDeviceManager/res/values-pa/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"ਡੀਵਾਈਸ"</string> <string name="profile_name_watch" msgid="576290739483672360">"ਸਮਾਰਟ-ਵਾਚ"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ ਤੁਹਾਡਾ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਸੈੱਟ ਕਰੋ"</string> + <string name="profile_summary" msgid="2009764182871566255">"ਤੁਹਾਡੇ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ <xliff:g id="APP_NAME">%1$s</xliff:g> ਦੀ ਲੋੜ ਹੈ। <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"ਹਾਂ"</string> + <string name="consent_no" msgid="1335543792857823917">"ਨਹੀਂ ਧੰਨਵਾਦ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml index 7adf064e80b6..b07af57a936a 100644 --- a/packages/CompanionDeviceManager/res/values-pl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"urządzenie"</string> <string name="profile_name_watch" msgid="576290739483672360">"zegarek"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Ustaw aplikację <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> do zarządzania profilem <xliff:g id="PROFILE_NAME">%2$s</xliff:g> na urządzeniu <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest wymagana do zarządzania profilem <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Tak"</string> + <string name="consent_no" msgid="1335543792857823917">"Nie, dziękuję"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml index b5ddc6db6f78..16906f62f9f1 100644 --- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Defina o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> como gerenciador do seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (<strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>)"</string> + <string name="profile_summary" msgid="2009764182871566255">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> é necessário para gerenciar seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Sim"</string> + <string name="consent_no" msgid="1335543792857823917">"Agora não"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml index c06ac7de1c11..745d1630dd86 100644 --- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Defina a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> para gerir o seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> é necessária para gerir o seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Sim"</string> + <string name="consent_no" msgid="1335543792857823917">"Não, obrigado"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml index b5ddc6db6f78..16906f62f9f1 100644 --- a/packages/CompanionDeviceManager/res/values-pt/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Defina o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> como gerenciador do seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> (<strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>)"</string> + <string name="profile_summary" msgid="2009764182871566255">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> é necessário para gerenciar seu <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Sim"</string> + <string name="consent_no" msgid="1335543792857823917">"Agora não"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml index 437e8dc78c76..187cfbdfe6f0 100644 --- a/packages/CompanionDeviceManager/res/values-ro/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"dispozitiv"</string> <string name="profile_name_watch" msgid="576290739483672360">"ceas"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Setați <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pentru a vă gestiona profilul <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> este necesară pentru a vă gestiona profilul <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Da"</string> + <string name="consent_no" msgid="1335543792857823917">"Nu, mulțumesc"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml index d087959971b6..8dd9a392712b 100644 --- a/packages/CompanionDeviceManager/res/values-ru/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string> <string name="profile_name_watch" msgid="576290739483672360">"часы"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Разрешите приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> управлять устройством <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>)"</string> + <string name="profile_summary" msgid="2009764182871566255">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" необходимо для управления устройством (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>). <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Да"</string> + <string name="consent_no" msgid="1335543792857823917">"Нет"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml index 365b6bfb3d2a..9e7c02e0c0d9 100644 --- a/packages/CompanionDeviceManager/res/values-si/strings.xml +++ b/packages/CompanionDeviceManager/res/values-si/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"උපාංගය"</string> <string name="profile_name_watch" msgid="576290739483672360">"ඔරලෝසුව"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ඔබගේ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> කළමනාකරණය කිරීමට සකසන්න - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"ඔබගේ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> කළමනාකරණය කිරීමට <xliff:g id="APP_NAME">%1$s</xliff:g> අවශ්යයි. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"ඔව්"</string> + <string name="consent_no" msgid="1335543792857823917">"එපා, ස්තුතියි"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml index d5c099a36424..55a47c2df427 100644 --- a/packages/CompanionDeviceManager/res/values-sk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string> <string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Nastavte aplikáciu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>, aby spravovala profil <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Na správu profilu <xliff:g id="PROFILE_NAME">%2$s</xliff:g> je potrebná aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Áno"</string> + <string name="consent_no" msgid="1335543792857823917">"Nie, vďaka"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml index d855db1cea72..159afd543609 100644 --- a/packages/CompanionDeviceManager/res/values-sl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"naprava"</string> <string name="profile_name_watch" msgid="576290739483672360">"ura"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Nastavitev aplikacije <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>, ki bo upravljala napravo <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Za upravljanje naprave <xliff:g id="PROFILE_NAME">%2$s</xliff:g> potrebujete aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Da"</string> + <string name="consent_no" msgid="1335543792857823917">"Ne, hvala"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml index 7335446765da..6fa759c15905 100644 --- a/packages/CompanionDeviceManager/res/values-sq/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string> <string name="profile_name_watch" msgid="576290739483672360">"ora inteligjente"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Cakto <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> që të menaxhojë profilin tënd <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Nevojitet <xliff:g id="APP_NAME">%1$s</xliff:g> për të menaxhuar profilin tënd të <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Po"</string> + <string name="consent_no" msgid="1335543792857823917">"Jo, faleminderit"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml index f3f65e17101b..fdbbe8e668f5 100644 --- a/packages/CompanionDeviceManager/res/values-sr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"уређај"</string> <string name="profile_name_watch" msgid="576290739483672360">"сат"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Подесите апликацију <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да управља профилом <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је неопходна за управљање профилом <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Да"</string> + <string name="consent_no" msgid="1335543792857823917">"Не, хвала"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml index 574166822006..bfd25162aec6 100644 --- a/packages/CompanionDeviceManager/res/values-sv/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string> <string name="profile_name_watch" msgid="576290739483672360">"klocka"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Konfigurera <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> för att hantera din <xliff:g id="PROFILE_NAME">%2$s</xliff:g> – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> krävs för att hantera din <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Ja"</string> + <string name="consent_no" msgid="1335543792857823917">"Nej tack"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml index 357eb4a475b8..437ae7f332e8 100644 --- a/packages/CompanionDeviceManager/res/values-sw/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"kifaa"</string> <string name="profile_name_watch" msgid="576290739483672360">"saa"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Weka <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ili udhibiti <xliff:g id="PROFILE_NAME">%2$s</xliff:g> yako - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g> linahitajika ili kudhibiti <xliff:g id="PROFILE_NAME">%2$s</xliff:g> yako. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Ndiyo"</string> + <string name="consent_no" msgid="1335543792857823917">"Hapana"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml index 651d9e276a7a..9b4a720a4863 100644 --- a/packages/CompanionDeviceManager/res/values-ta/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"சாதனம்"</string> <string name="profile_name_watch" msgid="576290739483672360">"வாட்ச்"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> ஐ நிர்வகிக்க <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அமையுங்கள்"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> ஐ நிர்வகிக்க <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் வேண்டும். <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"ஆம்"</string> + <string name="consent_no" msgid="1335543792857823917">"வேண்டாம்"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml index 9c3e334c9373..6e785de583aa 100644 --- a/packages/CompanionDeviceManager/res/values-te/strings.xml +++ b/packages/CompanionDeviceManager/res/values-te/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"పరికరం"</string> <string name="profile_name_watch" msgid="576290739483672360">"వాచ్"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"మీ <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>ను మేనేజ్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను సెటప్ చేయండి"</string> + <string name="profile_summary" msgid="2009764182871566255">"మీ <xliff:g id="PROFILE_NAME">%2$s</xliff:g>ను మేనేజ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> అవసరం ఉంది. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"అవును"</string> + <string name="consent_no" msgid="1335543792857823917">"వద్దు, ధన్యవాదాలు"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml index 557515af6ac8..b727d42035dd 100644 --- a/packages/CompanionDeviceManager/res/values-th/strings.xml +++ b/packages/CompanionDeviceManager/res/values-th/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"อุปกรณ์"</string> <string name="profile_name_watch" msgid="576290739483672360">"นาฬิกา"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"ตั้งค่า <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ให้จัดการ<xliff:g id="PROFILE_NAME">%2$s</xliff:g>ของคุณ - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"ต้องใช้ <xliff:g id="APP_NAME">%1$s</xliff:g> ในการจัดการ<xliff:g id="PROFILE_NAME">%2$s</xliff:g> <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"ใช่"</string> + <string name="consent_no" msgid="1335543792857823917">"ไม่เป็นไร"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml index 6cbf2e875881..a93282a8fae0 100644 --- a/packages/CompanionDeviceManager/res/values-tl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="profile_name_watch" msgid="576290739483672360">"relo"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Itakda ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> para pamahalaan ang iyong <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Kailangan ang <xliff:g id="APP_NAME">%1$s</xliff:g> para pamahalaan ang iyong <xliff:g id="PROFILE_NAME">%2$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Oo"</string> + <string name="consent_no" msgid="1335543792857823917">"Huwag na lang"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml index bc1ab31d9b90..3abe064d60bc 100644 --- a/packages/CompanionDeviceManager/res/values-tr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string> <string name="profile_name_watch" msgid="576290739483672360">"saat"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasını, <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> cihazınızı yönetecek şekilde ayarlayın"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="PROFILE_NAME">%2$s</xliff:g> yönetimi için gereklidir. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Evet"</string> + <string name="consent_no" msgid="1335543792857823917">"Hayır, teşekkürler"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml index 33477c8f1429..161d95e127e8 100644 --- a/packages/CompanionDeviceManager/res/values-uk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"пристрій"</string> <string name="profile_name_watch" msgid="576290739483672360">"годинник"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Налаштуйте додаток <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>, щоб керувати своїм пристроєм <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>)"</string> + <string name="profile_summary" msgid="2009764182871566255">"Щоб керувати своїм пристроєм (<xliff:g id="PROFILE_NAME">%2$s</xliff:g>), вам потрібен додаток <xliff:g id="APP_NAME">%1$s</xliff:g>. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Так"</string> + <string name="consent_no" msgid="1335543792857823917">"Ні, дякую"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml index 83e20d8940cd..dce18152dff4 100644 --- a/packages/CompanionDeviceManager/res/values-ur/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"آلہ"</string> <string name="profile_name_watch" msgid="576290739483672360">"دیکھیں"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"اپنے <xliff:g id="PROFILE_NAME">%2$s</xliff:g> کا نظم کرنے کے لیے <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو سیٹ کریں - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"آپ کے <xliff:g id="PROFILE_NAME">%2$s</xliff:g> کا نظم کرنے کے لیے <xliff:g id="APP_NAME">%1$s</xliff:g> کی ضرورت ہے۔ <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"ہاں"</string> + <string name="consent_no" msgid="1335543792857823917">"نہیں شکریہ"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml index b16db730def4..2ca27b530651 100644 --- a/packages/CompanionDeviceManager/res/values-uz/strings.xml +++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string> <string name="profile_name_watch" msgid="576290739483672360">"soat"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong> qurilmalarini boshqarish uchun <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasini sozlang"</string> + <string name="profile_summary" msgid="2009764182871566255">"<xliff:g id="PROFILE_NAME">%2$s</xliff:g> qurilmasini boshqarish uchun <xliff:g id="APP_NAME">%1$s</xliff:g> zarur. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Ha"</string> + <string name="consent_no" msgid="1335543792857823917">"Kerak emas"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml index 75d2de37cb14..06a1ab6846ae 100644 --- a/packages/CompanionDeviceManager/res/values-vi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"thiết bị"</string> <string name="profile_name_watch" msgid="576290739483672360">"đồng hồ"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Đặt <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> để quản lý <xliff:g id="PROFILE_NAME">%2$s</xliff:g> của bạn – <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"Cần có <xliff:g id="APP_NAME">%1$s</xliff:g> để quản lý <xliff:g id="PROFILE_NAME">%2$s</xliff:g> của bạn. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Có"</string> + <string name="consent_no" msgid="1335543792857823917">"Không, cảm ơn"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml index 788f8f9edce1..12bfcf3629cd 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"设备"</string> <string name="profile_name_watch" msgid="576290739483672360">"手表"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"设为由<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>管理您的<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"若要管理<xliff:g id="PROFILE_NAME">%2$s</xliff:g>,您需要使用<xliff:g id="APP_NAME">%1$s</xliff:g>。<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"好"</string> + <string name="consent_no" msgid="1335543792857823917">"不用了"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml index 576f3f46e8ba..0c583b211035 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string> <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"設定 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 來管理您的 <xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"必須使用 <xliff:g id="APP_NAME">%1$s</xliff:g> 來管理您的<xliff:g id="PROFILE_NAME">%2$s</xliff:g>。<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"是"</string> + <string name="consent_no" msgid="1335543792857823917">"不用了,謝謝"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml index 8a50658ad25c..519f0e8a7082 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string> <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"授權讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>管理你的<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"如要管理你的<xliff:g id="PROFILE_NAME">%2$s</xliff:g>,必須使用「<xliff:g id="APP_NAME">%1$s</xliff:g>」。<xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"是"</string> + <string name="consent_no" msgid="1335543792857823917">"不用了,謝謝"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml index fc3f19d72ee2..7721b54166f5 100644 --- a/packages/CompanionDeviceManager/res/values-zu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml @@ -20,12 +20,8 @@ <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> <string name="profile_name_generic" msgid="6851028682723034988">"idivayisi"</string> <string name="profile_name_watch" msgid="576290739483672360">"buka"</string> - <!-- no translation found for confirmation_title (814973816731238955) --> - <skip /> - <!-- no translation found for profile_summary (2059360676631420073) --> - <skip /> - <!-- no translation found for consent_yes (8344487259618762872) --> - <skip /> - <!-- no translation found for consent_no (2640796915611404382) --> - <skip /> + <string name="confirmation_title" msgid="4751119145078041732">"Setha i-<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukuba iphathe i-<xliff:g id="PROFILE_NAME">%2$s</xliff:g> - <strong><xliff:g id="DEVICE_NAME">%3$s</xliff:g></strong>"</string> + <string name="profile_summary" msgid="2009764182871566255">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> iyadingeka ukuphatha i-<xliff:g id="PROFILE_NAME">%2$s</xliff:g> yakho. <xliff:g id="PRIVILEGES_DISCPLAIMER">%3$s</xliff:g>"</string> + <string name="consent_yes" msgid="4055438216605487056">"Yebo"</string> + <string name="consent_no" msgid="1335543792857823917">"Cha ngiyabonga"</string> </resources> diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index 1a67b5e7dea7..eafc6147fae8 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rooi-groen)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (blou-geel)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Kleurregstelling"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Kleurregstelling stel jou in staat om te verstel hoe kleure op jou toestel vertoon word"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Geneutraliseer deur <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> oor"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Totdat jy dit afskakel"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Sopas"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Foonluidspreker"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kan nie koppel nie. Skakel toestel af en weer aan"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedrade oudiotoestel"</string> <string name="help_label" msgid="3528360748637781274">"Hulp en terugvoer"</string> diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index 97abce186d96..547d0af6200d 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ፕሮታኖማሊ (ቀይ-አረንጓዴ)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ትራይታኖማሊ (ሰማያዊ-ቢጫ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"የቀለም ማስተካከያ"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ቀለም ማስተካከያ ቀለሞች በመሣሪያዎ ላይ እንዴት እንደሚታዩ እንዲያስተካክሉ ያስችሉዎታል"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"በ<xliff:g id="TITLE">%1$s</xliff:g> ተሽሯል"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ገደማ ቀርቷል"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"እስኪያጠፉት ድረስ"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ልክ አሁን"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"የስልክ ድምጽ ማጉያ"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"መገናኘት ላይ ችግር። መሳሪያውን ያጥፉት እና እንደገና ያብሩት"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ባለገመድ የኦዲዮ መሣሪያ"</string> <string name="help_label" msgid="3528360748637781274">"እገዛ እና ግብረመልስ"</string> diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index f9e12c7149c0..c6a1d18f9c1e 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"غطش الأحمر (الأحمر والأخضر)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"غمش الأزرق (الأزرق والأصفر)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"تصحيح الألوان"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"تسمح لك ميزة تصحيح الألوان بتعديل كيفية عرض الألوان على جهازك."</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"تم الاستبدال بـ <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"يتبقى <xliff:g id="TIME_REMAINING">%1$s</xliff:g> تقريبًا"</string> @@ -520,8 +519,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"إلى أن يتم إيقاف الوضع"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"للتو"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"مكبر صوت الهاتف"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"حدثت مشكلة أثناء الاتصال. يُرجى إيقاف الجهاز ثم إعادة تشغيله."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"جهاز سماعي سلكي"</string> <string name="help_label" msgid="3528360748637781274">"المساعدة والملاحظات والآراء"</string> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index efd813a010e0..e9deb4641e46 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"প্ৰ’টানোমালি (ৰঙা-সেউজীয়া)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ট্ৰাইটান\'মেলী (নীলা-হালধীয়া)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ৰং শুধৰণী"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ৰং শুধৰণি সুবিধাটোৰে আপোনাক আপোনাৰ ডিভাইচত ৰংবোৰ কেনেকৈ প্ৰদর্শন কৰা হয় সেয়া মিলাবলৈ দিয়ে"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g>ৰ দ্বাৰা অগ্ৰাহ্য কৰা হৈছে"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"প্রায় <xliff:g id="TIME_REMAINING">%1$s</xliff:g> বাকী আছে"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"আপুনি অফ নকৰা পর্যন্ত"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"এই মাত্ৰ"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ফ’নৰ স্পীকাৰ"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"সংযোগ হোৱাত সমস্যা হৈছে। ডিভাইচটো অফ কৰি পুনৰ অন কৰক"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"তাঁৰযুক্ত অডিঅ’ ডিভাইচ"</string> <string name="help_label" msgid="3528360748637781274">"সহায় আৰু মতামত"</string> diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml index 2b0fa86499bc..d04409cd5e56 100644 --- a/packages/SettingsLib/res/values-az/strings.xml +++ b/packages/SettingsLib/res/values-az/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaliya (qırmızı-yaşıl)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaliya (göy-sarı)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Rəng düzəlişi"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Cihazınızda rənglərin necə göstərilməsini tənzimləyin. Bu, aşağıdakıları etmək istədikdə faydalı ola bilər:<br/><br/> <ol> <li> Rəngləri daha dəqiq görmək</li> <li> Fokuslanmaq üçün rəngləri ləğv etmək</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Rəng korreksiyası sizə rənglərin cihazınızda necə göstərilməsini tənzimləmək imkanı verir"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> tərəfindən qəbul edilmir"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Təxminən <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qalıb"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Deaktiv edənə qədər"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"İndicə"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefon dinamiki"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"Bu telefon"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Qoşulmaqla bağlı problem. Cihazı deaktiv edin, sonra yenidən aktiv edin"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio cihaz"</string> <string name="help_label" msgid="3528360748637781274">"Yardım və rəy"</string> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index b3186376ad59..ecd70a285bd0 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (crveno-zeleno)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (plavo-žuto)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekcija boja"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Prilagodite način na koji se boje prikazuju na uređaju. To može da bude korisno kada želite:<br/><br/> <ol> <li> da vam se boje tačnije prikazuju</li> <li> da uklonite boje kako biste se fokusirali</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Korekcija boja vam omogućava da prilagodite način na koji se boje prikazuju na uređaju"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamenjuje ga <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>–<xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,7 +516,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Dok ne isključite"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Upravo"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Zvučnik telefona"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ovaj telefon"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem pri povezivanju. Isključite uređaj, pa ga ponovo uključite"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string> <string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string> diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml index 7a5aec4d3b9b..6a3b961d1c5c 100644 --- a/packages/SettingsLib/res/values-be/strings.xml +++ b/packages/SettingsLib/res/values-be/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Пратанамалія (чырвоны-зялёны)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Трытанамалія (сіні-жоўты)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Карэкцыя колеру"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Карэкцыя колеру дазволіць вам наладзіць адлюстраванне колераў на экране прылады"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Перавызначаны <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Зараду хопіць прыблізна на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -518,8 +517,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Пакуль не выключыце"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Толькі што"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Дынамік тэлефона"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Праблема з падключэннем. Выключыце і зноў уключыце прыладу"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Правадная аўдыяпрылада"</string> <string name="help_label" msgid="3528360748637781274">"Даведка і водгукі"</string> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index 9ff2531c0e7c..d2bf70565be9 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (червено – зелено)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (синьо – жълто)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекция на цветове"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Коригирайте как цветовете се показват на устройството ви. Това може да бъде полезно, когато искате да:<br/><br/> <ol> <li> видите цветовете по-ясно;</li> <li> премахнете цветовете, за да се фокусирате.</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Функцията „Корекция на цветове“ ви позволява да коригирате това, как цветовете се показват на устройството ви"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Заменено от „<xliff:g id="TITLE">%1$s</xliff:g>“"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Още около <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"До изключване"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Току-що"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Високоговорител"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"Този телефон"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"При свързването възникна проблем. Изключете устройството и го включете отново"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Аудиоустройство с кабел"</string> <string name="help_label" msgid="3528360748637781274">"Помощ и отзиви"</string> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index 675d1794ae1a..3ccf0e426b77 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"প্রোটানোম্যালি (লাল-সবুজ)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ট্রিট্যানোম্যালি (নীল-হলুদ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"রঙ সংশোধন"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ডিভাইসে রঙগুলি কেমনভাবে দেখানো হবে তা অ্যাডজাস্ট করতে \'রঙ সংশোধন করুন\' বিকল্প ব্যবহার করা যেতে পারে"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> এর দ্বারা ওভাররাইড করা হয়েছে"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"আর আনুমানিক <xliff:g id="TIME_REMAINING">%1$s</xliff:g> চলবে"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"যতক্ষণ না আপনি বন্ধ করছেন"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"এখনই"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ফোনের স্পিকার"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"কানেক্ট করতে সমস্যা হচ্ছে। ডিভাইস বন্ধ করে আবার চালু করুন"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ওয়্যার অডিও ডিভাইস"</string> <string name="help_label" msgid="3528360748637781274">"সহায়তা ও মতামত"</string> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index 97083ad15519..f01eef340abc 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (crveno-zeleno)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (plavo-žuto)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Ispravka boje"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Ispravka boje vam dozvoljava da prilagodite način prikazivanja boja na uređaju"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamjenjuje <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -517,8 +516,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Dok ne isključite"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Upravo"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Zvučnik telefona"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Došlo je do problema prilikom povezivanja. Isključite, pa ponovo uključite uređaj"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audio uređaj"</string> <string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string> diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml index 9202013641ea..3fd968ba4763 100644 --- a/packages/SettingsLib/res/values-ca/arrays.xml +++ b/packages/SettingsLib/res/values-ca/arrays.xml @@ -234,7 +234,7 @@ <item msgid="4433736508877934305">"Cap"</item> <item msgid="9140053004929079158">"Logcat"</item> <item msgid="3866871644917859262">"Systrace (gràfics)"</item> - <item msgid="7345673972166571060">"Pila de crides a glGetError"</item> + <item msgid="7345673972166571060">"Pila de trucades a glGetError"</item> </string-array> <string-array name="show_non_rect_clip_entries"> <item msgid="2482978351289846212">"Desactivat"</item> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 4889220a8894..7069999fc8e7 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermell-verd)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (blau-groc)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correcció de color"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La correcció de color permet ajustar com es mostren els colors al teu dispositiu"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"S\'ha substituït per <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>: <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Temps restant aproximat: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Fins que no el desactivis"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Ara mateix"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Altaveu del telèfon"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Hi ha hagut un problema amb la connexió. Desactiva el dispositiu i torna\'l a activar."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositiu d\'àudio amb cable"</string> <string name="help_label" msgid="3528360748637781274">"Ajuda i suggeriments"</string> diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml index e857e60ed224..c677feffc384 100644 --- a/packages/SettingsLib/res/values-cs/strings.xml +++ b/packages/SettingsLib/res/values-cs/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomálie (červená a zelená)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomálie (modrá a žlutá)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekce barev"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Korekce barev umožňuje upravit zobrazování barev na zařízení"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Přepsáno nastavením <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zbývá asi <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -518,8 +517,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Dokud tuto funkci nevypnete"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Právě teď"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Reproduktor telefonu"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problém s připojením. Vypněte zařízení a znovu jej zapněte"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kabelové audiozařízení"</string> <string name="help_label" msgid="3528360748637781274">"Nápověda a zpětná vazba"</string> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index 53e21ba3abc2..84247a622740 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanopi (rød-grøn)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanopi (blå-gul)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korriger farver"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Ved hjælp af farvekorrigering kan du justere, hvordan farver ser ud på din enhed"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Tilsidesat af <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ca. <xliff:g id="TIME_REMAINING">%1$s</xliff:g> tilbage"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Indtil du deaktiverer"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Lige nu"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefonens højttaler"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Der kunne ikke oprettes forbindelse. Sluk og tænd enheden"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhed med ledning"</string> <string name="help_label" msgid="3528360748637781274">"Hjælp og feedback"</string> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index a4a976fcf34d..4cc79d32b797 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (Rot-Grün-Sehschwäche)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (Blau-Gelb-Sehschwäche)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Farbkorrektur"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Mit der Farbkorrektur kannst du anpassen, wie Farben auf deinem Display angezeigt werden"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Außer Kraft gesetzt von \"<xliff:g id="TITLE">%1$s</xliff:g>\""</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Noch etwa <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Bis zur Deaktivierung"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Gerade eben"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Smartphone-Lautsprecher"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Verbindung kann nicht hergestellt werden. Schalte das Gerät aus & und wieder ein."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Netzbetriebenes Audiogerät"</string> <string name="help_label" msgid="3528360748637781274">"Hilfe und Feedback"</string> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index 76faa4c13617..30705a1f6f62 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Πρωτανοπία (κόκκινο-πράσινο)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Τριτανοπία (μπλε-κίτρινο)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Διόρθωση χρωμάτων"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Προσαρμόστε πώς θα εμφανίζονται τα χρώματα στη συσκευή σας. Αυτό μπορεί να είναι χρήσιμο όταν θέλετε:<br/><br/> <ol> <li> Να βλέπετε τα χρώματα με μεγαλύτερη ακρίβεια</li> <li> Να καταργήσετε τα χρώματα για να συγκεντρωθείτε</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Η διόρθωση χρωμάτων σάς επιτρέπει να ρυθμίσετε τον τρόπο εμφάνισης των χρωμάτων στη συσκευή σας"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Αντικαταστάθηκε από <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Απομένει/ουν περίπου <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Μέχρι την απενεργοποίηση"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Μόλις τώρα"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Ηχείο τηλεφώνου"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"Αυτό το τηλέφωνο"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Πρόβλημα κατά τη σύνδεση. Απενεργοποιήστε τη συσκευή και ενεργοποιήστε την ξανά"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ενσύρματη συσκευή ήχου"</string> <string name="help_label" msgid="3528360748637781274">"Βοήθεια και σχόλια"</string> diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml index 9a63404229a5..b3d80abfc0a2 100644 --- a/packages/SettingsLib/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/res/values-en-rAU/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colours display on your device. This can be helpful when you want to:<br/><br/> <ol> <li> See colours more accurately</li> <li> Remove colours to help you focus</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Colour correction allows you to adjust how colours are displayed on your device"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Phone speaker"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string> <string name="help_label" msgid="3528360748637781274">"Help and feedback"</string> diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml index 49271dbed6f5..ecf97ad07c85 100644 --- a/packages/SettingsLib/res/values-en-rCA/strings.xml +++ b/packages/SettingsLib/res/values-en-rCA/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colours display on your device. This can be helpful when you want to:<br/><br/> <ol> <li> See colours more accurately</li> <li> Remove colours to help you focus</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Colour correction allows you to adjust how colours are displayed on your device"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Phone speaker"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string> <string name="help_label" msgid="3528360748637781274">"Help and feedback"</string> diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml index 9a63404229a5..b3d80abfc0a2 100644 --- a/packages/SettingsLib/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/res/values-en-rGB/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colours display on your device. This can be helpful when you want to:<br/><br/> <ol> <li> See colours more accurately</li> <li> Remove colours to help you focus</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Colour correction allows you to adjust how colours are displayed on your device"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Phone speaker"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string> <string name="help_label" msgid="3528360748637781274">"Help and feedback"</string> diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml index 9a63404229a5..b3d80abfc0a2 100644 --- a/packages/SettingsLib/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/res/values-en-rIN/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Colour correction"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colours display on your device. This can be helpful when you want to:<br/><br/> <ol> <li> See colours more accurately</li> <li> Remove colours to help you focus</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Colour correction allows you to adjust how colours are displayed on your device"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Phone speaker"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off and back on"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string> <string name="help_label" msgid="3528360748637781274">"Help and feedback"</string> diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml index 3476b975253f..c3a3f3f484fb 100644 --- a/packages/SettingsLib/res/values-en-rXC/strings.xml +++ b/packages/SettingsLib/res/values-en-rXC/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (red-green)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (blue-yellow)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Color correction"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Adjust how colors display on your device. This can be helpful when you want to:<br/><br/> <ol> <li> See colors more accurately</li> <li> Remove colors to help you focus</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Color correction allows you to adjust how colors are displayed on your device"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Until you turn off"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Just now"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Phone speaker"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"This phone"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem connecting. Turn device off & back on"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired audio device"</string> <string name="help_label" msgid="3528360748637781274">"Help & feedback"</string> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index 71cf5cbea0f2..eb2a23b45e70 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -220,7 +220,7 @@ <string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Conectado actualmente"</string> <string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Detalles del dispositivo"</string> <string name="adb_device_forget" msgid="193072400783068417">"Olvidar"</string> - <string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Huellas dactilares del dispositivo: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string> + <string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Huellas digitales del dispositivo: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string> <string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Error de conexión"</string> <string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Asegúrate de que <xliff:g id="DEVICE_NAME">%1$s</xliff:g> esté conectado a la red correcta."</string> <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Vincular con dispositivo"</string> @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (rojo-verde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarillo)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección de color"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La corrección de color te permite ajustar la manera en que se muestran los colores en el dispositivo"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Reemplazado por <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tiempo restante: aproximadamente <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Hasta que lo desactives"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Recién"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Altavoz del teléfono"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Error al establecer la conexión. Apaga el dispositivo y vuelve a encenderlo."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string> <string name="help_label" msgid="3528360748637781274">"Ayuda y comentarios"</string> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index a7d7b215e3a8..fe9984b701db 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (rojo-verde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarillo)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección de color"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La corrección de color te permite ajustar cómo se muestran los colores en tu dispositivo"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>: <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tiempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Hasta que lo desactives"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"justo ahora"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Altavoz del teléfono"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"No se ha podido conectar; reinicia el dispositivo"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string> <string name="help_label" msgid="3528360748637781274">"Ayuda y comentarios"</string> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index add25f839d21..c70700ddc24c 100644 --- a/packages/SettingsLib/res/values-et/strings.xml +++ b/packages/SettingsLib/res/values-et/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaalia (punane-roheline)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaalia (sinine-kollane)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Värvide korrigeerimine"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Värvide korrigeerimine võimaldab kohandada seadmes kuvatavaid värve"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Alistas <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ligikaudu <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäänud"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Kuni välja lülitate"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Äsja"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefoni kõlar"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem ühendamisel. Lülitage seade välja ja uuesti sisse"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Juhtmega heliseade"</string> <string name="help_label" msgid="3528360748637781274">"Abi ja tagasiside"</string> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index c95d15761561..09c964aa9dd1 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanopia (gorri-berdeak)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanopia (urdin-horia)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Koloreen zuzenketa"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Koloreen zuzenketaren bidez, gailuan koloreak bistaratzen diren modua doi dezakezu"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> hobespena gainjarri zaio"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> inguru gelditzen dira"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Zuk desaktibatu arte"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Oraintxe"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefonoaren bozgorailua"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Arazoren bat izan da konektatzean. Itzali gailua eta pitz ezazu berriro."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio-gailu kableduna"</string> <string name="help_label" msgid="3528360748637781274">"Laguntza eta iritziak"</string> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index 631ff5e3cbc4..22cd6ae68de2 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"قرمزدشواربینی (قرمز-سبز)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"آبیدشواربینی (آبی-زرد)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"تصحیح رنگ"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"تصحیح رنگ به شما امکان میدهد نحوه نمایش رنگها را در دستگاهتان تنظیم کنید"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"توسط <xliff:g id="TITLE">%1$s</xliff:g> لغو شد"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"تقریباً <xliff:g id="TIME_REMAINING">%1$s</xliff:g> شارژ باقی مانده است"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"تا زمانیکه آن را خاموش کنید"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"هماکنون"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"بلندگوی تلفن"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"مشکل در اتصال. دستگاه را خاموش و دوباره روشن کنید"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"دستگاه صوتی سیمی"</string> <string name="help_label" msgid="3528360748637781274">"راهنما و بازخورد"</string> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index 7591c911b96e..22dde690c3cf 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (puna-vihersokeus)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (sini-keltasokeus)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Värinkorjaus"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Värinkorjauksella voit muuttaa värien näkymistä laitteellasi"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Tämän ohittaa <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Noin <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäljellä"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Kunnes laitat pois päältä"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Äsken"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Puhelimen kaiutin"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Yhteysvirhe. Sammuta laite ja käynnistä se uudelleen."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Langallinen äänilaite"</string> <string name="help_label" msgid="3528360748637781274">"Ohje ja palaute"</string> diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml index a390257c8ce4..d189f72aad65 100644 --- a/packages/SettingsLib/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rouge/vert)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (bleu/jaune)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correction des couleurs"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La correction des couleurs vous permet d\'ajuster la manière dont les couleurs s\'affichent sur votre appareil"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> : <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Il reste environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Jusqu\'à la désactivation"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"À l\'instant"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Haut-parleur du téléphone"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteingez et rallumez l\'appareil"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio à câble"</string> <string name="help_label" msgid="3528360748637781274">"Aide et commentaires"</string> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index 8cf8c6ee5ee6..49d7faa63a3b 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rouge/vert)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (bleu-jaune)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correction des couleurs"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La correction des couleurs vous permet d\'ajuster l\'affichage des couleurs sur votre appareil"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Temps restant : environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Jusqu\'à la désactivation"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"À l\'instant"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Haut-parleur du téléphone"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problème de connexion. Éteignez l\'appareil, puis rallumez-le"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Appareil audio filaire"</string> <string name="help_label" msgid="3528360748637781274">"Aide et commentaires"</string> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index c1ba51d798f1..0922c3dca3af 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (vermello-verde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarelo)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección da cor"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"A corrección da cor permíteche axustar como se mostran as cores no dispositivo"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Ata a desactivación"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Agora mesmo"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Altofalante do teléfono"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Produciuse un problema coa conexión. Apaga e acende o dispositivo."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string> <string name="help_label" msgid="3528360748637781274">"Axuda e comentarios"</string> diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml index 94d83e0577bf..10c5cc87c6da 100644 --- a/packages/SettingsLib/res/values-gu/strings.xml +++ b/packages/SettingsLib/res/values-gu/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"પ્રોટેનોમલી (લાલ-લીલો)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ટ્રાઇટેનોમલી(વાદળી-પીળો)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"રંગ સુધારણા"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"રંગ સુધારણા તમને તમારા ડિવાઇસ પર રંગો કેવી રીતે બતાવવામાં આવે તેની ગોઠવણી કરવાની મંજૂરી આપે છે"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> દ્વારા ઓવરરાઇડ થયું"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"લગભગ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> બાકી છે"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"તમે બંધ ન કરો ત્યાં સુધી"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"હમણાં જ"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ફોન સ્પીકર"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"કનેક્ટ કરવામાં સમસ્યા આવી રહી છે. ડિવાઇસને બંધ કરીને ફરી ચાલુ કરો"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"વાયરવાળો ઑડિયો ડિવાઇસ"</string> <string name="help_label" msgid="3528360748637781274">"સહાય અને પ્રતિસાદ"</string> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index 835e760df1b3..ea25406b1541 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"लाल रंग पहचान न पाना (लाल-हरा)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"नीला रंग पहचान न पाना (नीला-पीला)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"रंग में सुधार करने की सुविधा"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"आपके डिवाइस पर रंगों के दिखने के तरीके में बदलाव करें. इससे, आपको इनमें मदद मिलेगी:<br/><br/> <ol> <li> रंगों को बेहतर तरीके से देखने में</li> <li> आसानी से फ़ोकस करने के लिए, रंग हटाने में</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"रंग में सुधार करने की सुविधा, आपके डिवाइस पर दिखने वाले रंगों में बदलाव करने में मदद करती है"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> के द्वारा ओवरराइड किया गया"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"जब तक आप इसे बंद नहीं करते"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"अभी-अभी"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"फ़ोन का स्पीकर"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"यह फ़ोन"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करने में समस्या हो रही है. डिवाइस को बंद करके चालू करें"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर वाला ऑडियो डिवाइस"</string> <string name="help_label" msgid="3528360748637781274">"सहायता और सुझाव"</string> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index e99d4cb94e8b..27a7a6e7891a 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (crveno – zeleno)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (plavo – žuto)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekcija boje"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Korekcija boje omogućuje vam prilagodbu načina prikazivanja boja na vašem uređaju"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Premošćeno postavkom <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Još otprilike <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -517,8 +516,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Dok ne isključite"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Upravo sad"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Zvučnik telefona"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem s povezivanjem. Isključite i ponovo uključite uređaj"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žičani audiouređaj"</string> <string name="help_label" msgid="3528360748637781274">"Pomoć i povratne informacije"</string> diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml index 503ee6020361..70a48b638506 100644 --- a/packages/SettingsLib/res/values-hu/strings.xml +++ b/packages/SettingsLib/res/values-hu/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomália (piros– zöld)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomália (kék–sárga)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Színkorrekció"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"A színkorrekcióval módosíthatja a színek megjelenítésének módját az eszközön"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Felülírva erre: <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Körülbelül <xliff:g id="TIME_REMAINING">%1$s</xliff:g> maradt hátra"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Kikapcsolásig"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Az imént"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefon hangszórója"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sikertelen csatlakozás. Kapcsolja ki az eszközt, majd kapcsolja be újra."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vezetékes audioeszköz"</string> <string name="help_label" msgid="3528360748637781274">"Súgó és visszajelzés"</string> diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index 3686dd171964..c39e966d880a 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -404,7 +404,7 @@ <string name="transcode_user_control" msgid="6176368544817731314">"Չեղարկել վերակոդավորման կանխադրված կարգավորումները"</string> <string name="transcode_enable_all" msgid="2411165920039166710">"Միացնել վերակոդավորումը"</string> <string name="transcode_default" msgid="3784803084573509491">"Ենթադրել, որ հավելվածներն աջակցում են ժամանակակից ձևաչափեր"</string> - <string name="transcode_notification" msgid="5560515979793436168">"Ցույց տալ տրանսկոդավորման մասին ծանուցումները"</string> + <string name="transcode_notification" msgid="5560515979793436168">"Ցուցադրել անդրկոդավորման ծանուցումներ"</string> <string name="runningservices_settings_title" msgid="6460099290493086515">"Աշխատող ծառայություններ"</string> <string name="runningservices_settings_summary" msgid="1046080643262665743">"Դիտել և վերահսկել ընթացիկ աշխատող ծառայությունները"</string> <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ծառայություն"</string> @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Պրոտանոմալիա (կարմիր-կանաչ)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Տրիտանոմալիա (կապույտ-դեղին)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Գունաշտկում"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Գունաշտկումը թույլ է տալիս կարգավորել գույների ցուցադրումն այս սարքում"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Գերազանցված է <xliff:g id="TITLE">%1$s</xliff:g>-ից"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Լիցքը կբավարարի մոտ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Մինչև չանջատեք"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Հենց նոր"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Հեռախոսի բարձրախոս"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Կապի խնդիր կա: Սարքն անջատեք և նորից միացրեք:"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Լարով աուդիո սարք"</string> <string name="help_label" msgid="3528360748637781274">"Օգնություն և հետադարձ կապ"</string> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index 035be7d90e05..037c1b3b3e76 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (merah-hijau)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (biru-kuning)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Koreksi warna"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Koreksi warna memungkinkan Anda untuk menyesuaikan cara warna ditampilkan pada perangkat Anda"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Digantikan oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Sekitar <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Sampai Anda menonaktifkannya"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Baru saja"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Speaker ponsel"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ada masalah saat menghubungkan. Nonaktifkan perangkat & aktifkan kembali"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Perangkat audio berkabel"</string> <string name="help_label" msgid="3528360748637781274">"Bantuan & masukan"</string> diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml index 718b5be270a7..3f8783053ba3 100644 --- a/packages/SettingsLib/res/values-is/strings.xml +++ b/packages/SettingsLib/res/values-is/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Litblinda (rauðgræn)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Litblinda (blágul)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Litaleiðrétting"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Litaleiðrétting gerir þér kleift að stilla hvernig litir birtast í tækinu þínu"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Hnekkt af <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Um það bil <xliff:g id="TIME_REMAINING">%1$s</xliff:g> eftir"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Þar til þú slekkur"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Rétt í þessu"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Símahátalari"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Vandamál í tengingu. Slökktu og kveiktu á tækinu"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Snúrutengt hljómtæki"</string> <string name="help_label" msgid="3528360748637781274">"Hjálp og ábendingar"</string> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index d2176d905b34..80ab57b66548 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalìa (rosso-verde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalìa (blu-giallo)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correzione del colore"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"La correzione del colore ti consente di regolare la visualizzazione dei colori sul tuo dispositivo"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Valore sostituito da <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo rimanente: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> circa"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Fino alla disattivazione"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Adesso"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Altoparlante telefono"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema di connessione. Spegni e riaccendi il dispositivo"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo audio cablato"</string> <string name="help_label" msgid="3528360748637781274">"Guida e feedback"</string> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index 1357cae170f7..4355f31e3ed1 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"פרוטנומליה (אדום-ירוק)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"טריטנומליה (כחול-צהוב)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"תיקון צבע"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"תיקון צבע מאפשר לשנות את האופן שבו צבעים מוצגים במכשיר שלך"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"נעקף על ידי <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"הזמן הנותר: בערך <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -518,8 +517,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"עד הכיבוי"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"הרגע"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"רמקול של טלפון"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"יש בעיה בחיבור. עליך לכבות את המכשיר ולהפעיל אותו מחדש"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"התקן אודיו חוטי"</string> <string name="help_label" msgid="3528360748637781274">"עזרה ומשוב"</string> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index 4a9126f066af..ea4a683dd283 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"第一色弱(赤緑)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"第三色弱(青黄)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色補正"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"デバイスで色をどのように表示するかを調整できます。この設定は以下の場合に役立ちます。<br/><br/> <ol> <li> 色をより正確に表示したい場合</li> <li> はっきり読み取れるよう色を取り除きたい場合</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"色補正機能では、デバイスで色をどのように表示するかを調整できます"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g>によって上書き済み"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"残り時間: 約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"OFF にするまで"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"たった今"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"スマートフォンのスピーカー"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"このスマートフォン"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"接続エラーです。デバイスを OFF にしてから ON に戻してください"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線オーディオ デバイス"</string> <string name="help_label" msgid="3528360748637781274">"ヘルプとフィードバック"</string> diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml index 8bb6ba892e6d..5798a46e7c99 100644 --- a/packages/SettingsLib/res/values-ka/strings.xml +++ b/packages/SettingsLib/res/values-ka/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"პროტოანომალია (წითელი-მწვანე)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ტრიტანომალია (ლურჯი-ყვითელი)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ფერის კორექცია"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ფერთა კორექცია საშუალებას გაძლევთ დაარეგულიროთ, თუ როგორ გამოჩნდება ფერები თქვენს მოწყობილობაზე"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"უკუგებულია <xliff:g id="TITLE">%1$s</xliff:g>-ის მიერ"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"დარჩა დაახლოებით <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"გამორთვამდე"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ახლახან"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ტელეფონის დინამიკი"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"დაკავშირებისას წარმოიქმნა პრობლემა. გამორთეთ და კვლავ ჩართეთ მოწყობილობა"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"სადენიანი აუდიო მოწყობილობა"</string> <string name="help_label" msgid="3528360748637781274">"დახმარება და გამოხმაურება"</string> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index 6a2c21eee17f..5ce4e3a8f1c8 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (қызыл-жасыл)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (көк-сары)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Түсті түзету"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Түсті түзету функциясының көмегімен құрылғыңызда көрсетілетін түстерді реттеуге болады."</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> үстінен басқан"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Шамамен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> қалды"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Өшірілгенге дейін"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Дәл қазір"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Телефон динамигі"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Байланыс орнату қатесі шығуып жатыр. Құрылғыны өшіріп, қайта қосыңыз."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Сымды аудио құрылғысы"</string> <string name="help_label" msgid="3528360748637781274">"Анықтама және пікір"</string> diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml index f4cece4aa038..e6f2cb03439e 100644 --- a/packages/SettingsLib/res/values-km/strings.xml +++ b/packages/SettingsLib/res/values-km/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (ក្រហមពណ៌បៃតង)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ពណ៌ខៀវ-លឿង)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ការកែពណ៌"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"កែតម្រូវរបៀបដែលពណ៌បង្ហាញនៅលើឧបករណ៍របស់អ្នក។ ចំណុចនេះអាចមានប្រយោជន៍ នៅពេលដែលអ្នកចង់៖<br/><br/> <ol> <li> មើលឃើញពណ៌កាន់តែត្រឹមត្រូវ</li> <li> លុបពណ៌ ដើម្បីជួយអ្នកក្នុងការផ្ដោត</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ការកែតម្រូវពណ៌អនុញ្ញាតឱ្យអ្នកកែតម្រូវរបៀបបង្ហាញពណ៌នៅលើឧបករណ៍របស់អ្នក"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"បដិសេធដោយ <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"នៅសល់ប្រហែល <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ទៀត"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"រហូតទាល់តែអ្នកបិទ"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"អម្បាញ់មិញ"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ឧបករណ៍បំពងសំឡេងទូរសព្ទ"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"ទូរសព្ទនេះ"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"មានបញ្ហាក្នុងការភ្ជាប់។ បិទ រួចបើកឧបករណ៍វិញ"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ឧបករណ៍សំឡេងប្រើខ្សែ"</string> <string name="help_label" msgid="3528360748637781274">"ជំនួយ និងមតិកែលម្អ"</string> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index a844ee6d0ad5..561e6bed887d 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -404,7 +404,8 @@ <string name="transcode_user_control" msgid="6176368544817731314">"ಟ್ರಾನ್ಸ್ಕೋಡಿಂಗ್ ಡೀಫಾಲ್ಟ್ಗಳನ್ನು ಅತಿಕ್ರಮಿಸಿ"</string> <string name="transcode_enable_all" msgid="2411165920039166710">"ಟ್ರಾನ್ಸ್ಕೋಡಿಂಗ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string> <string name="transcode_default" msgid="3784803084573509491">"ಆ್ಯಪ್ಗಳು ಆಧುನಿಕ ಫಾರ್ಮ್ಯಾಟ್ಗಳನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ ಎಂದು ಊಹಿಸಿ"</string> - <string name="transcode_notification" msgid="5560515979793436168">"ಟ್ರಾನ್ಸ್ಕೋಡಿಂಗ್ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸಿ"</string> + <!-- no translation found for transcode_notification (5560515979793436168) --> + <skip /> <string name="runningservices_settings_title" msgid="6460099290493086515">"ರನ್ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳು"</string> <string name="runningservices_settings_summary" msgid="1046080643262665743">"ಈಗ ರನ್ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ನಿಯಂತ್ರಿಸಿ"</string> <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ಹೊಂದಿಸಿ"</string> @@ -424,8 +425,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ಪ್ರೊಟನೋಮಲಿ (ಕೆಂಪು-ಹಸಿರು)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ಟ್ರಿಟನೋಮಲಿ (ನೀಲಿ-ಹಳದಿ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ಬಣ್ಣದ ತಿದ್ದುಪಡಿ"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಬಣ್ಣಗಳನ್ನು ಹೇಗೆ ಪ್ರದರ್ಶಿಸಲಾಗುತ್ತದೆ ಎಂಬುದನ್ನು ಹೊಂದಾಣಿಕೆ ಮಾಡಲು ಬಣ್ಣ ತಿದ್ದುಪಡಿಯು ಅವಕಾಶ ನೀಡುತ್ತದೆ"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ಮೂಲಕ ಅತಿಕ್ರಮಿಸುತ್ತದೆ"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಉಳಿದಿದೆ"</string> @@ -516,8 +516,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"ನೀವು ಆಫ್ ಮಾಡುವವರೆಗೆ"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ಇದೀಗ"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ಫೋನ್ ಸ್ಪೀಕರ್"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ಕನೆಕ್ಟ್ ಮಾಡುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ ಸಾಧನವನ್ನು ಆಫ್ ಮಾಡಿ ಹಾಗೂ ನಂತರ ಪುನಃ ಆನ್ ಮಾಡಿ"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ವೈರ್ ಹೊಂದಿರುವ ಆಡಿಯೋ ಸಾಧನ"</string> <string name="help_label" msgid="3528360748637781274">"ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"</string> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index c9960c4086be..cd3b8b842c66 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"적색약(적녹)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"청색약(청황)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"색상 보정"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"기기에 색상이 표시되는 방식을 조정합니다. 색상을 더 정확하게 보고 싶거나 집중을 위해 일부 색상을 제거할 때 유용합니다."</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"색상 보정을 사용하면 기기에 표시되는 색상을 조절할 수 있습니다."</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> 우선 적용됨"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>, <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"남은 시간 약 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"사용 중지할 때까지"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"조금 전"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"휴대전화 스피커"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"이 휴대전화"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"연결 중에 문제가 발생했습니다. 기기를 껐다가 다시 켜 보세요."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"유선 오디오 기기"</string> <string name="help_label" msgid="3528360748637781274">"고객센터"</string> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index 4ca656798df8..1990353f80b8 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (кызыл-жашыл)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (көк-сары)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Түсүн тууралоо"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Түстөрдү тууралоо менен, түзмөгүңүздүн экранынын түстөрүн өзгөртө аласыз"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> менен алмаштырылган"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Болжол менен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> калды"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Бул функция өчүрүлгөнгө чейин"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Жаңы эле"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Телефондун динамиги"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Туташууда маселе келип чыкты. Түзмөктү өчүрүп, кайра күйгүзүп көрүңүз"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Зымдуу аудио түзмөк"</string> <string name="help_label" msgid="3528360748637781274">"Жардам/Пикир билдирүү"</string> diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml index 176c80fbc1d6..4997ea1a82c6 100644 --- a/packages/SettingsLib/res/values-lo/strings.xml +++ b/packages/SettingsLib/res/values-lo/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (ສີແດງ-ສີຂຽວ)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ສີຟ້າ-ສີເຫຼືອງ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ການປັບແຕ່ງສີ"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ການແກ້ໄຂສີຈະເຮັດໃຫ້ທ່ານສາມາດປັບແຕ່ງການສະແດງຜົນຂອງສີຢູ່ອຸປະກອນຂອງທ່ານໄດ້"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"ຖືກແທນໂດຍ <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"ເຫຼືອອີກປະມານ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"ຈົນກວ່າທ່ານຈະປິດ"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ຕອນນີ້"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ລຳໂພງໂທລະສັບ"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ເກີດບັນຫາໃນການເຊື່ອມຕໍ່. ປິດອຸປະກອນແລ້ວເປີດກັບຄືນມາໃໝ່"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ອຸປະກອນສຽງແບບມີສາຍ"</string> <string name="help_label" msgid="3528360748637781274">"ຊ່ວຍເຫຼືອ ແລະ ຕິຊົມ"</string> diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml index b0ab8f449c67..ec3cb0d94a51 100644 --- a/packages/SettingsLib/res/values-lt/strings.xml +++ b/packages/SettingsLib/res/values-lt/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (raudona, žalia)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (mėlyna, geltona)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Spalvų taisymas"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Spalvų taisymo funkcija padės koreguoti, kaip spalvos rodomos jūsų įrenginyje"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Nepaisyta naudojant nuostatą „<xliff:g id="TITLE">%1$s</xliff:g>“"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Liko maždaug <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -518,8 +517,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Kol išjungsite"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Ką tik"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefono garsiakalbis"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Prisijungiant kilo problema. Išjunkite įrenginį ir vėl jį įjunkite"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Laidinis garso įrenginys"</string> <string name="help_label" msgid="3528360748637781274">"Pagalba ir atsiliepimai"</string> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index 2633f13e4e34..ff9f0a1649f9 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomālija (sarkans/zaļš)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomālija (zils/dzeltens)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Krāsu korekcija"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Izmantojot krāsu korekciju, varat koriģēt krāsu attēlojumu savā ierīcē"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Jaunā preference: <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> — <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Aptuvenais atlikušais laiks: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -517,8 +516,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Līdz brīdim, kad izslēgsiet"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Tikko"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Tālruņa skaļrunis"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Radās problēma ar savienojuma izveidi. Izslēdziet un atkal ieslēdziet ierīci."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Vadu audioierīce"</string> <string name="help_label" msgid="3528360748637781274">"Palīdzība un atsauksmes"</string> diff --git a/packages/SettingsLib/res/values-mk/arrays.xml b/packages/SettingsLib/res/values-mk/arrays.xml index 03128c17c784..d1c74e64827f 100644 --- a/packages/SettingsLib/res/values-mk/arrays.xml +++ b/packages/SettingsLib/res/values-mk/arrays.xml @@ -138,9 +138,9 @@ <item msgid="1333279807604675720">"Стерео"</item> </string-array> <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles"> - <item msgid="1241278021345116816">"Оптимизирано за квалитет на аудиото (990 kbps - 909 kbps)"</item> + <item msgid="1241278021345116816">"Оптимизирано за квалитет на аудиото (990 кб/с - 909 кб/с)"</item> <item msgid="3523665555859696539">"Балансиран квалитет на звукот и врската (660 kb/s/606 kb/s)"</item> - <item msgid="886408010459747589">"Оптимизирано за квалитет на врската (330 kbps - 303 kbps)"</item> + <item msgid="886408010459747589">"Оптимизирано за квалитет на врската (330 кб/с - 303 кб/с)"</item> <item msgid="3808414041654351577">"Најдобар напор (приспособлива стапка на битови)"</item> </string-array> <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries"> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index e4173d0dcac9..507f65c641b2 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалија (слепило за црвена и зелена)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалија (слепило за сина и жолта)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекција на бои"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Корекцијата на боите ви овозможува да го приспособите начинот на прикажување на боите на вашиот уред"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Прескокнато според <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Додека не го исклучите"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Неодамнешни"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Телефонски звучник"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем со поврзување. Исклучете го уредот и повторно вклучете го"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичен аудиоуред"</string> <string name="help_label" msgid="3528360748637781274">"Помош и повратни информации"</string> diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml index 3cfe47954a33..8a09801502e1 100644 --- a/packages/SettingsLib/res/values-ml/strings.xml +++ b/packages/SettingsLib/res/values-ml/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"പ്രോട്ടാനോമലി (ചുവപ്പ്-പച്ച)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ട്രിട്ടാനോമലി (നീല-മഞ്ഞ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"നിറം ക്രമീകരിക്കൽ"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"നിങ്ങളുടെ ഉപകരണത്തിൽ നിറങ്ങൾ എങ്ങനെ പ്രദർശിപ്പിക്കുന്നു എന്നത് ക്രമീകരിക്കാൻ \'നിറം ക്രമീകരിക്കൽ\' അനുവദിക്കുന്നു"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ഉപയോഗിച്ച് അസാധുവാക്കി"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"ഏതാണ്ട് <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ശേഷിക്കുന്നു"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"നിങ്ങൾ ഓഫാക്കുന്നത് വരെ"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ഇപ്പോൾ"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ഫോൺ സ്പീക്കർ"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"കണക്റ്റ് ചെയ്യുന്നതിൽ പ്രശ്നമുണ്ടായി. ഉപകരണം ഓഫാക്കി വീണ്ടും ഓണാക്കുക"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"വയർ മുഖേന ബന്ധിപ്പിച്ച ഓഡിയോ ഉപകരണം"</string> <string name="help_label" msgid="3528360748637781274">"സഹായവും ഫീഡ്ബാക്കും"</string> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index 7c833f7a3a52..27ca8f59739d 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномаль (улаан-ногоон)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомаль (цэнхэр-шар)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Өнгө тохируулах"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Таны төхөөрөмж дээр өнгийг хэрхэн үзүүлэхийг тохируулна уу. Энэ нь таныг дараахыг хийхийг хүссэн үед хэрэгтэй байж болно:<br/><br/> <ol> <li> Өнгийг илүү оновчтой харах</li> <li> Төвлөрөхийн тулд өнгийг хасах</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Өнгө тохируулга нь танд төхөөрөмж дээрээ өнгө хэрхэн харагдахыг тохируулах боломжийг олгодог"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Давхарласан <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Таныг унтраах хүртэл"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Дөнгөж сая"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Утасны чанга яригч"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"Энэ утас"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Холбогдоход асуудал гарлаа. Төхөөрөмжийг унтраагаад дахин асаана уу"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Утастай аудио төхөөрөмж"</string> <string name="help_label" msgid="3528360748637781274">"Тусламж, санал хүсэлт"</string> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index f8d9089d88e3..b6c546072473 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -404,7 +404,8 @@ <string name="transcode_user_control" msgid="6176368544817731314">"ट्रान्सकोडिंग डीफॉल्ट ओव्हरराइड करा"</string> <string name="transcode_enable_all" msgid="2411165920039166710">"ट्रान्सकोडिंग सुरू करा"</string> <string name="transcode_default" msgid="3784803084573509491">"असे गृहीत धरा की, ॲप्स आधुनिक फॉरमॅटना सपोर्ट करतात"</string> - <string name="transcode_notification" msgid="5560515979793436168">"ट्रान्सकोडिंग सूचना दाखवा"</string> + <!-- no translation found for transcode_notification (5560515979793436168) --> + <skip /> <string name="runningservices_settings_title" msgid="6460099290493086515">"सुरू सेवा"</string> <string name="runningservices_settings_summary" msgid="1046080643262665743">"सध्या सुरू असलेल्या सेवा पहा आणि नियंत्रित करा"</string> <string name="select_webview_provider_title" msgid="3917815648099445503">"वेबदृश्य अंमलबजावणी"</string> @@ -424,8 +425,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"क्षीण रक्तवर्णांधता (लाल-हिरवा)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"रंग दृष्टी कमतरता (निळा-पिवळा)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"रंग सुधारणा"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"कलर इन्व्हर्जन तुमच्या डिव्हाइसवर रंग कसे प्रदर्शित केले जातात ते अॅडजस्ट करू देते"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारे अधिलिखित"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"अंदाजे <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाकी आहे"</string> @@ -516,8 +516,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"तुम्ही बंद करेपर्यंत"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"आत्ताच"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"फोनचा स्पीकर"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करण्यात समस्या आली. डिव्हाइस बंद करा आणि नंतर सुरू करा"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर असलेले ऑडिओ डिव्हाइस"</string> <string name="help_label" msgid="3528360748637781274">"मदत आणि फीडबॅक"</string> diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml index 4df385597068..53a4398d1b90 100644 --- a/packages/SettingsLib/res/values-ms/strings.xml +++ b/packages/SettingsLib/res/values-ms/strings.xml @@ -68,7 +68,7 @@ <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Memutuskan sambungan..."</string> <string name="bluetooth_connecting" msgid="5871702668260192755">"Menyambung..."</string> <string name="bluetooth_connected" msgid="8065345572198502293">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> disambungkan"</string> - <string name="bluetooth_pairing" msgid="4269046942588193600">"Menggandingkan..."</string> + <string name="bluetooth_pairing" msgid="4269046942588193600">"Memasangkan..."</string> <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"Disambungkan (tiada telefon)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string> <string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"Disambungkan (tiada media)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string> <string name="bluetooth_connected_no_map" msgid="3381860077002724689">"Disambungkan (tiada akses mesej)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string> @@ -113,7 +113,7 @@ <string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Gunakan untuk pemindahan fail"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gunakan untuk input"</string> <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Gunakan untuk Alat Bantu Dengar"</string> - <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Gandingkan"</string> + <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Jadikan pasangan"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"JADIKAN PASANGAN"</string> <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Batal"</string> <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Berpasangan memberi anda akses kepada kenalan dan sejarah panggilan apabila disambungkan."</string> @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (merah-hijau)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (biru-kuning)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Pembetulan warna"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Laraskan cara warna dipaparkan pada peranti anda. Ini boleh membantu apabila anda ingin:<br/><br/> <ol> <li> Lihat warna dengan lebih tepat</li> <li> Alih keluar warna untuk membantu anda fokus</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Pembetulan warna membolehkan anda melaraskan cara warna dipaparkan pada peranti anda"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Diatasi oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Kira-kira <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Sehingga anda matikan"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Sebentar tadi"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Pembesar suara telefon"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"Telefon ini"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Masalah penyambungan. Matikan & hidupkan kembali peranti"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Peranti audio berwayar"</string> <string name="help_label" msgid="3528360748637781274">"Bantuan & maklum balas"</string> diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml index f10e5393877f..0fef5abf782b 100644 --- a/packages/SettingsLib/res/values-my/strings.xml +++ b/packages/SettingsLib/res/values-my/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (အနီ-အစိမ်း)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (အပြာ-အဝါ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"အရောင်ပြင်ဆင်မှု"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"အရောင်အမှန်ပြင်ခြင်းက သင့်စက်ပေါ်တွင် အရောင်များပြနေပုံကို ချိန်ညှိခွင့်ပြုသည်"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> မှ ကျော်၍ လုပ်ထားသည်။"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည်"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"သင်ပိတ်လိုက်သည် အထိ"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ယခုလေးတင်"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ဖုန်းစပီကာ"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ချိတ်ဆက်ရာတွင် ပြဿနာရှိပါသည်။ စက်ကိုပိတ်ပြီး ပြန်ဖွင့်ပါ"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ကြိုးတပ် အသံစက်ပစ္စည်း"</string> <string name="help_label" msgid="3528360748637781274">"အကူအညီနှင့် အကြံပြုချက်"</string> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index 9fb68d0a30ef..0ca8d51645e8 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (rød-grønn)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (blå-gul)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Fargekorrigering"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Med fargekorrigering kan du justere hvordan farger vises på enheten din"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overstyres av <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Omtrent <xliff:g id="TIME_REMAINING">%1$s</xliff:g> gjenstår"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Til du slår av"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Nå nettopp"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefonhøyttaler"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Tilkoblingsproblemer. Slå enheten av og på igjen"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Lydenhet med kabel"</string> <string name="help_label" msgid="3528360748637781274">"Hjelp og tilbakemelding"</string> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index 4c847cfaa2b4..75b4537f6a8f 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -404,7 +404,8 @@ <string name="transcode_user_control" msgid="6176368544817731314">"ट्रान्सकोडिङसम्बन्धी पूर्वनिर्धारित सेटिङ परिवर्तन गर्नुहोस्"</string> <string name="transcode_enable_all" msgid="2411165920039166710">"ट्रान्सकोडिङ अन गर्नुहोस्"</string> <string name="transcode_default" msgid="3784803084573509491">"एपहरूमा आधुनिक फर्म्याट प्रयोग गर्न मिल्छ भनी मान्नुहोस्"</string> - <string name="transcode_notification" msgid="5560515979793436168">"ट्रान्सकोडिङसम्बन्धी सूचना देखाइयोस्"</string> + <!-- no translation found for transcode_notification (5560515979793436168) --> + <skip /> <string name="runningservices_settings_title" msgid="6460099290493086515">"चलिरहेका सेवाहरू"</string> <string name="runningservices_settings_summary" msgid="1046080643262665743">"हाल चालु भइरहेका सेवाहरू हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string> <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView कार्यान्वयन"</string> @@ -424,8 +425,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"प्रोटानेमली (रातो, हरियो)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ट्रिटानोमेली (निलो-पंहेलो)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"रङ्ग सुधार"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"रंङ सच्याउने सुविधाले तपाईंलाई आफ्नो यन्त्रमा रंङहरू कसरी देखाउने भन्ने कुरा निर्धारण गर्न दिन्छ"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारा अधिरोहित"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाँकी छ"</string> @@ -516,8 +516,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"तपाईंले निष्क्रिय नपार्दासम्म"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"अहिले भर्खरै"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"फोनको स्पिकर"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"जोड्ने क्रममा समस्या भयो। यन्त्रलाई निष्क्रिय पारेर फेरि सक्रिय गर्नुहोस्"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"तारयुक्त अडियो यन्त्र"</string> <string name="help_label" msgid="3528360748637781274">"मद्दत र प्रतिक्रिया"</string> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index 4cb755ba468c..71d6acc6a22b 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rood-groen)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (blauw-geel)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Kleurcorrectie"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Aanpassen hoe kleuren worden getoond op je apparaat. In de volgende gevallen kan dit handig zijn:<br/><br/> <ol> <li> Je wilt kleuren duidelijker zien.</li> <li> Je wilt kleuren verwijderen zodat je je beter kunt focussen.</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Met kleurcorrectie kun je aanpassen hoe kleuren op je apparaat worden weergegeven"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overschreven door <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Nog ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Totdat je uitschakelt"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Zojuist"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefoonspeaker"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"Deze telefoon"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Probleem bij verbinding maken. Schakel het apparaat uit en weer in."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Bedraad audioapparaat"</string> <string name="help_label" msgid="3528360748637781274">"Hulp en feedback"</string> diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml index b7c93e55163c..1d6e34f7af23 100644 --- a/packages/SettingsLib/res/values-or/strings.xml +++ b/packages/SettingsLib/res/values-or/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ପ୍ରୋଟାନୋମାଲି (ଲାଲ୍-ସବୁଜ)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ନୀଳ-ହଳଦିଆ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ରଙ୍ଗ ସଂଶୋଧନ"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ଆପଣଙ୍କ ଡିଭାଇସରେ ରଙ୍ଗଗୁଡ଼ିକ କିପରି ଡିସପ୍ଲେ ହୁଏ, ତାହା ଆଡଜଷ୍ଟ କରିବାକୁ \'ରଙ୍ଗ ସଂଶୋଧନ’ ଆପଣଙ୍କୁ ଅନୁମତି ଦିଏ"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ଦ୍ୱାରା ଓଭର୍ରାଇଡ୍ କରାଯାଇଛି"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"ପାଖାପାଖି <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ବଳକା ଅଛି"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"ଆପଣ ବନ୍ଦ ନକରିବା ପର୍ଯ୍ୟନ୍ତ"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ଏହିକ୍ଷଣି"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ଫୋନ୍ ସ୍ପିକର୍"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ସଂଯୋଗ କରିବାରେ ସମସ୍ୟା ହେଉଛି। ଡିଭାଇସ୍ ବନ୍ଦ କରି ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ତାରଯୁକ୍ତ ଅଡିଓ ଡିଭାଇସ୍"</string> <string name="help_label" msgid="3528360748637781274">"ସାହାଯ୍ୟ ଓ ମତାମତ"</string> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index 896a10034383..9d91aae0a982 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -404,7 +404,8 @@ <string name="transcode_user_control" msgid="6176368544817731314">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਦੀਆਂ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਸੈਟਿੰਗਾਂ ਨੂੰ ਓਵਰਰਾਈਡ ਕਰੋ"</string> <string name="transcode_enable_all" msgid="2411165920039166710">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਚਾਲੂ ਕਰੋ"</string> <string name="transcode_default" msgid="3784803084573509491">"ਮੰਨ ਲਓ ਕਿ ਐਪਾਂ ਆਧੁਨਿਕ ਫਾਰਮੈਟਾਂ ਦਾ ਸਮਰਥਨ ਕਰਦੀਆਂ ਹਨ"</string> - <string name="transcode_notification" msgid="5560515979793436168">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਸੂਚਨਾਵਾਂ ਦਿਖਾਓ"</string> + <!-- no translation found for transcode_notification (5560515979793436168) --> + <skip /> <string name="runningservices_settings_title" msgid="6460099290493086515">"ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ"</string> <string name="runningservices_settings_summary" msgid="1046080643262665743">"ਇਸ ਵੇਲੇ ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ ਦੇਖੋ ਅਤੇ ਇਹਨਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string> <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ਅਮਲ"</string> @@ -424,8 +425,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (ਲਾਲ-ਹਰਾ)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (ਨੀਲਾ-ਪੀਲਾ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"ਰੰਗ ਸੁਧਾਈ"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"ਰੰਗ ਸੁਧਾਈ ਨਾਲ ਤੁਹਾਨੂੰ ਆਪਣੇ ਡੀਵਾਈਸ \'ਤੇ ਰੰਗਾਂ ਦੇ ਪ੍ਰਦਰਸ਼ਿਤ ਹੋਣ ਨੂੰ ਵਿਵਸਥਿਤ ਕਰਨ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ਦੁਆਰਾ ਓਵਰਰਾਈਡ ਕੀਤਾ"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"ਲਗਭਗ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਬਾਕੀ"</string> @@ -516,8 +516,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਬੰਦ ਨਹੀਂ ਕਰਦੇ"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ਹੁਣੇ ਹੀ"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ਫ਼ੋਨ ਦਾ ਸਪੀਕਰ"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ਕਨੈਕਟ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ ਆਈ। ਡੀਵਾਈਸ ਨੂੰ ਬੰਦ ਕਰਕੇ ਵਾਪਸ ਚਾਲੂ ਕਰੋ"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ਤਾਰ ਵਾਲਾ ਆਡੀਓ ਡੀਵਾਈਸ"</string> <string name="help_label" msgid="3528360748637781274">"ਮਦਦ ਅਤੇ ਵਿਚਾਰ"</string> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index 663f3fc592da..f48b05f01ddc 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (czerwony-zielony)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (niebieski-żółty)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korekcja kolorów"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Korekcja kolorów pozwala na dostosowanie sposobu wyświetlania kolorów na urządzeniu"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Nadpisana przez <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Jeszcze około <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -518,8 +517,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Dopóki nie wyłączysz"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Przed chwilą"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Głośnik telefonu"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem z połączeniem. Wyłącz i ponownie włącz urządzenie"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Przewodowe urządzenie audio"</string> <string name="help_label" msgid="3528360748637781274">"Pomoc i opinie"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index 8eab928c7fb5..b9c919129623 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermelho-verde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (azul-amarelo)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correção de cor"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"A correção de cor permite ajustar como as cores são exibidas no dispositivo"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Até você desativar"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Agora"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Alto-falante do smartphone"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string> <string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index f28d70a71ce7..57e38c078375 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermelho-verde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (azul-amarelo)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correção da cor"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"A correção da cor permite-lhe ajustar a forma como as cores são apresentadas no seu dispositivo."</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Resta(m) cerca de <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Até desativar"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Agora mesmo"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Altifalante do telemóvel"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema ao ligar. Desligue e volte a ligar o dispositivo."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fios"</string> <string name="help_label" msgid="3528360748637781274">"Ajuda e comentários"</string> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index 8eab928c7fb5..b9c919129623 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalia (vermelho-verde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalia (azul-amarelo)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Correção de cor"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"A correção de cor permite ajustar como as cores são exibidas no dispositivo"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Até você desativar"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Agora"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Alto-falante do smartphone"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ocorreu um problema na conexão. Desligue o dispositivo e ligue-o novamente"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fio"</string> <string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index 0a4e46209939..c2da73c5679c 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (roșu-verde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (albastru-galben)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corecția culorii"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Folosind corecția culorii, puteți ajusta modul în care se afișează culorile pe dispozitiv"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Valoare înlocuită de <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Timp aproximativ rămas: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -517,8 +516,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Până când dezactivați"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Chiar acum"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Difuzorul telefonului"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problemă la conectare. Opriți și reporniți dispozitivul."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispozitiv audio cu fir"</string> <string name="help_label" msgid="3528360748637781274">"Ajutor și feedback"</string> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index b030715da04f..efcce7556910 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалия (красный/зеленый)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалия (синий/желтый)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Коррекция цвета"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Коррекция цвета позволяет изменить настройки цветопередачи на экране устройства."</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Новая настройка: <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"Уровень заряда – <xliff:g id="PERCENTAGE">%1$s</xliff:g>. <xliff:g id="TIME_STRING">%2$s</xliff:g>."</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Заряда хватит примерно на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -518,8 +517,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Пока вы не отключите"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Только что"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Встроенный динамик"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ошибка подключения. Выключите и снова включите устройство."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Проводное аудиоустройство"</string> <string name="help_label" msgid="3528360748637781274">"Справка/отзыв"</string> diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml index 035a159d6e97..590e0e4eded1 100644 --- a/packages/SettingsLib/res/values-si/strings.xml +++ b/packages/SettingsLib/res/values-si/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"වර්ණ දුර්වලතාවය (රතු-කොළ)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"වර්ණ අන්ධතාවය (නිල්-කහ)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"වර්ණ නිවැරදි කිරීම"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"ඔබගේ උපාංගයේ වර්ණ සංදර්ශනය වන ආකාරය සීරුමාරු කරන්න. මෙය ඔබට පහත දේවල් සිදු කිරීමට අවශ්ය විට ප්රයෝජනවත් විය හැකිය:<br/><br/> <ol> <li> වර්ණ වඩාත් නිවැරදිව බැලීම</li> <li> ඔබට අවධානය යොමු කිරීමට උදව් වීමට වර්ණ ඉවත් කිරීම</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"වර්ණ නිවැරදි කිරීම ඔබට ඔබේ උපාංගයෙහි වර්ණ සංදර්ශනය වන ආකාරය සීරුමාරු කිරීමට ඉඩ දේ"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> මගින් ඉක්මවන ලදී"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ක් පමණ ඉතිරියි"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"ඔබ ක්රියාවිරහිත කරන තුරු"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"මේ දැන්"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"දුරකථන ස්පීකරය"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"මෙම දුරකථනය"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"සම්බන්ධ කිරීමේ ගැටලුවකි උපාංගය ක්රියාවිරහිත කර & ආපසු ක්රියාත්මක කරන්න"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"රැහැන්ගත කළ ඕඩියෝ උපාංගය"</string> <string name="help_label" msgid="3528360748637781274">"උදවු & ප්රතිපෝෂණ"</string> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index d9d53515351f..c817ed0e200c 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomália (červená a zelená)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomália (modrá a žltá)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Úprava farieb"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Úprava farieb umožňuje nastaviť spôsob zobrazovania farieb vo vašom zariadení"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Prekonané predvoľbou <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zostáva približne <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -518,8 +517,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Dokým funkciu nevypnete"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Teraz"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Reproduktor telefónu"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Pri pripájaní sa vyskytol problém. Zariadenie vypnite a znova zapnite."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio zariadenie s káblom"</string> <string name="help_label" msgid="3528360748637781274">"Pomocník a spätná väzba"</string> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index 81b1b60ac7fd..464b235e90da 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (rdeča – zelena)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (modra – rumena)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Popravljanje barv"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Popravljanje barv vam omogoča prilagajanje prikaza barv v napravi"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Preglasila nastavitev: <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Še približno <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -518,8 +517,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Dokler ne izklopite"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Pravkar"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Zvočnik telefona"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Težava pri povezovanju. Napravo izklopite in znova vklopite."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Žična zvočna naprava"</string> <string name="help_label" msgid="3528360748637781274">"Pomoč in povratne informacije"</string> diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml index b71e51f35bb4..a2a63e165a96 100644 --- a/packages/SettingsLib/res/values-sq/strings.xml +++ b/packages/SettingsLib/res/values-sq/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (e kuqe - e gjelbër)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (e kaltër - e verdhë)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Korrigjimi i ngjyrës"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Korrigjimi i ngjyrave të lejon të rregullosh mënyrën se si shfaqen ngjyrat në pajisjen tënde"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Mbivendosur nga <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Rreth <xliff:g id="TIME_REMAINING">%1$s</xliff:g> të mbetura"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Deri sa ta çaktivizosh"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Pikërisht tani"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Altoparlanti i telefonit"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem me lidhjen. Fike dhe ndize përsëri pajisjen"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Pajisja audio me tel"</string> <string name="help_label" msgid="3528360748637781274">"Ndihma dhe komentet"</string> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index 4f37180c7f7e..2119303410e0 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалија (црвено-зелено)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалија (плаво-жуто)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекција боја"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Прилагодите начин на који се боје приказују на уређају. То може да буде корисно када желите:<br/><br/> <ol> <li> да вам се боје тачније приказују</li> <li> да уклоните боје како бисте се фокусирали</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Корекција боја вам омогућава да прилагодите начин на који се боје приказују на уређају"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Замењује га <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>–<xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Преостало је око <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,7 +516,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Док не искључите"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Управо"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Звучник телефона"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"Овај телефон"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Проблем при повезивању. Искључите уређај, па га поново укључите"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Жичани аудио уређај"</string> <string name="help_label" msgid="3528360748637781274">"Помоћ и повратне информације"</string> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index 2ec2ded3d34f..c7a21692fea6 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (rött-grönt)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (blått-gult)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Färgkorrigering"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Med färgkorrigering kan du ändra hur färger visas på enheten"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Har åsidosatts av <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Cirka <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kvar"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Tills du inaktiverar funktionen"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Nyss"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefonens högtalare"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Det gick inte att ansluta. Stäng av enheten och slå på den igen"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Ljudenhet med kabelanslutning"</string> <string name="help_label" msgid="3528360748637781274">"Hjälp och feedback"</string> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index 410a4aa0bddc..60014f437c4b 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (nyekundu-kijani)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (samawati-manjano)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Usahihishaji wa rangi"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Badilisha jinsi rangi zinavyoonekana kwenye kifaa chako. Hali hii inaweza kuwa muhimu unapotaka:<br/><br/> <ol> <li> Kuona rangi kwa usahihi zaidi</li> <li> Kuondoa rangi ili kukusaidia kuwa makini</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Urekebishaji rangi hukuruhusu ubadilishe jinsi rangi zinavyoonyeshwa kwenye kifaa chako"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Imetanguliwa na <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Zimesalia takribani <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Hadi utakapoizima"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Sasa hivi"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Spika ya simu"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"Simu hii"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Kuna tatizo la kuunganisha kwenye Intaneti. Zima kisha uwashe kifaa"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kifaa cha sauti kinachotumia waya"</string> <string name="help_label" msgid="3528360748637781274">"Usaidizi na maoni"</string> diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml index 14eb25d36a64..82cce1275b10 100644 --- a/packages/SettingsLib/res/values-ta/strings.xml +++ b/packages/SettingsLib/res/values-ta/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"நிறம் அடையாளங்காண முடியாமை (சிவப்பு-பச்சை)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"நிறம் அடையாளங்காண முடியாமை (நீலம்-மஞ்சள்)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"வண்ணத்திருத்தம்"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"கலர் கரெக்ஷனைப் பயன்படுத்தி உங்கள் சாதனத்தில் வண்ணங்கள் காண்பிக்கப்படும் விதத்தைச் சரிசெய்யலாம்"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> மூலம் மேலெழுதப்பட்டது"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"ஆஃப் செய்யும் வரை"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"சற்றுமுன்"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"மொபைல் ஸ்பீக்கர்"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"இணைப்பதில் சிக்கல். சாதனத்தை ஆஃப் செய்து மீண்டும் ஆன் செய்யவும்"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"வயருடன்கூடிய ஆடியோ சாதனம்"</string> <string name="help_label" msgid="3528360748637781274">"உதவியும் கருத்தும்"</string> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index e652ab71bba3..3b04eb402585 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ప్రొటానోమలీ (ఎరుపు-ఆకుపచ్చ రంగు)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ట్రైటనోమలీ (నీలం-పసుపు రంగు)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"కలర్ సరిచేయడం"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"\'కలర్ సరిచేయడం\' అనే ఫీచర్ సాయంతో, మీ పరికరంలో రంగులు కనిపించే పద్ధతిని మీరు మార్చగలుగుతారు"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ద్వారా భర్తీ చేయబడింది"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> సమయం మిగిలి ఉంది"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"మీరు ఆఫ్ చేసే వరకు"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ఇప్పుడే"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ఫోన్ స్పీకర్"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"కనెక్ట్ చేయడంలో సమస్య ఉంది. పరికరాన్ని ఆఫ్ చేసి, ఆపై తిరిగి ఆన్ చేయండి"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"వైర్ గల ఆడియో పరికరం"</string> <string name="help_label" msgid="3528360748637781274">"సహాయం & ఫీడ్బ్యాక్"</string> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index 4bd7b6ddd21e..a9703213813e 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ตาบอดจางสีแดง (สีแดง/เขียว)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ตาบอดจางสีน้ำเงิน (สีน้ำเงิน/เหลือง)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"การแก้สี"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"ปรับวิธีแสดงสีในอุปกรณ์ การดำเนินการนี้จะเป็นประโยชน์เมื่อคุณต้องการดังนี้<br/><br/> <ol> <li> เห็นสีได้ถูกต้องยิ่งขึ้น</li> <li> นำสีออกเพื่อช่วยให้เห็นชัดเจนยิ่งขึ้น</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"การแก้สีช่วยให้คุณปรับการแสดงสีในอุปกรณ์ได้"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"แทนที่โดย <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"เหลืออีกประมาณ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"จนกว่าคุณจะปิด"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"เมื่อสักครู่"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ลำโพงโทรศัพท์"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"โทรศัพท์เครื่องนี้"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"เกิดปัญหาในการเชื่อมต่อ ปิดอุปกรณ์แล้วเปิดใหม่อีกครั้ง"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"อุปกรณ์เสียงแบบมีสาย"</string> <string name="help_label" msgid="3528360748637781274">"ความช่วยเหลือและความคิดเห็น"</string> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index e56e5b9b6077..bedd00511118 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (pula-berde)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (asul-dilaw)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Pagtatama ng kulay"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Isaayos kung paano ipinapakita ang mga kulay sa iyong device. Makakatulong ito kapag gusto mong:<br/><br/> <ol> <li> Makakita ng mas tumpak na mga kulay</li> <li> Mag-alis ng mga kulay para matulungan kang mag-focus</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Nagbibigay-daan sa iyo ang pagtatama ng kulay na maisaayos kung paano ipinapakita ang mga kulay sa iyong device"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Na-override ng <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Humigit-kumulang <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ang natitira"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Hanggang sa i-off mo"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Ngayon lang"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Speaker ng telepono"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"Ang teleponong ito"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Nagkaproblema sa pagkonekta. I-off at pagkatapos ay i-on ang device"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Wired na audio device"</string> <string name="help_label" msgid="3528360748637781274">"Tulong at feedback"</string> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 5fbf5d41e40b..2b2b44e0f9dc 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomali (kırmızı-yeşil)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomali (mavi-sarı)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Renk düzeltme"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Renk düzeltme, renklerin cihazınızda nasıl görüntüleneceğini düzenlemenize olanak sağlar."</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> tarafından geçersiz kılındı"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Yaklaşık <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Siz kapatana kadar"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Az önce"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefon hoparlörü"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Bağlanırken sorun oluştu. Cihazı kapatıp tekrar açın"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Kablolu ses cihazı"</string> <string name="help_label" msgid="3528360748637781274">"Yardım ve geri bildirim"</string> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index 4511a4bc9ab5..9c5e2aa858aa 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномалія (червоний – зелений)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомалія (синій – жовтий)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекція кольору"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Корекція кольору дає змогу регулювати відтінки зображення на екрані пристрою"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Замінено на <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Залишилося приблизно <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -518,8 +517,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Доки не вимкнути"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Щойно"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Динамік телефона"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Не вдається підключитися. Перезавантажте пристрій."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Дротовий аудіопристрій"</string> <string name="help_label" msgid="3528360748637781274">"Довідка й відгуки"</string> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index e61d281a025f..ee06623240de 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (سرخ سبز)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (نیلا پیلا)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"رنگ کی اصلاح"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"رنگ کی اصلاح آپ کو یہ ایڈجسٹ کرنے کی سہولت دیتی ہے کہ آپ کے آلے پر رنگ کیسے ڈسپلے کئے جاتے ہیں"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> کے ذریعہ منسوخ کردیا گیا"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"تقریباً <xliff:g id="TIME_REMAINING">%1$s</xliff:g> باقی ہے"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"یہاں تک کہ آپ آف کر دیں"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"ابھی ابھی"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"فون اسپیکر"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"منسلک کرنے میں مسئلہ پیش آ گیا۔ آلہ کو آف اور بیک آن کریں"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"وائرڈ آڈیو آلہ"</string> <string name="help_label" msgid="3528360748637781274">"مدد اور تاثرات"</string> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index 0730c6cc1b50..29c0f91c4e60 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaliya (qizil/yashil)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaliya (ko‘k/sariq)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Rangni tuzatish"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Qurilmadagi ranglar qanday chiqishini moslash Bu quyidagi amallarni bajarishga yordam beradi:<br/><br/> <ol> <li> Ranglarni yanada aniq koʻrish</li> <li> Diqqatni jamlash uchun ranglarni olib tashlash</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Ranglarni tuzatish orqali qurilmangizda ranglar qanday chiqishini tuzatish mumkin"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> bilan almashtirildi"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Rejimdan chiqilgunicha"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Hozir"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefon karnayi"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"Shu telefon"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ulanishda muammo yuz berdi. Qurilmani oʻchiring va yoqing"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Simli audio qurilma"</string> <string name="help_label" msgid="3528360748637781274">"Yordam/fikr-mulohaza"</string> diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index 148ed89dc6dd..39beecd0a87a 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Mù màu đỏ không hoàn toàn (đỏ-xanh lục)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Mù màu (xanh lam-vàng)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Chỉnh màu"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"Điều chỉnh cách các màu hiển thị trên thiết bị. Tùy chọn này có thể hữu ích khi bạn muốn:<br/><br/> <ol> <li> Xem các màu chính xác hơn</li> <li> Loại bỏ các màu để giúp bạn tập trung</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Với chế độ chỉnh màu, bạn có thể điều chỉnh cách các màu hiển thị trên thiết bị"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Bị ghi đè bởi <xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Còn khoảng <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Cho đến khi bạn tắt"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Vừa xong"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Loa điện thoại"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"Điện thoại này"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Sự cố kết nối. Hãy tắt thiết bị rồi bật lại"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Thiết bị âm thanh có dây"</string> <string name="help_label" msgid="3528360748637781274">"Trợ giúp và phản hồi"</string> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index 7d1bde3d8c5c..010a4dc9ea6c 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"红色弱视(红绿不分)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"蓝色弱视(蓝黄不分)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色彩校正"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"借助色彩校正功能,您可以调整设备上的颜色显示方式"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已被“<xliff:g id="TITLE">%1$s</xliff:g>”覆盖"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"大约还可使用 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"直到您将其关闭"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"刚刚"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"手机扬声器"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"连接时遇到问题。请关闭并重新开启设备"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有线音频设备"</string> <string name="help_label" msgid="3528360748637781274">"帮助和反馈"</string> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index 06b5cd0dfbaa..1e06a91859e2 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"紅色弱視 (紅綠)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"藍色弱視 (藍黃)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色彩校正"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"調整裝置顯示顏色的方式。這項設定適用於以下情況:<br/><br/> <ol> <li> 想讓裝置更準確地顯示顏色</li> <li> 移除顏色以提高專注力</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"色彩校正功能讓您調整裝置顯示的顏色"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已由「<xliff:g id="TITLE">%1$s</xliff:g>」覆寫"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"還有大約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"直至您關閉為止"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"剛剛"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"手機喇叭"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"這支手機"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連接,請關閉裝置然後重新開機"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音響裝置"</string> <string name="help_label" msgid="3528360748637781274">"說明與意見反映"</string> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index dcfc59934dd8..2c077e7991be 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -424,7 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"紅色弱視 (紅-綠)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"藍色弱視 (藍-黃)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"色彩校正"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="8625527799885140826">"調整裝置顯示顏色的方式。這項設定適用於以下情況:<br/><br/> <ol> <li> 想讓裝置更準確地顯示顏色</li> <li> 移除顏色以提高專注力</li> </ol>"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"色彩校正可讓你調整裝置上顯示的顏色"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"已改為<xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"還能使用約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> @@ -515,7 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"直到你關閉為止"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"剛剛"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"手機喇叭"</string> - <string name="media_transfer_this_phone" msgid="7194341457812151531">"這支手機"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"無法連線,請關閉裝置後再重新開啟"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"有線音訊裝置"</string> <string name="help_label" msgid="3528360748637781274">"說明與意見回饋"</string> diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml index 2297cbe77fac..87cf75b0beaf 100644 --- a/packages/SettingsLib/res/values-zu/strings.xml +++ b/packages/SettingsLib/res/values-zu/strings.xml @@ -424,8 +424,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"I-Protanomaly (bomvu-luhlaza)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"I-Tritanomaly (luhlaza okwesibhakabhaka-phuzi)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Ukulungiswa kombala"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (8625527799885140826) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Ukulungisa umbala kukuvumela ukuthi ulungise indlela imibala eboniswa ngayo kudivayisi yakho"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Igitshezwe ngaphezulu yi-<xliff:g id="TITLE">%1$s</xliff:g>"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"Cishe u-<xliff:g id="TIME_REMAINING">%1$s</xliff:g> osele"</string> @@ -516,8 +515,6 @@ <string name="zen_mode_forever" msgid="3339224497605461291">"Uze uvale isikrini"</string> <string name="time_unit_just_now" msgid="3006134267292728099">"Khona manje"</string> <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Isipikha sefoni"</string> - <!-- no translation found for media_transfer_this_phone (7194341457812151531) --> - <skip /> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Inkinga yokuxhumeka. Vala idivayisi futhi uphinde uyivule"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Idivayisi yomsindo enentambo"</string> <string name="help_label" msgid="3528360748637781274">"Usizo nempendulo"</string> diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index d10ff402aa3a..4c3ffb6245f8 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -214,6 +214,10 @@ <!-- Default for Settings.System.VIBRATE_WHEN_RINGING --> <bool name="def_vibrate_when_ringing">false</bool> + <!-- Default for Settings.Global.CELL_ON; see PhoneConstants.CELL_ON_FLAG. + 0: cellular off; 1: cellular on. --> + <integer name="def_cell_on">1</integer> + <!-- Default for Settings.Global.APPLY_RAMPING_RINGER --> <bool name="def_apply_ramping_ringer">false</bool> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index 6568bffddecc..ba4f7e167188 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -2467,6 +2467,9 @@ class DatabaseHelper extends SQLiteOpenHelper { loadBooleanSetting(stmt, Settings.Global.BLUETOOTH_ON, R.bool.def_bluetooth_on); + loadIntegerSetting(stmt, Settings.Global.CELL_ON, + R.integer.def_cell_on); + // Enable or disable Cell Broadcast SMS loadSetting(stmt, Settings.Global.CDMA_CELL_BROADCAST_SMS, RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED); diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 4dc6d1475c4a..bde2b9f914fe 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -751,7 +751,8 @@ public class SettingsBackupTest { Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_MAGNIFICATION_CONTROLLER, Settings.Secure.SUPPRESS_DOZE, Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, - Settings.Secure.ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT); + Settings.Secure.ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT, + Settings.Secure.TRANSFORM_ENABLED); @Test public void systemSettingsBackedUpOrDenied() { diff --git a/packages/SystemUI/res/drawable/accessibility_floating_menu_background.xml b/packages/SystemUI/res/drawable/accessibility_floating_menu_background.xml new file mode 100644 index 000000000000..ef67e512d95d --- /dev/null +++ b/packages/SystemUI/res/drawable/accessibility_floating_menu_background.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. +--> + +<layer-list + xmlns:android="http://schemas.android.com/apk/res/android"> + + <item android:id="@+id/menu_background_item"> + <shape android:shape="rectangle"> + <corners + android:bottomLeftRadius="@dimen/accessibility_floating_menu_small_single_radius" + android:bottomRightRadius="0dp" + android:topLeftRadius="@dimen/accessibility_floating_menu_small_single_radius" + android:topRightRadius="0dp"/> + <solid + android:color="@color/accessibility_floating_menu_background"/> + </shape> + </item> +</layer-list>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/accessibility_floating_menu_item.xml b/packages/SystemUI/res/layout/accessibility_floating_menu_item.xml new file mode 100644 index 000000000000..f7357b27af5f --- /dev/null +++ b/packages/SystemUI/res/layout/accessibility_floating_menu_item.xml @@ -0,0 +1,37 @@ +<?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:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="@dimen/accessibility_floating_menu_padding" + android:paddingEnd="@dimen/accessibility_floating_menu_padding" + android:orientation="vertical" + android:gravity="center"> + + <View + android:id="@+id/icon_view" + android:layout_width="@dimen/accessibility_floating_menu_small_width_height" + android:layout_height="@dimen/accessibility_floating_menu_small_width_height"/> + + <View + android:id="@+id/transparent_divider" + android:layout_width="match_parent" + android:layout_height="@dimen/accessibility_floating_menu_padding"/> + +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 0623205f9afb..f4e01380b5c3 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Kanselleer"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Deel"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skermopname is gekanselleer"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Skermopname is gestoor, tik om te sien"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Kon nie skermopname uitvee nie"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Kon nie toestemmings kry nie"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Kon nie skermopname begin nie"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index cf7e9fd90a8c..b394a61c30a9 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"ይቅር"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"አጋራ"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"የማያ ገጽ ቀረጻ ተሰርዟል"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"የማያ ገጽ ቀረጻ ተቀምጧል፣ ለመመልከት መታ ያድርጉ"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"የማያ ገጽ ቀረጻን መሰረዝ ላይ ስህተት"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"ፈቃዶችን ማግኘት አልተቻለም"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"የማያ ገጽ ቀረጻን መጀመር ላይ ስህተት"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index db76744bb696..8ad4e4417811 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"إلغاء"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"مشاركة"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"تمّ إلغاء تسجيل الشاشة."</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"تمّ حفظ تسجيل الشاشة، انقر لعرضه."</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"حدث خطأ أثناء حذف تسجيل الشاشة."</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"تعذّر الحصول على أذونات."</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"حدث خطأ في بدء تسجيل الشاشة"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 47c86ec66ba5..308e45031981 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"বাতিল কৰক"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"শ্বেয়াৰ কৰক"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"স্ক্রীণ ৰেকৰ্ড কৰাটো বাতিল কৰা হ’ল"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"স্ক্রীণ ৰেকৰ্ডিং ছেভ কৰা হ’ল, চাবলৈ টিপক"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"স্ক্রীণ ৰেকৰ্ডিং মচি থাকোঁতে কিবা আসোঁৱাহ হ’ল"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"অনুমতি পাব পৰা নগ\'ল"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"স্ক্রীন ৰেকৰ্ড কৰা আৰম্ভ কৰোঁতে আসোঁৱাহ হৈছে"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 8b629c1d03b2..92ed00799492 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Ləğv edin"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Paylaşın"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekranın video çəkimi ləğv edildi"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Ekranın video çəkimi yadda saxlanıldı. Baxmaq üçün klikləyin"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Ekranın video çəkiminin silinməsi zamanı xəta baş verdi"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"İcazələr əldə edilmədi"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Ekranın yazılması ilə bağlı xəta"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 700484cbdd02..d9a3e73f7bd2 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Otkaži"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Deli"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snimanje ekrana je otkazano"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Snimak ekrana je sačuvan, dodirnite da biste pregledali"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Došlo je do problema pri brisanju snimka ekrana"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Preuzimanje dozvola nije uspelo"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Greška pri pokretanju snimanja ekrana"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 7fe5fb48b127..41536f632d7a 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Скасаваць"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Абагуліць"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Запіс экрана скасаваны"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Запіс экрана захаваны. Націсніце, каб прагледзець"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Памылка выдалення запісу экрана"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Не ўдалося атрымаць дазволы"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Памылка пачатку запісу экрана"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 4046f0f3e494..e3ce208669fa 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Отказ"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Споделяне"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Записването на екрана е анулирано"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Записът на екрана е запазен. Докоснете, за да го видите"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"При изтриването на записа на екрана възникна грешка"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Извличането на разрешенията не бе успешно."</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"При стартирането на записа на екрана възникна грешка"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index c88b5782bb99..a3422ddd2717 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"বাতিল করুন"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"শেয়ার করুন"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"স্ক্রিন রেকর্ডিং বাতিল করা হয়েছে"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"স্ক্রিন রেকর্ডিং সেভ করা হয়েছে, দেখতে ট্যাপ করুন"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"স্ক্রিন রেকডিং মুছে ফেলার সময় সমস্যা হয়েছে"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"অনুমতি পাওয়া যায়নি"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"স্ক্রিন রেকর্ডিং শুরু করার সময় সমস্যা হয়েছে"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index ed605d43ac1c..5884311ced95 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Otkaži"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Dijeli"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snimanje ekrana je otkazano"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Snimak ekrana je sačuvan. Dodirnite za prikaz."</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Greška prilikom brisanja snimka ekrana"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Dobijanje odobrenja nije uspjelo"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Greška pri pokretanju snimanja ekrana"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 95775e9cfe7b..7b691e7e09d6 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel·la"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Comparteix"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"S\'ha cancel·lat la gravació de la pantalla"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"S\'ha desat la gravació de la pantalla; toca per mostrar"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"S\'ha produït un error en suprimir la gravació de la pantalla"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"No s\'han pogut obtenir els permisos"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"S\'ha produït un error en iniciar la gravació de pantalla"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 8f86d4277478..29783abbb89d 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Zrušit"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Sdílet"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Nahrávání obrazovky bylo zrušeno"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Záznam obrazovky byl uložen, zobrazíte jej klepnutím"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Při mazání záznamu obrazovky došlo k chybě"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Nepodařilo se načíst oprávnění"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Při spouštění nahrávání obrazovky došlo k chybě"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index aad5d2576ed8..718731489778 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuller"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Del"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skærmoptagelsen er annulleret"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Skærmoptagelsen er gemt. Tryk for at se den."</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Der opstod en fejl ved sletning af skærmoptagelsen"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Det lykkedes ikke et hente tilladelserne"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Skærmoptagelsen kunne ikke startes"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 3266954d7be5..358627842609 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Abbrechen"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Teilen"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Bildschirmaufzeichnung abgebrochen"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Bildschirmaufzeichnung gespeichert, zum Ansehen tippen"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Fehler beim Löschen der Bildschirmaufzeichnung"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Berechtigungen nicht erhalten"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Fehler beim Start der Bildschirmaufzeichnung"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 7ba79889e51e..622b1ae46d2f 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Ακύρωση"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Κοινοποίηση"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Η εγγραφή οθόνης ακυρώθηκε"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Η εγγραφή οθόνης αποθηκεύτηκε. Πατήστε για προβολή."</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Παρουσιάστηκε σφάλμα κατά τη διαγραφή της εγγραφής οθόνης"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Η λήψη αδειών απέτυχε"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Σφάλμα κατά την έναρξη της εγγραφής οθόνης"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 5cff3c0be53d..8f5a99868193 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 0ee516615235..365539fa6245 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 5cff3c0be53d..8f5a99868193 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 5cff3c0be53d..8f5a99868193 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording cancelled"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index a9e20165d25b..6d4151ed1376 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancel"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Share"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Screen recording canceled"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Screen recording saved, tap to view"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Error deleting screen recording"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Failed to get permissions"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Error starting screen recording"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 4157fca000af..d3126542bda5 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Compartir"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Se canceló la grabación de pantalla"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Se guardó la grabación de pantalla; presiona para verla"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"No se pudo borrar la grabación de pantalla"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Error al obtener permisos"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Error al iniciar la grabación de pantalla"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 8d8f5b5c2846..4d36799f3143 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Compartir"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Se ha cancelado la grabación de la pantalla"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Se ha guardado la grabación de la pantalla; toca para verla"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"No se ha podido eliminar la grabación de la pantalla"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"No se han podido obtener los permisos"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"No se ha podido empezar a grabar la pantalla"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 06fcd0534027..cc6e6cfdfaf6 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Tühista"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Jaga"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekraanikuva salvestamine on tühistatud"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Ekraanikuva salvestis on salvestatud, puudutage vaatamiseks"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Viga ekraanikuva salvestise kustutamisel"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Lubade hankimine ebaõnnestus"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Viga ekraanikuva salvestamise alustamisel"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 2eab6eb61dfa..14469d8c3e6d 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Utzi"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Partekatu"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Utzi zaio pantaila grabatzeari"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Gorde da pantailaren grabaketa; sakatu ikusteko"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Errore bat gertatu da pantailaren grabaketa ezabatzean"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Ezin izan dira lortu baimenak"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Errore bat gertatu da pantaila grabatzen hastean"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index b25f118f0cee..dc2db52d21c8 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"لغو"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"همرسانی"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"ضبط صفحهنمایش لغو شد"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"ضبط صفحهنمایش ذخیره شد، برای مشاهده ضربه بزنید"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"خطا در حذف فایل ضبط صفحهنمایش"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"مجوزها دریافت نشدند"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"خطا هنگام شروع ضبط صفحهنمایش"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index c9043d1fcbda..3b64a68f119b 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Peruuta"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Jaa"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Näytön tallennus peruutettu"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Näyttötallenne tallennettu, katso napauttamalla"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Virhe poistettaessa näyttötallennetta"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Käyttöoikeuksien hakeminen epäonnistui."</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Virhe näytön tallennuksen aloituksessa"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 8e6c39c824c7..f7a5c535354d 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuler"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Partager"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"L\'enregistrement d\'écran a été annulé"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"L\'enregistrement d\'écran est terminé. Touchez ici pour l\'afficher."</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Une erreur s\'est produite lors de la suppression de l\'enregistrement d\'écran"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Impossible d\'obtenir les autorisations"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Une erreur s\'est produite lors du démarrage de l\'enregistrement d\'écran"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 837a424f8b27..45bf7bd7612b 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuler"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Partager"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Enregistrement de l\'écran annulé"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Enregistrement de l\'écran enregistré. Appuyez pour afficher"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Erreur lors de la suppression de l\'enregistrement de l\'écran"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Échec d\'obtention des autorisations"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Erreur lors du démarrage de l\'enregistrement de l\'écran"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 199dd543bb8f..4cff5a96e06a 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Compartir"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Cancelouse a gravación de pantalla"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Gardouse a gravación de pantalla; toca esta notificación para visualizala"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Produciuse un erro ao eliminar a gravación de pantalla"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Produciuse un erro ao obter os permisos"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Produciuse un erro ao iniciar a gravación da pantalla"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index d19c341c7ab6..37648e5c049e 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"રદ કરો"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"શેર કરો"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"સ્ક્રીન રેકોર્ડિંગ રદ કર્યું"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"સ્ક્રીન રેકોર્ડિંગ સાચવ્યું, જોવા માટે ટૅપ કરો"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"સ્ક્રીન રેકોર્ડિંગ ડિલીટ કરવામાં ભૂલ આવી"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"પરવાનગીઓ મેળવવામાં નિષ્ફળ રહ્યાં"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"સ્ક્રીનને રેકૉર્ડ કરવાનું શરૂ કરવામાં ભૂલ"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 764acad61b6f..c47accca527a 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"रद्द करें"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"शेयर करें"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"स्क्रीन रिकॉर्डिंग रद्द कर दी गई"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"स्क्रीन रिकॉर्डिंग सेव की गई, देखने के लिए टैप करें"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"स्क्रीन रिकॉर्डिंग मिटाने में गड़बड़ी हुई"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"मंज़ूरी नहीं मिल सकी"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रीन को रिकॉर्ड करने में गड़बड़ी आ रही है"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 55970a04b2a6..b0acaaa1fec5 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Odustani"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Dijeli"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snimanje zaslona otkazano"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Snimanje zaslona spremljeno je, dodirnite da biste ga pregledali"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Pogreška prilikom brisanja snimanja zaslona"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Dohvaćanje dopuštenja nije uspjelo"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Pogreška prilikom pokretanja snimanja zaslona"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index ee3f45db05d2..65db64463c20 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Mégse"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Megosztás"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"A képernyő rögzítése megszakítva"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Képernyőfelvétel mentve, koppintson a megtekintéshez"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Hiba történt a képernyőről készült felvétel törlésekor"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Nincs engedély"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Hiba a képernyőrögzítés indításakor"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 84451eb7f490..e38708f179c3 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Չեղարկել"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Կիսվել"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Էկրանի տեսագրումը չեղարկվեց"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Էկրանի տեսագրությունը պահվեց։ Հպեք՝ դիտելու համար:"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Չհաջողվեց ջնջել տեսագրությունը"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Չհաջողվեց ստանալ անհրաժեշտ թույլտվությունները"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Չհաջողվեց սկսել տեսագրումը"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index f694e1d0dec1..d0e494b30319 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Batal"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Bagikan"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Rekaman layar dibatalkan"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Rekaman layar disimpan, ketuk untuk melihat"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Error saat menghapus rekaman layar"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Gagal mendapatkan izin"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Terjadi error saat memulai perekaman layar"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 08210ef1d5cc..d34769b34e7e 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Hætta við"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Deila"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Hætt við skjáupptöku"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Skjáupptaka vistuð, ýttu til að skoða"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Villa við að eyða skjáupptöku"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Ekki tókst að fá heimildir"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Villa við að hefja upptöku skjás"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index d47a4549e18a..03e745cd96fd 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annulla"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Condividi"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Registrazione dello schermo annullata"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Registrazione dello schermo salvata. Tocca per visualizzarla."</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Errore durante l\'eliminazione della registrazione dello schermo"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Impossibile ottenere le autorizzazioni"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Errore durante l\'avvio della registrazione dello schermo"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index e937a5aa68f8..b40bef3145b9 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"ביטול"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"שיתוף"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"הקלטת המסך בוטלה"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"הקלטת המסך נשמרה, יש להקיש כדי להציג"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"שגיאה במחיקת הקלטת המסך"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"קבלת ההרשאות נכשלה"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"שגיאה בהפעלה של הקלטת המסך"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 802e160a205c..9e8f6f2572ef 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"キャンセル"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"共有"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"画面の録画をキャンセルしました"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"画面の録画を保存しました。タップで表示できます"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"画面の録画の削除中にエラーが発生しました"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"権限を取得できませんでした"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"画面の録画中にエラーが発生しました"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 53cf03e12aaa..c667267584c2 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"გაუქმება"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"გაზიარება"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"ეკრანის ჩაწერა გაუქმდა"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"ეკრანის ჩანაწერი შენახულია, შეეხეთ სანახავად"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"ეკრანის ჩანაწერის წაშლისას წარმოიშვა შეცდომა"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"ნებართვების მიღება ვერ მოხერხდა"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"ეკრანის ჩაწერის დაწყებისას წარმოიქმნა შეცდომა"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 68519422352c..f3aa7b015685 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Бас тарту"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Бөлісу"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Экранды бейнеге жазудан бас тартылды"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Экран бейне жазбасы сақталды, көру үшін түртіңіз"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Экран бейне жазбасын жою кезінде қате кетті"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Рұқсаттар алынбады"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Экрандағы бейнені жазу кезінде қате шықты."</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index d7faeecb26aa..8164adceb105 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"បោះបង់"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"ចែករំលែក"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"បានបោះបង់ការថតសកម្មភាពអេក្រង់"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"បានរក្សាទុកការថតសកម្មភាពអេក្រង់។ សូមចុចដើម្បីមើល"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"មានបញ្ហាក្នុងការលុបការថតសកម្មភាពអេក្រង់"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"មិនអាចទទួលបានការអនុញ្ញាតទេ"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"មានបញ្ហាក្នុងការចាប់ផ្ដើមថតអេក្រង់"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 851039ffd1a8..9569697d1c22 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"ರದ್ದುಮಾಡಿ"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"ಹಂಚಿಕೊಳ್ಳಿ"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅನ್ನು ರದ್ದುಮಾಡಲಾಗಿದೆ"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅನ್ನು ಉಳಿಸಲಾಗಿದೆ, ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಅಳಿಸುವಾಗ ದೋಷ ಕಂಡುಬಂದಿದೆ"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"ಅನುಮತಿಗಳನ್ನು ಪಡೆಯುವಲ್ಲಿ ವಿಫಲವಾಗಿದೆ"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಪ್ರಾರಂಭಿಸುವಾಗ ದೋಷ ಕಂಡುಬಂದಿದೆ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index d42899252bb7..b5a5fd6002f0 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"취소"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"공유"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"화면 녹화가 취소되었습니다."</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"화면 녹화본이 저장되었습니다. 확인하려면 탭하세요."</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"화면 녹화는 삭제하는 중에 오류가 발생했습니다."</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"권한을 확보하지 못했습니다."</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"화면 녹화 시작 중 오류 발생"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index d726d55ca6f1..aa76b4cb1059 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Жокко чыгаруу"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Бөлүшүү"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Экранды жаздыруу жокко чыгарылды"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Экранды жаздыруу сакталды, көрүү үчүн таптап коюңуз"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Экранды жаздырууну өчүрүүдө ката кетти"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Уруксаттар алынбай калды"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Экранды жаздырууну баштоодо ката кетти"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 23df8bcebded..3ee461020a3a 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"ຍົກເລີກ"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"ແບ່ງປັນ"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"ຍົກເລີກການບັນທຶກໜ້າຈໍແລ້ວ"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"ຈັດເກັບການບັນທຶກໜ້າຈໍ, ແຕະເພື່ອເບິ່ງ"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"ເກີດຄວາມຜິດພາດໃນການລຶບການບັນທຶກໜ້າຈໍ"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"ໂຫຼດສິດອະນຸຍາດບໍ່ສຳເລັດ"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"ເກີດຄວາມຜິດພາດໃນການບັນທຶກໜ້າຈໍ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 64b4d6df3f79..fb53e5344e97 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Atšaukti"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Bendrinti"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekrano įrašymas atšauktas"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Ekrano įrašas išsaugotas, palieskite ir peržiūrėkite"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Ištrinant ekrano įrašą įvyko klaida"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Nepavyko gauti leidimų"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Pradedant ekrano vaizdo įrašymą iškilo problema"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 225b9aa7444a..60e9c303701a 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Atcelt"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Kopīgot"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekrāna ierakstīšana ir atcelta."</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Ekrāna ieraksts ir saglabāts. Pieskarieties, lai to skatītu."</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Dzēšot ekrāna ierakstu, radās kļūda."</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Neizdevās iegūt atļaujas."</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Sākot ierakstīt ekrāna saturu, radās kļūda."</string> @@ -724,7 +721,7 @@ <string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Statuss:</b> svarīgums pazemināts, un paziņojums tiks rādīts bez skaņas"</string> <string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Statuss:</b> rangs paaugstināts"</string> <string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Statuss:</b> rangs pazemināts"</string> - <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Parādās sarunu sadaļas augšdaļā un kā peldošs burbulis, kā arī bloķēšanas ekrānā tiek rādīts profila attēls"</string> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Parādās sarunu sadaļas augšdaļā, arī kā peldošs burbulis, profila attēls parādās bloķēšanas ekrānā"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Iestatījumi"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritārs"</string> <string name="no_shortcut" msgid="8257177117568230126">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstītas sarunu funkcijas."</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index c74786e9bf85..a65f9876323f 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Откажи"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Сподели"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Снимањето екран е откажано"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Снимката од екранот е зачувана, допрете за да ја видите"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Грешка при бришењето на снимката од екранот"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Не успеаја да се добијат дозволи"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Грешка при почетокот на снимањето на екранот"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index b54c6b02d11a..f41ee3b86ca5 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"റദ്ദാക്കുക"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"പങ്കിടുക"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"സ്ക്രീൻ റെക്കോർഡിംഗ് റദ്ദാക്കി"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"സ്ക്രീൻ റെക്കോർഡിംഗ് സംരക്ഷിച്ചു, കാണാൻ ടാപ്പ് ചെയ്യുക"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"സ്ക്രീൻ റെക്കോർഡിംഗ് ഇല്ലാതാക്കുന്നതിൽ പിശക്"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"അനുമതികൾ ലഭിച്ചില്ല"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"സ്ക്രീൻ റെക്കോർഡിംഗ് ആരംഭിക്കുന്നതിൽ പിശക്"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 93d66f45be6b..30b539794d2c 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Цуцлах"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Хуваалцах"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Дэлгэцийн бичлэгийг цуцалсан"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Дэлгэцийн бичлэгийг хадгалсан. Харахын тулд товшино уу"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Дэлгэцийн бичлэгийг устгахад алдаа гарлаа"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Зөвшөөрөл авч чадсангүй"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Дэлгэцийн бичлэгийг эхлүүлэхэд алдаа гарлаа"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 093a03b4cd95..6a17fbcdbac2 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"रद्द करा"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"शेअर करा"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"स्क्रीन रेकॉर्डिंग रद्द केले"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"स्क्रीन रेकॉर्डिंग सेव्ह केली, पाहण्यासाठी टॅप करा"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"स्क्रीन रेकॉर्डिंग हटवताना एरर आली"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"परवानग्या मिळवता आल्या नाहीत"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रीन रेकॉर्डिंग सुरू करताना एरर आली"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index ca5c6cf0d45b..dbe2c561e222 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Batal"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Kongsi"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Rakaman skrin dibatalkan"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Rakaman skrin disimpan, ketik untuk melihat"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Ralat semasa memadamkan rakaman skrin"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Gagal mendapatkan kebenaran"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Ralat semasa memulakan rakaman skrin"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index cd4d5907da16..2b3d99c91e8b 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"မလုပ်တော့"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"မျှဝေရန်"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"ဖန်သားပြင် ရိုက်ကူးမှု ပယ်ဖျက်လိုက်ပါပြီ"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"ဖန်သားပြင် ရိုက်ကူးမှု သိမ်းထားသည်၊ ကြည့်ရန် တို့ပါ"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"ဖန်သားပြင် ရိုက်ကူးမှု ဖျက်ရာတွင် အမှားအယွင်းရှိနေသည်"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"ခွင့်ပြုချက် မရယူနိုင်ပါ"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"ဖန်သားပြင် ရိုက်ကူးမှု စတင်ရာတွင် အမှားအယွင်းရှိနေသည်"</string> @@ -212,7 +209,7 @@ <string name="accessibility_desc_connected" msgid="3082590384032624233">"ချိတ်ဆက်ထားသည်"</string> <string name="accessibility_desc_connecting" msgid="8011433412112903614">"ချိတ်ဆက်နေ။"</string> <string name="data_connection_hspa" msgid="6096234094857660873">"HSPA"</string> - <string name="data_connection_roaming" msgid="375650836665414797">"ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်ခြင်း"</string> + <string name="data_connection_roaming" msgid="375650836665414797">"ပြင်ပကွန်ရက်သုံးခြင်း"</string> <string name="accessibility_data_connection_wifi" msgid="4422160347472742434">"Wi-Fi"</string> <string name="accessibility_no_sim" msgid="1140839832913084973">"ဆင်းကဒ်မရှိပါ။"</string> <string name="accessibility_cell_data" msgid="172950885786007392">"မိုဘိုင်းဒေတာ"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 52c289d34d9f..3825f998d013 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Avbryt"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Del"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skjermopptak er avbrutt"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Skjermopptaket er lagret. Trykk for å se det"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Feil ved sletting av skjermopptaket"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Kunne ikke få tillatelser"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Feil ved start av skjermopptaket"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 63a842356d8e..008f35e76b5f 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"रद्द गर्नुहोस्"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"सेयर गर्नुहोस्"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"स्क्रिन रेकर्ड गर्ने कार्य रद्द गरियो"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"स्क्रिन रेकर्डिङ सुरक्षित गरियो, हेर्न ट्याप गर्नुहोस्"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"स्क्रिनको रेकर्डिङ मेट्ने क्रममा त्रुटि"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"अनुमति प्राप्त गर्न सकिएन"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"स्क्रिन रेकर्ड गर्न थाल्ने क्रममा त्रुटि भयो"</string> diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml index 37ec576be4be..d571f2f17497 100644 --- a/packages/SystemUI/res/values-night/colors.xml +++ b/packages/SystemUI/res/values-night/colors.xml @@ -102,4 +102,6 @@ <color name="privacy_circle_camera">#81C995</color> <!-- g300 --> <color name="privacy_circle_microphone_location">#FCAD70</color> <!--o300 --> + <!-- Accessibility floating menu --> + <color name="accessibility_floating_menu_background">#B3000000</color> <!-- 70% --> </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 9da7ad74c505..b35cd53a67c7 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Annuleren"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Delen"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Schermopname geannuleerd"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Schermopname opgeslagen, tik om te bekijken"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Fout bij verwijderen van schermopname"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Kan rechten niet ophalen"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Fout bij starten van schermopname"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index c847d1545cb1..5656da5635ac 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"ବାତିଲ୍ କରନ୍ତୁ"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"ସେୟାର୍ କରନ୍ତୁ"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ବାତିଲ୍ କରିଦିଆଯାଇଛି"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ସେଭ୍ ହୋଇଛି, ଦେଖିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ଡିଲିଟ୍ କରିବାରେ ତ୍ରୁଟି"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"ଅନୁମତି ପାଇବାରେ ଅସଫଳ ହେଲା।"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ଆରମ୍ଭ କରିବାରେ ତ୍ରୁଟି"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 53a71a6f74e5..ee0ccd62080f 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"ਰੱਦ ਕਰੋ"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"ਸਾਂਝਾ ਕਰੋ"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"ਸਕ੍ਰੀਨ ਦੀ ਰਿਕਾਰਡਿੰਗ ਰੱਦ ਕੀਤੀ ਗਈ"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਰੱਖਿਅਤ ਕੀਤੀ ਗਈ, ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਨੂੰ ਮਿਟਾਉਣ ਦੌਰਾਨ ਗੜਬੜ ਹੋਈ"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"ਇਜਾਜ਼ਤਾਂ ਪ੍ਰਾਪਤ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਵੇਲੇ ਗੜਬੜ ਹੋਈ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index f8c275d58cd7..8bfc7de476de 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Anuluj"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Udostępnij"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Anulowano nagrywanie zawartości ekranu"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Zapisano nagranie zawartości ekranu – kliknij, by je obejrzeć"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Błąd podczas usuwania nagrania zawartości ekranu"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Nie udało się uzyskać uprawnień"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Błąd podczas rozpoczynania rejestracji zawartości ekranu"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index ab53aa0fb2cb..6a19857cb550 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Compartilhar"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Gravação de tela cancelada"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Gravação de tela salva, toque para ver"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Erro ao excluir a gravação de tela"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Não foi possível acessar as permissões"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Erro ao iniciar a gravação de tela"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 884b2101f90a..01ccf0062605 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Partilhar"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Gravação de ecrã cancelada."</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Gravação de ecrã guardada. Toque para ver."</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Erro ao eliminar a gravação de ecrã."</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Falha ao obter as autorizações."</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Ocorreu um erro ao iniciar a gravação do ecrã."</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index ab53aa0fb2cb..6a19857cb550 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Cancelar"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Compartilhar"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Gravação de tela cancelada"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Gravação de tela salva, toque para ver"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Erro ao excluir a gravação de tela"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Não foi possível acessar as permissões"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Erro ao iniciar a gravação de tela"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 6a928da1a969..a766db78578a 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Anulați"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Trimiteți"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Înregistrarea ecranului a fost anulată"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Înregistrarea ecranului a fost salvată. Atingeți pentru vizualizare"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Eroare la ștergerea înregistrării ecranului"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Nu s-au obținut permisiunile"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Eroare la începerea înregistrării ecranului"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index f064e4f54f4b..817b3fe20a75 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Отмена"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Поделиться"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Запись видео с экрана отменена"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Запись видео с экрана сохранена. Чтобы открыть ее, нажмите на уведомление."</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Не удалось удалить запись видео с экрана"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Не удалось получить необходимые разрешения"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Не удалось начать запись видео с экрана."</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 5a1f5993c817..00da260a75fb 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"අවලංගු කරන්න"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"බෙදා ගන්න"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"තිර පටිගත කිරීම අවලංගු කරන ලදී"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"තිර පටිගත කිරීම සුරකින ලදී, බැලීමට තට්ටු කරන්න"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"තිර පටිගත කිරීම මැකීමේ දෝෂයකි"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"අවසර ලබා ගැනීමට අසමත් විය"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"තිර පටිගත කිරීම ආරම්භ කිරීමේ දෝෂයකි"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index eba75e36db7f..9bf0a8d1ab9c 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Zrušiť"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Zdieľať"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Záznam obrazovky bol zrušený"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Záznam obrazovky bol uložený, zobrazíte ho klepnutím"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Pri odstraňovaní záznamu obrazovky sa vyskytla chyba"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Nepodarilo sa získať povolenia"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Pri spustení nahrávania obrazovky sa vyskytla chyba"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 7bf496a2780e..5100d261f4cb 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Prekliči"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Deli"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Snemanje zaslona je preklicano"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Videoposnetek zaslona je shranjen, dotaknite se za ogled"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Napaka pri brisanju videoposnetka zaslona"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Dovoljenj ni bilo mogoče pridobiti"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Napaka pri začenjanju snemanja zaslona"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index ac22fea9c3c9..27740ad36bc6 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Anulo"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Ndaj"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Regjistrimi i ekranit u anulua"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Regjistrimi i ekranit u ruajt, trokit për ta parë"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Gabim gjatë fshirjes së regjistrimit të ekranit"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Marrja e lejeve dështoi"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Gabim gjatë nisjes së regjistrimit të ekranit"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index bcfcf3083c62..c0d7dca01a6c 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Откажи"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Дели"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Снимање екрана је отказано"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Снимак екрана је сачуван, додирните да бисте прегледали"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Дошло је до проблема при брисању снимка екрана"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Преузимање дозвола није успело"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Грешка при покретању снимања екрана"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index f1f9f20b49ec..b98caff9fed5 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Avbryt"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Dela"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Skärminspelningen har avbrutits"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Skärminspelningen har sparats, tryck här om du vill titta på den"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Det gick inte att radera skärminspelningen"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Behörighet saknas"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Det gick inte att starta skärminspelningen"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 5a4088ed25f5..22cab56f1f6d 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Ghairi"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Shiriki"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Imeghairi mchakato wa kurekodi skrini"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Imehifadhi rekodi ya skrini, gusa ili uangalie"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Hitilafu imetokea wakati wa kufuta rekodi ya skrini"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Imeshindwa kupata ruhusa"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Hitilafu imetokea wakati wa kuanza kurekodi skrini"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 5750119f4c5b..23bb3fd6d175 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"ரத்துசெய்"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"பகிர்"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"திரை ரெக்கார்டிங் ரத்துசெய்யப்பட்டது"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"திரை ரெக்கார்டிங் சேமிக்கப்பட்டது, பார்க்கத் தட்டவும்"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"திரை ரெக்கார்டிங்கை நீக்குவதில் பிழை"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"அனுமதிகளைப் பெற இயலவில்லை"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"ஸ்கிரீன் ரெக்கார்டிங்கைத் தொடங்குவதில் பிழை"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index f39fa69054b7..bb4e11b208d6 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"రద్దు చేయి"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"షేర్ చేయి"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"స్క్రీన్ రికార్డ్ రద్దు చేయబడింది"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"స్క్రీన్ రికార్డింగ్ సేవ్ చేయబడింది, చూడటం కోసం నొక్కండి"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"స్క్రీన్ రికార్డింగ్ని తొలగిస్తున్నప్పుడు ఎర్రర్ ఏర్పడింది"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"అనుమతులను పొందడం విఫలమైంది"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"స్క్రీన్ రికార్డింగ్ ప్రారంభించడంలో ఎర్రర్ ఏర్పడింది"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index a726dda73682..98465870ce64 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"ยกเลิก"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"แชร์"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"ยกเลิกการบันทึกหน้าจอแล้ว"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"บันทึกการบันทึกหน้าจอแล้ว แตะเพื่อดู"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"เกิดข้อผิดพลาดในการลบการบันทึกหน้าจอ"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"ขอสิทธิ์ไม่สำเร็จ"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"เกิดข้อผิดพลาดขณะเริ่มบันทึกหน้าจอ"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 92d5a66bb116..84c370102777 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Kanselahin"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Ibahagi"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Kinansela ang pag-record ng screen"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Na-save ang pag-record ng screen, i-tap para tingnan"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Error sa pag-delete sa pag-record ng screen"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Hindi nakuha ang mga pahintulot"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Nagkaroon ng error sa pagsisimula ng pag-record ng screen"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index c708b5a6a7c3..fca50889e83e 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"İptal"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Paylaş"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekran kaydı iptal edildi"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Ekran kaydı tamamlandı, görüntülemek için dokunun"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Ekran kaydı silinirken hata oluştu"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"İzinler alınamadı"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Ekran kaydı başlatılırken hata oluştu"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index e51122b36c75..3ae2b6a7caa0 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Скасувати"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Поділитися"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Запис екрана скасовано"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Запис екрана збережено. Натисніть, щоб переглянути"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Не вдалося видалити запис екрана"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Не вдалось отримати дозволи"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Не вдалося почати запис екрана"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index d2e37e7ac4bc..fc2cb01d2b91 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"منسوخ کریں"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"اشتراک کریں"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"اسکرین ریکارڈنگ منسوخ ہو گئی"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"اسکرین ریکارڈنگ محفوظ ہو گئی، دیکھنے کیلئے تھپتھپائیں"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"اسکرین ریکارڈنگ کو حذف کرنے میں خرابی"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"اجازتیں حاصل کرنے میں ناکامی"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"اسکرین ریکارڈنگ شروع کرنے میں خرابی"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 4615f4a7e55f..a9755e94294e 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Bekor qilish"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Ulashish"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ekrandan yozib olish bekor qilindi"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Ekrandan yozib olingan video saqlandi. Uni ochish uchun bildirishnomani bosing."</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Ekrandan yozib olingan vi olib tashlanmadi"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Zarur ruxsatlar olinmadi"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Ekranni yozib olish boshlanmadi"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index ee97bc541c4f..3d4f904f8b86 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Hủy"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Chia sẻ"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Đã hủy bản ghi màn hình"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Đã lưu bản ghi màn hình, nhấn để xem"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Lỗi khi xóa bản ghi màn hình"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Không được cấp đủ quyền"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Lỗi khi bắt đầu ghi màn hình"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index bee359dd00c7..5557ca282f3b 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"取消"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"分享"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"已取消录制屏幕"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"屏幕录制内容已保存,点按即可查看"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"删除屏幕录制内容时出错"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"无法获取权限"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"启动屏幕录制时出错"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 7b4f663bc516..4e4a6f998653 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"取消"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"分享"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"已取消錄影畫面"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"已儲存錄影畫面,輕按即可查看"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"刪除錄影畫面時發生錯誤"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"無法獲得權限"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"開始錄影畫面時發生錯誤"</string> @@ -449,7 +446,7 @@ <string name="require_unlock_for_nfc" msgid="1305686454823018831">"解鎖方可使用 NFC"</string> <string name="do_disclosure_generic" msgid="4896482821974707167">"此裝置屬於您的機構"</string> <string name="do_disclosure_with_name" msgid="2091641464065004091">"此裝置屬於「<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>」"</string> - <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"此為「<xliff:g id="ORGANIZATION_NAME">%s</xliff:g>」提供的裝置"</string> + <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"此裝置由 <xliff:g id="ORGANIZATION_NAME">%s</xliff:g> 提供"</string> <string name="phone_hint" msgid="6682125338461375925">"從圖示滑動即可使用手機功能"</string> <string name="voice_hint" msgid="7476017460191291417">"從圖示滑動即可使用語音助手"</string> <string name="camera_hint" msgid="4519495795000658637">"從圖示滑動即可使用相機功能"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 1dddeba06a8a..d06c594e8d17 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"取消"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"分享"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"已取消錄製螢幕畫面"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"已儲存螢幕畫面錄製內容,輕觸即可查看"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"刪除螢幕畫面錄製內容時發生錯誤"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"無法取得權限"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"開始錄製螢幕畫面時發生錯誤"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index c6f0ef9ae1c8..e71aa88c6591 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -116,10 +116,7 @@ <string name="screenrecord_cancel_label" msgid="7850926573274483294">"Khansela"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Yabelana"</string> <string name="screenrecord_cancel_success" msgid="1775448688137393901">"Ukurekhoda isikrini kukhanseliwe"</string> - <!-- no translation found for screenrecord_save_title (1886652605520893850) --> - <skip /> - <!-- no translation found for screenrecord_save_text (3008973099800840163) --> - <skip /> + <string name="screenrecord_save_message" msgid="490522052388998226">"Ukurekhoda isikrini kulondoloziwe, thepha ukuze ubuke"</string> <string name="screenrecord_delete_error" msgid="2870506119743013588">"Iphutha lokususa ukurekhoda isikrini"</string> <string name="screenrecord_permission_error" msgid="7856841237023137686">"Yehlulekile ukuthola izimvume"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Iphutha lokuqala ukurekhoda isikrini"</string> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 424172458b80..edb58729293b 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -277,4 +277,8 @@ <!-- TODO(b/178093014) Colors for privacy dialog. These should be changed to the new palette --> <color name="privacy_circle_camera">#1E8E3E</color> <!-- g600 --> <color name="privacy_circle_microphone_location">#E8710A</color> <!--o600 --> + + <!-- Accessibility floating menu --> + <color name="accessibility_floating_menu_background">#CCFFFFFF</color> <!-- 80% --> + <color name="accessibility_floating_menu_stroke_dark">#26FFFFFF</color> <!-- 15% --> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index c0e474ae7882..96929e3baaff 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1353,6 +1353,19 @@ <dimen name="people_space_image_radius">20dp</dimen> <dimen name="people_space_widget_background_padding">6dp</dimen> + <!-- Accessibility floating menu --> + <dimen name="accessibility_floating_menu_elevation">5dp</dimen> + <dimen name="accessibility_floating_menu_stroke_width">1dp</dimen> + <dimen name="accessibility_floating_menu_stroke_inset">-2dp</dimen> + <dimen name="accessibility_floating_menu_margin">16dp</dimen> + <dimen name="accessibility_floating_menu_padding">6dp</dimen> + <dimen name="accessibility_floating_menu_small_width_height">36dp</dimen> + <dimen name="accessibility_floating_menu_small_single_radius">25dp</dimen> + <dimen name="accessibility_floating_menu_small_multiple_radius">20dp</dimen> + <dimen name="accessibility_floating_menu_large_width_height">56dp</dimen> + <dimen name="accessibility_floating_menu_large_single_radius">33dp</dimen> + <dimen name="accessibility_floating_menu_large_multiple_radius">35dp</dimen> + <dimen name="rounded_slider_height">48dp</dimen> <!-- rounded_slider_height / 2 --> <dimen name="rounded_slider_corner_radius">24dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java new file mode 100644 index 000000000000..b71e135fe644 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java @@ -0,0 +1,175 @@ +/* + * 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.accessibility.floatingmenu; + +import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED; +import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE; +import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY; +import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE; +import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; + +import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets; +import static com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuView.ShapeType; +import static com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuView.SizeType; + +import android.content.Context; +import android.database.ContentObserver; +import android.os.Handler; +import android.os.Looper; +import android.os.UserHandle; +import android.provider.Settings; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * Contains logic for an accessibility floating menu view. + */ +public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu { + private static final int DEFAULT_FADE_EFFECT_ENABLED = 1; + private static final float DEFAULT_OPACITY_VALUE = 0.55f; + private final Context mContext; + private final AccessibilityFloatingMenuView mMenuView; + + private final ContentObserver mContentObserver = + new ContentObserver(new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange) { + mMenuView.onTargetsChanged(getTargets(mContext, ACCESSIBILITY_BUTTON)); + } + }; + + private final ContentObserver mSizeContentObserver = + new ContentObserver(new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange) { + mMenuView.setSizeType(getSizeType(mContext)); + } + }; + + private final ContentObserver mShapeContentObserver = + new ContentObserver(new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange) { + mMenuView.setShapeType(getShapeType(mContext)); + } + }; + + private final ContentObserver mFadeOutContentObserver = + new ContentObserver(new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange) { + mMenuView.updateOpacityWith(isFadeEffectEnabled(mContext), + getOpacityValue(mContext)); + } + }; + + public AccessibilityFloatingMenu(Context context) { + mContext = context; + mMenuView = new AccessibilityFloatingMenuView(context); + } + + @VisibleForTesting + AccessibilityFloatingMenu(Context context, AccessibilityFloatingMenuView menuView) { + mContext = context; + mMenuView = menuView; + } + + @Override + public boolean isShowing() { + return mMenuView.isShowing(); + } + + @Override + public void show() { + if (isShowing()) { + return; + } + + mMenuView.show(); + mMenuView.onTargetsChanged(getTargets(mContext, ACCESSIBILITY_BUTTON)); + mMenuView.updateOpacityWith(isFadeEffectEnabled(mContext), + getOpacityValue(mContext)); + mMenuView.setSizeType(getSizeType(mContext)); + mMenuView.setShapeType(getShapeType(mContext)); + + registerContentObservers(); + } + + @Override + public void hide() { + if (!isShowing()) { + return; + } + + mMenuView.hide(); + + unregisterContentObservers(); + } + + private static boolean isFadeEffectEnabled(Context context) { + return Settings.Secure.getInt( + context.getContentResolver(), ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED, + DEFAULT_FADE_EFFECT_ENABLED) == /* enable */ 1; + } + + private static float getOpacityValue(Context context) { + return Settings.Secure.getFloat( + context.getContentResolver(), ACCESSIBILITY_FLOATING_MENU_OPACITY, + DEFAULT_OPACITY_VALUE); + } + + private static int getSizeType(Context context) { + return Settings.Secure.getInt( + context.getContentResolver(), ACCESSIBILITY_FLOATING_MENU_SIZE, SizeType.SMALL); + } + + private static int getShapeType(Context context) { + return Settings.Secure.getInt( + context.getContentResolver(), ACCESSIBILITY_FLOATING_MENU_ICON_TYPE, + ShapeType.CIRCLE); + } + + private void registerContentObservers() { + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS), + /* notifyForDescendants */ false, mContentObserver, + UserHandle.USER_CURRENT); + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE), + /* notifyForDescendants */ false, mSizeContentObserver, + UserHandle.USER_CURRENT); + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE), + /* notifyForDescendants */ false, mShapeContentObserver, + UserHandle.USER_CURRENT); + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED), + /* notifyForDescendants */ false, mFadeOutContentObserver, + UserHandle.USER_CURRENT); + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY), + /* notifyForDescendants */ false, mFadeOutContentObserver, + UserHandle.USER_CURRENT); + } + + private void unregisterContentObservers() { + mContext.getContentResolver().unregisterContentObserver(mContentObserver); + mContext.getContentResolver().unregisterContentObserver(mSizeContentObserver); + mContext.getContentResolver().unregisterContentObserver(mShapeContentObserver); + mContext.getContentResolver().unregisterContentObserver(mFadeOutContentObserver); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java new file mode 100644 index 000000000000..3aed1d857cd1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java @@ -0,0 +1,430 @@ +/* + * 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.accessibility.floatingmenu; + +import android.animation.ValueAnimator; +import android.annotation.IntDef; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.LayerDrawable; +import android.os.Handler; +import android.os.Looper; +import android.util.DisplayMetrics; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import androidx.annotation.DimenRes; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.android.internal.accessibility.dialog.AccessibilityTarget; +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.R; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; + +/** + * Accessibility floating menu is used for the actions of accessibility features, it's also the + * action set. + * + * <p>The number of items would depend on strings key + * {@link android.provider.Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS}. + */ +public class AccessibilityFloatingMenuView extends FrameLayout + implements RecyclerView.OnItemTouchListener { + private static final float DEFAULT_LOCATION_Y_PERCENTAGE = 0.8f; + private static final int INDEX_MENU_ITEM = 0; + private static final int FADE_OUT_DURATION_MS = 1000; + private static final int FADE_EFFECT_DURATION_MS = 3000; + + private boolean mIsFadeEffectEnabled; + private boolean mIsShowing; + @SizeType + private int mSizeType = SizeType.SMALL; + private int mMargin; + private int mPadding; + private int mScreenHeight; + private int mScreenWidth; + private int mIconWidth; + private int mIconHeight; + private final RecyclerView mListView; + private final AccessibilityTargetAdapter mAdapter; + private float mFadeOutValue; + private final ValueAnimator mFadeOutAnimator; + private final Handler mUiHandler; + private final WindowManager.LayoutParams mLayoutParams; + private final WindowManager mWindowManager; + private final List<AccessibilityTarget> mTargets = new ArrayList<>(); + + @IntDef({ + SizeType.SMALL, + SizeType.LARGE + }) + @Retention(RetentionPolicy.SOURCE) + @interface SizeType { + int SMALL = 0; + int LARGE = 1; + } + + @IntDef({ + ShapeType.CIRCLE, + ShapeType.HALF_CIRCLE + }) + @Retention(RetentionPolicy.SOURCE) + @interface ShapeType { + int CIRCLE = 0; + int HALF_CIRCLE = 1; + } + + public AccessibilityFloatingMenuView(Context context) { + this(context, new RecyclerView(context)); + } + + @VisibleForTesting + AccessibilityFloatingMenuView(Context context, + RecyclerView listView) { + super(context); + + mListView = listView; + mWindowManager = context.getSystemService(WindowManager.class); + mLayoutParams = createDefaultLayoutParams(); + mAdapter = new AccessibilityTargetAdapter(mTargets); + mUiHandler = createUiHandler(); + + mFadeOutAnimator = ValueAnimator.ofFloat(1.0f, mFadeOutValue); + mFadeOutAnimator.setDuration(FADE_OUT_DURATION_MS); + mFadeOutAnimator.addUpdateListener( + (animation) -> setAlpha((float) animation.getAnimatedValue())); + + updateDimensions(); + initListView(); + + final int uiMode = context.getResources().getConfiguration().uiMode; + updateStrokeWith(uiMode); + } + + @Override + public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView, + @NonNull MotionEvent event) { + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + fadeIn(); + break; + case MotionEvent.ACTION_MOVE: + // Do nothing + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + fadeOut(); + break; + default: // Do nothing + } + return false; + } + + @Override + public void onTouchEvent(@NonNull RecyclerView recyclerView, @NonNull MotionEvent motionEvent) { + // Do Nothing + } + + @Override + public void onRequestDisallowInterceptTouchEvent(boolean b) { + // Do Nothing + } + + void show() { + if (isShowing()) { + return; + } + + mIsShowing = true; + mWindowManager.addView(this, mLayoutParams); + } + + void hide() { + if (!isShowing()) { + return; + } + + mIsShowing = false; + mWindowManager.removeView(this); + } + + boolean isShowing() { + return mIsShowing; + } + + void onTargetsChanged(List<AccessibilityTarget> newTargets) { + fadeIn(); + + mTargets.clear(); + mTargets.addAll(newTargets); + mAdapter.notifyDataSetChanged(); + + updateRadiusWith(mSizeType, mTargets.size()); + + fadeOut(); + } + + void setSizeType(@SizeType int newSizeType) { + fadeIn(); + + mSizeType = newSizeType; + + updateIconSizeWith(newSizeType); + updateRadiusWith(newSizeType, mTargets.size()); + + // When the icon sized changed, the menu size and location will be impacted. + updateLocation(); + + fadeOut(); + } + + void setShapeType(@ShapeType int newShapeType) { + fadeIn(); + + final boolean isCircleShape = + newShapeType == ShapeType.CIRCLE; + final float offset = + isCircleShape + ? 0 + : getLayoutWidth() / 2.0f; + mListView.animate().translationX(offset); + + setOnTouchListener( + isCircleShape + ? null + : (view, event) -> onTouched(event)); + + fadeOut(); + } + + void updateOpacityWith(boolean isFadeEffectEnabled, float newOpacityValue) { + mIsFadeEffectEnabled = isFadeEffectEnabled; + mFadeOutValue = newOpacityValue; + + mFadeOutAnimator.cancel(); + mFadeOutAnimator.setFloatValues(1.0f, mFadeOutValue); + setAlpha(mIsFadeEffectEnabled ? mFadeOutValue : /* completely opaque */ 1.0f); + } + + @VisibleForTesting + void fadeIn() { + if (!mIsFadeEffectEnabled) { + return; + } + + mUiHandler.removeCallbacksAndMessages(null); + mUiHandler.post(() -> setAlpha(/* completely opaque */ 1.0f)); + } + + @VisibleForTesting + void fadeOut() { + if (!mIsFadeEffectEnabled) { + return; + } + + mUiHandler.postDelayed(() -> mFadeOutAnimator.start(), FADE_EFFECT_DURATION_MS); + } + + private boolean onTouched(MotionEvent event) { + final int currentX = (int) event.getX(); + final int currentY = (int) event.getY(); + + final int menuHalfWidth = getLayoutWidth() / 2; + final Rect touchDelegateBounds = + new Rect(mMargin, mMargin, mMargin + menuHalfWidth, mMargin + getLayoutHeight()); + if (touchDelegateBounds.contains(currentX, currentY)) { + // In order to correspond to the correct item of list view. + event.setLocation(currentX - mMargin, currentY - mMargin); + return mListView.dispatchTouchEvent(event); + } + + return false; + } + + private void setRadius(float radius) { + final float[] radii = new float[]{radius, radius, 0.0f, 0.0f, 0.0f, 0.0f, radius, radius}; + getMenuGradientDrawable().setCornerRadii(radii); + } + + private Handler createUiHandler() { + final Looper looper = Looper.myLooper(); + if (looper == null) { + throw new IllegalArgumentException("looper must not be null"); + } + return new Handler(looper); + } + + private void updateDimensions() { + final Resources res = getResources(); + final DisplayMetrics dm = res.getDisplayMetrics(); + mScreenWidth = dm.widthPixels; + mScreenHeight = dm.heightPixels; + mMargin = + res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_margin); + mPadding = + res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_padding); + } + + private void updateIconSizeWith(@SizeType int sizeType) { + final Resources res = getResources(); + final int iconResId = + sizeType == SizeType.SMALL + ? R.dimen.accessibility_floating_menu_small_width_height + : R.dimen.accessibility_floating_menu_large_width_height; + mIconWidth = res.getDimensionPixelSize(iconResId); + mIconHeight = mIconWidth; + + mAdapter.setIconWidthHeight(mIconWidth); + mAdapter.notifyDataSetChanged(); + } + + private void initListView() { + final Drawable listViewBackground = + getContext().getDrawable(R.drawable.accessibility_floating_menu_background); + final LinearLayoutManager layoutManager = new LinearLayoutManager(getContext()); + mListView.setBackground(listViewBackground); + mListView.setAdapter(mAdapter); + mListView.setLayoutManager(layoutManager); + mListView.addOnItemTouchListener(this); + updateListView(); + + addView(mListView); + } + + private void updateListView() { + final int elevation = + getResources().getDimensionPixelSize(R.dimen.accessibility_floating_menu_elevation); + final LayoutParams layoutParams = + new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + layoutParams.setMarginsRelative(mMargin, mMargin, /* end= */ 0, mMargin); + mListView.setLayoutParams(layoutParams); + mListView.setElevation(elevation); + } + + private WindowManager.LayoutParams createDefaultLayoutParams() { + final WindowManager.LayoutParams params = new WindowManager.LayoutParams( + WindowManager.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.TRANSLUCENT); + final DisplayMetrics dm = getResources().getDisplayMetrics(); + params.gravity = Gravity.START | Gravity.TOP; + params.x = dm.widthPixels; + params.y = (int) (dm.heightPixels * DEFAULT_LOCATION_Y_PERCENTAGE); + + return params; + } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + updateDimensions(); + updateListView(); + updateIconSizeWith(mSizeType); + updateColor(); + updateStrokeWith(newConfig.uiMode); + updateLocation(); + } + + private LayerDrawable getMenuLayerDrawable() { + return (LayerDrawable) mListView.getBackground(); + } + + private GradientDrawable getMenuGradientDrawable() { + return (GradientDrawable) getMenuLayerDrawable().getDrawable(INDEX_MENU_ITEM); + } + + /** + * Updates the floating menu to be fixed at the side of the screen. + */ + private void updateLocation() { + mLayoutParams.x = mScreenWidth - mMargin - getLayoutWidth(); + mLayoutParams.y = (int) (mScreenHeight * DEFAULT_LOCATION_Y_PERCENTAGE); + mWindowManager.updateViewLayout(this, mLayoutParams); + } + + private void updateColor() { + final int menuColorResId = R.color.accessibility_floating_menu_background; + getMenuGradientDrawable().setColor(getResources().getColor(menuColorResId)); + } + + private void updateStrokeWith(int uiMode) { + final Resources res = getResources(); + final boolean isNightMode = + (uiMode & Configuration.UI_MODE_NIGHT_MASK) + == Configuration.UI_MODE_NIGHT_YES; + + final int inset = + res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_stroke_inset); + final int insetRight = isNightMode ? inset : 0; + getMenuLayerDrawable().setLayerInset(INDEX_MENU_ITEM, 0, 0, insetRight, 0); + + final int width = + res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_stroke_width); + final int strokeWidth = isNightMode ? width : 0; + final int strokeColor = res.getColor(R.color.accessibility_floating_menu_stroke_dark); + getMenuGradientDrawable().setStroke(strokeWidth, strokeColor); + } + + private void updateRadiusWith(@SizeType int sizeType, int itemCount) { + setRadius(getResources().getDimensionPixelSize(getRadiusResId(sizeType, itemCount))); + } + + private @DimenRes int getRadiusResId(@SizeType int sizeType, int itemCount) { + return sizeType == SizeType.SMALL + ? getSmallSizeResIdWith(itemCount) + : getLargeSizeResIdWith(itemCount); + } + + private int getSmallSizeResIdWith(int itemCount) { + return itemCount > 1 + ? R.dimen.accessibility_floating_menu_small_multiple_radius + : R.dimen.accessibility_floating_menu_small_single_radius; + } + + private int getLargeSizeResIdWith(int itemCount) { + return itemCount > 1 + ? R.dimen.accessibility_floating_menu_large_multiple_radius + : R.dimen.accessibility_floating_menu_large_single_radius; + } + + private int getLayoutWidth() { + return mPadding * 2 + mIconWidth; + } + + private int getLayoutHeight() { + return (mPadding + mIconHeight) * mTargets.size() + mPadding; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapter.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapter.java new file mode 100644 index 000000000000..bb4038e92ff4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapter.java @@ -0,0 +1,150 @@ +/* + * 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.accessibility.floatingmenu; + +import static android.view.View.GONE; + +import static com.android.systemui.accessibility.floatingmenu.AccessibilityTargetAdapter.ItemType.FIRST_ITEM; +import static com.android.systemui.accessibility.floatingmenu.AccessibilityTargetAdapter.ItemType.LAST_ITEM; +import static com.android.systemui.accessibility.floatingmenu.AccessibilityTargetAdapter.ItemType.REGULAR_ITEM; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.RecyclerView.Adapter; + +import com.android.internal.accessibility.dialog.AccessibilityTarget; +import com.android.systemui.R; +import com.android.systemui.accessibility.floatingmenu.AccessibilityTargetAdapter.ViewHolder; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; + +/** + * An adapter which shows the set of accessibility targets that can be performed. + */ +public class AccessibilityTargetAdapter extends Adapter<ViewHolder> { + private int mIconWidthHeight; + private final List<AccessibilityTarget> mTargets; + + @IntDef({ + FIRST_ITEM, + REGULAR_ITEM, + LAST_ITEM + }) + @Retention(RetentionPolicy.SOURCE) + @interface ItemType { + int FIRST_ITEM = 0; + int REGULAR_ITEM = 1; + int LAST_ITEM = 2; + } + + public AccessibilityTargetAdapter(List<AccessibilityTarget> targets) { + mTargets = targets; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, @ItemType int itemType) { + final View root = LayoutInflater.from(parent.getContext()).inflate( + R.layout.accessibility_floating_menu_item, parent, + /* attachToRoot= */ false); + + if (itemType == FIRST_ITEM) { + return new TopViewHolder(root); + } + + if (itemType == LAST_ITEM) { + return new BottomViewHolder(root); + } + + return new ViewHolder(root); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + holder.mIconView.setBackground(mTargets.get(position).getIcon()); + holder.updateIconWidthHeight(mIconWidthHeight); + holder.itemView.setOnClickListener((v) -> mTargets.get(position).onSelected()); + } + + @ItemType + @Override + public int getItemViewType(int position) { + if (position == 0) { + return FIRST_ITEM; + } + + if (position == (getItemCount() - 1)) { + return LAST_ITEM; + } + + return REGULAR_ITEM; + } + + @Override + public int getItemCount() { + return mTargets.size(); + } + + public void setIconWidthHeight(int iconWidthHeight) { + mIconWidthHeight = iconWidthHeight; + } + + static class ViewHolder extends RecyclerView.ViewHolder { + final View mIconView; + final View mDivider; + + ViewHolder(View itemView) { + super(itemView); + mIconView = itemView.findViewById(R.id.icon_view); + mDivider = itemView.findViewById(R.id.transparent_divider); + } + + void updateIconWidthHeight(int newValue) { + final ViewGroup.LayoutParams layoutParams = mIconView.getLayoutParams(); + if (layoutParams.width == newValue) { + return; + } + layoutParams.width = newValue; + layoutParams.height = newValue; + mIconView.setLayoutParams(layoutParams); + } + } + + static class TopViewHolder extends ViewHolder { + TopViewHolder(View itemView) { + super(itemView); + final int padding = itemView.getPaddingStart(); + itemView.setPaddingRelative(padding, padding, padding, 0); + } + } + + static class BottomViewHolder extends ViewHolder { + BottomViewHolder(View itemView) { + super(itemView); + mDivider.setVisibility(GONE); + final int padding = itemView.getPaddingStart(); + itemView.setPaddingRelative(padding, 0, padding, padding); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/IAccessibilityFloatingMenu.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/IAccessibilityFloatingMenu.java new file mode 100644 index 000000000000..62f02a044485 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/IAccessibilityFloatingMenu.java @@ -0,0 +1,38 @@ +/* + * 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.accessibility.floatingmenu; + +/** + * Interface for managing the accessibility targets menu component. + */ +public interface IAccessibilityFloatingMenu { + + /** + * Checks if the menu was shown. + */ + boolean isShowing(); + + /** + * Shows the accessibility targets menu. + */ + void show(); + + /** + * Hides the accessibility targets menu. + */ + void hide(); +} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS b/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS new file mode 100644 index 000000000000..9b3e386bc0d8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS @@ -0,0 +1,12 @@ +# Scroll Capture (Long Screenshots) +# Bug component: 801322 +# +# Referenced by: +# +# core/java/src/android/view/OWNERS +# core/java/src/com/android/internal/view/OWNERS +# core/tests/coretests/src/android/view/OWNERS +# core/tests/coretests/src/com/android/internal/view/OWNERS + +mrcasey@google.com +mrenouf@google.com diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java index 3db544011700..d6356de5ea51 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java @@ -242,12 +242,12 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener, int childCount = 0; boolean hasBubbles = false; for (NotificationEntry entry : group.children.values()) { - if (mBubblesOptional.isPresent() && !mBubblesOptional.get() + if (mBubblesOptional.isPresent() && mBubblesOptional.get() .isBubbleNotificationSuppressedFromShade( entry.getKey(), entry.getSbn().getGroupKey())) { - childCount++; - } else { hasBubbles = true; + } else { + childCount++; } } diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java index f19228783b88..f931b89d091e 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java @@ -169,6 +169,11 @@ public class ThemeOverlayController extends SystemUI implements Dumpable { }, UserHandle.USER_ALL); + // All wallpaper color and keyguard logic only applies when Monet is enabled. + if (!mIsMonetEnabled) { + return; + } + // Upon boot, make sure we have the most up to date colors mBgExecutor.execute(() -> { WallpaperColors systemColor = mWallpaperManager.getWallpaperColors( diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java index 4eb75ebe4553..19d8d3cabe3f 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java @@ -268,6 +268,7 @@ public final class WMShell extends SystemUI public void onStop() { mSysUiMainExecutor.execute(() -> { if (oneHanded.isOneHandedEnabled()) { + // Log metrics for 3-button navigation mode. oneHanded.stopOneHanded( OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT); } else if (oneHanded.isSwipeToNotificationEnabled()) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java new file mode 100644 index 000000000000..337d97e1dc0b --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java @@ -0,0 +1,95 @@ +/* + * 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.accessibility.floatingmenu; + +import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +import android.content.Context; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.accessibility.AccessibilityManager; + +import androidx.test.filters.SmallTest; + +import com.android.internal.accessibility.dialog.AccessibilityTarget; +import com.android.systemui.SysuiTestCase; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +/** Tests for {@link AccessibilityFloatingMenu}. */ +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class AccessibilityFloatingMenuTest extends SysuiTestCase { + + @Mock + private AccessibilityManager mAccessibilityManager; + + private AccessibilityFloatingMenuView mMenuView; + private AccessibilityFloatingMenu mMenu; + + @Before + public void initMenu() { + MockitoAnnotations.initMocks(this); + + final List<AccessibilityTarget> mTargets = new ArrayList<>(); + mTargets.add(mock(AccessibilityTarget.class)); + + final List<String> assignedTargets = new ArrayList<>(); + mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager); + assignedTargets.add(MAGNIFICATION_CONTROLLER_NAME); + doReturn(assignedTargets).when(mAccessibilityManager).getAccessibilityShortcutTargets( + anyInt()); + + mMenuView = new AccessibilityFloatingMenuView(mContext); + mMenu = new AccessibilityFloatingMenu(mContext, mMenuView); + } + + @Test + public void showMenuView_success() { + mMenu.show(); + + assertThat(mMenuView.isShowing()).isTrue(); + } + + @Test + public void hideMenuView_success() { + mMenu.show(); + mMenu.hide(); + + assertThat(mMenuView.isShowing()).isFalse(); + } + + @After + public void tearDown() { + mMenu.hide(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java new file mode 100644 index 000000000000..124a749e2be1 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java @@ -0,0 +1,197 @@ +/* + * 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.accessibility.floatingmenu; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +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 android.content.Context; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.LayerDrawable; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.View; +import android.view.ViewPropertyAnimator; +import android.view.WindowManager; + +import androidx.recyclerview.widget.RecyclerView; +import androidx.test.filters.SmallTest; + +import com.android.internal.accessibility.dialog.AccessibilityTarget; +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.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +/** Tests for {@link AccessibilityFloatingMenuView}. */ +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class AccessibilityFloatingMenuViewTest extends SysuiTestCase { + private AccessibilityFloatingMenuView mMenuView; + + @Mock + private WindowManager mWindowManager; + + @Mock + private ViewPropertyAnimator mAnimator; + + private RecyclerView mListView; + + private final List<AccessibilityTarget> mTargets = new ArrayList<>(); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + final WindowManager wm = mContext.getSystemService(WindowManager.class); + doAnswer(invocation -> wm.getMaximumWindowMetrics()).when( + mWindowManager).getMaximumWindowMetrics(); + mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager); + + mTargets.add(mock(AccessibilityTarget.class)); + mListView = spy(new RecyclerView(mContext)); + mMenuView = spy(new AccessibilityFloatingMenuView(mContext)); + } + + @Test + public void initListView_success() { + assertThat(mMenuView.getChildCount()).isEqualTo(1); + } + + @Test + public void showMenuView_success() { + mMenuView.show(); + + assertThat(mMenuView.isShowing()).isTrue(); + verify(mWindowManager).addView(eq(mMenuView), any(WindowManager.LayoutParams.class)); + } + + @Test + public void showMenuView_showTwice_addViewOnce() { + mMenuView.show(); + mMenuView.show(); + + assertThat(mMenuView.isShowing()).isTrue(); + verify(mWindowManager, times(1)).addView(eq(mMenuView), + any(WindowManager.LayoutParams.class)); + } + + @Test + public void hideMenuView_success() { + mMenuView.show(); + mMenuView.hide(); + + assertThat(mMenuView.isShowing()).isFalse(); + verify(mWindowManager).removeView(eq(mMenuView)); + } + + @Test + public void hideMenuView_hideTwice_removeViewOnce() { + mMenuView.show(); + mMenuView.hide(); + mMenuView.hide(); + + assertThat(mMenuView.isShowing()).isFalse(); + verify(mWindowManager, times(1)).removeView(eq(mMenuView)); + } + + @Test + public void updateListViewRadius_singleTarget_matchResult() { + final float radius = + getContext().getResources().getDimensionPixelSize( + R.dimen.accessibility_floating_menu_small_single_radius); + final float[] expectedRadii = + new float[]{radius, radius, 0.0f, 0.0f, 0.0f, 0.0f, radius, radius}; + + mMenuView.onTargetsChanged(mTargets); + final View view = mMenuView.getChildAt(0); + final LayerDrawable layerDrawable = (LayerDrawable) view.getBackground(); + final GradientDrawable gradientDrawable = + (GradientDrawable) layerDrawable.getDrawable(0); + final float[] actualRadii = gradientDrawable.getCornerRadii(); + + assertThat(actualRadii).isEqualTo(expectedRadii); + } + + @Test + public void setSizeType_largeSize_matchResult() { + final int shapeType = 2; + final float radius = getContext().getResources().getDimensionPixelSize( + R.dimen.accessibility_floating_menu_large_single_radius); + final float[] expectedRadii = + new float[]{radius, radius, 0.0f, 0.0f, 0.0f, 0.0f, radius, radius}; + final Drawable listViewBackground = + mContext.getDrawable(R.drawable.accessibility_floating_menu_background); + mListView = spy(new RecyclerView(mContext)); + mListView.setBackground(listViewBackground); + + mMenuView = new AccessibilityFloatingMenuView(mContext, mListView); + mMenuView.setSizeType(shapeType); + final LayerDrawable layerDrawable = + (LayerDrawable) mListView.getBackground(); + final GradientDrawable gradientDrawable = + (GradientDrawable) layerDrawable.getDrawable(0); + + assertThat(gradientDrawable.getCornerRadii()).isEqualTo(expectedRadii); + } + + @Test + public void setShapeType_halfCircle_translationX() { + final int shapeType = 2; + doReturn(mAnimator).when(mListView).animate(); + + mMenuView = new AccessibilityFloatingMenuView(mContext, mListView); + mMenuView.setShapeType(shapeType); + + verify(mAnimator).translationX(anyFloat()); + } + + @Test + public void onTargetsChanged_fadeInOut() { + mMenuView.onTargetsChanged(mTargets); + + verify(mMenuView).fadeIn(); + verify(mMenuView).fadeOut(); + } + + @Test + public void setSizeType_fadeInOut() { + final int smallSize = 0; + mMenuView.setSizeType(smallSize); + + verify(mMenuView).fadeIn(); + verify(mMenuView).fadeOut(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapterTest.java new file mode 100644 index 000000000000..899625eee7d9 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityTargetAdapterTest.java @@ -0,0 +1,85 @@ +/* + * 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.accessibility.floatingmenu; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.graphics.drawable.Drawable; +import android.testing.AndroidTestingRunner; +import android.view.LayoutInflater; +import android.view.View; + +import androidx.test.filters.SmallTest; + +import com.android.internal.accessibility.dialog.AccessibilityTarget; +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.accessibility.floatingmenu.AccessibilityTargetAdapter.ViewHolder; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +/** Tests for {@link AccessibilityTargetAdapter}. */ +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class AccessibilityTargetAdapterTest extends SysuiTestCase { + @Mock + private AccessibilityTarget mAccessibilityTarget; + + @Mock + private Drawable mIcon; + + @Mock + private Drawable.ConstantState mConstantState; + + private ViewHolder mViewHolder; + private AccessibilityTargetAdapter mAdapter; + private final List<AccessibilityTarget> mTargets = new ArrayList<>(); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mTargets.add(mAccessibilityTarget); + mAdapter = new AccessibilityTargetAdapter(mTargets); + + final View root = LayoutInflater.from(mContext).inflate( + R.layout.accessibility_floating_menu_item, null); + mViewHolder = new ViewHolder(root); + when(mAccessibilityTarget.getIcon()).thenReturn(mIcon); + when(mIcon.getConstantState()).thenReturn(mConstantState); + } + + @Test + public void onBindViewHolder_setIconWidthHeight_matchResult() { + final int iconWidthHeight = 50; + mAdapter.setIconWidthHeight(iconWidthHeight); + + mAdapter.onBindViewHolder(mViewHolder, 0); + final int actualIconWith = mViewHolder.mIconView.getLayoutParams().width; + + assertThat(actualIconWith).isEqualTo(iconWidthHeight); + } +} diff --git a/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp b/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp index a18ebb3eaea5..690d0a0ecda3 100644 --- a/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp +++ b/packages/overlays/IconPackVictorThemePickerOverlay/Android.bp @@ -26,6 +26,5 @@ package { runtime_resource_overlay { name: "IconPackVictorThemePickerOverlay", theme: "IconPackVictorThemePicker", - certificate: "platform", product_specific: true, } diff --git a/rs/java/android/renderscript/ScriptIntrinsicBlend.java b/rs/java/android/renderscript/ScriptIntrinsicBlend.java index a1c79ef938c4..3109cd88bd7d 100644 --- a/rs/java/android/renderscript/ScriptIntrinsicBlend.java +++ b/rs/java/android/renderscript/ScriptIntrinsicBlend.java @@ -104,7 +104,7 @@ public class ScriptIntrinsicBlend extends ScriptIntrinsic { * @param opt LaunchOptions for clipping */ public void forEachSrc(Allocation ain, Allocation aout, Script.LaunchOptions opt) { - blend(1, ain, aout, null); + blend(1, ain, aout, opt); } /** @@ -641,4 +641,3 @@ public class ScriptIntrinsicBlend extends ScriptIntrinsic { } */ } - diff --git a/services/api/Android.bp b/services/api/Android.bp index e69de29bb2d1..bbc8c72b2eef 100644 --- a/services/api/Android.bp +++ b/services/api/Android.bp @@ -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 { + default_visibility: ["//visibility:private"], + // 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"], +} + +filegroup { + name: "non-updatable-system-server-current.txt", + srcs: ["non-updatable-current.txt"], + visibility: ["//frameworks/base/api"], +} + +filegroup { + name: "non-updatable-system-server-removed.txt", + srcs: ["non-updatable-removed.txt"], + visibility: ["//frameworks/base/api"], +} diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java index e9a099ae43a9..2c5038940e98 100644 --- a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java +++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java @@ -35,6 +35,7 @@ import android.content.Context; import android.content.pm.ParceledListSlice; import android.os.Binder; import android.os.IBinder; +import android.os.Process; import android.os.ResultReceiver; import android.os.ShellCallback; import android.util.Slog; @@ -179,7 +180,8 @@ public class AppPredictionManagerService extends Context ctx = getContext(); if (!(ctx.checkCallingPermission(PACKAGE_USAGE_STATS) == PERMISSION_GRANTED || mServiceNameResolver.isTemporary(userId) - || mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid()))) { + || mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid()) + || Binder.getCallingUid() == Process.SYSTEM_UID)) { String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid() diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java index 735f420ca03e..cd332a68fa88 100644 --- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java +++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java @@ -40,6 +40,7 @@ import android.util.ArrayMap; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.infra.AbstractRemoteService; import com.android.server.LocalServices; import com.android.server.infra.AbstractPerUserSystemService; @@ -55,6 +56,8 @@ public class AppPredictionPerUserService extends private static final String TAG = AppPredictionPerUserService.class.getSimpleName(); private static final String PREDICT_USING_PEOPLE_SERVICE_PREFIX = "predict_using_people_service_"; + private static final String REMOTE_APP_PREDICTOR_KEY = "remote_app_predictor"; + @Nullable @GuardedBy("mLock") @@ -112,8 +115,16 @@ public class AppPredictionPerUserService extends @GuardedBy("mLock") public void onCreatePredictionSessionLocked(@NonNull AppPredictionContext context, @NonNull AppPredictionSessionId sessionId, @NonNull IBinder token) { - final boolean usesPeopleService = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, + boolean usesPeopleService = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, PREDICT_USING_PEOPLE_SERVICE_PREFIX + context.getUiSurface(), false); + if (context.getExtras() != null + && context.getExtras().getBoolean(REMOTE_APP_PREDICTOR_KEY, false) + && DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.DARK_LAUNCH_REMOTE_PREDICTION_SERVICE_ENABLED, false) + ) { + // connect with remote AppPredictionService instead for dark launch + usesPeopleService = false; + } final boolean serviceExists = resolveService(sessionId, false, usesPeopleService, s -> s.onCreatePredictionSession(context, sessionId)); if (serviceExists && !mSessionInfos.containsKey(sessionId)) { diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 4b5684511757..f07bd2dd79eb 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -133,12 +133,15 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.Function; @@ -171,6 +174,11 @@ public class CompanionDeviceManagerService extends SystemService implements Bind private static final String XML_ATTR_TIME_APPROVED = "time_approved"; private static final String XML_FILE_NAME = "companion_device_manager_associations.xml"; + private static DateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + static { + sDateFormat.setTimeZone(TimeZone.getDefault()); + } + private final CompanionDeviceManagerImpl mImpl; private final ConcurrentMap<Integer, AtomicFile> mUidToStorage = new ConcurrentHashMap<>(); private PowerWhitelistManager mPowerWhitelistManager; @@ -631,12 +639,14 @@ public class CompanionDeviceManagerService extends SystemService implements Bind association.getDeviceMacAddress(), association.getPackageName(), association.getDeviceProfile(), - active, /* notifyOnDeviceNearby */ + active /* notifyOnDeviceNearby */, association.getTimeApprovedMs()); } else { return association; } })); + + restartBleScan(); } private void checkCanCallNotificationApi(String callingPackage) throws RemoteException { @@ -692,12 +702,40 @@ public class CompanionDeviceManagerService extends SystemService implements Bind synchronized (mLock) { for (UserInfo user : getAllUsers()) { forEach(mCachedAssociations.get(user.id), a -> { - fout.append(" ") - .append("u").append("" + a.getUserId()).append(": ") - .append(a.getPackageName()).append(" - ") - .append(a.getDeviceMacAddress()).append('\n'); + fout.append(" ").append(a.toString()).append('\n'); }); } + + } + fout.append("Currently Connected Devices:").append('\n'); + for (int i = 0, size = mCurrentlyConnectedDevices.size(); i < size; i++) { + fout.append(" ").append(mCurrentlyConnectedDevices.get(i)).append('\n'); + } + + fout.append("Devices Last Nearby:").append('\n'); + for (int i = 0, size = mDevicesLastNearby.size(); i < size; i++) { + String device = mDevicesLastNearby.keyAt(i); + Date time = mDevicesLastNearby.valueAt(i); + fout.append(" ").append(device).append(" -> ") + .append(sDateFormat.format(time)).append('\n'); + } + + fout.append("Discovery Service State:").append('\n'); + for (int i = 0, size = mServiceConnectors.size(); i < size; i++) { + int userId = mServiceConnectors.keyAt(i); + fout.append(" ") + .append("u").append(Integer.toString(userId)).append(": ") + .append(Objects.toString(mServiceConnectors.valueAt(i))) + .append('\n'); + } + + fout.append("Device Listener Services State:").append('\n'); + for (int i = 0, size = mDeviceListenerServiceConnectors.size(); i < size; i++) { + int userId = mDeviceListenerServiceConnectors.keyAt(i); + fout.append(" ") + .append("u").append(Integer.toString(userId)).append(": ") + .append(Objects.toString(mDeviceListenerServiceConnectors.valueAt(i))) + .append('\n'); } } } @@ -979,6 +1017,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind } } + private Set<Association> getAllAssociations( int userId, @Nullable String packageFilter, @Nullable String addressFilter) { return CollectionUtils.filter( @@ -1267,7 +1306,8 @@ public class CompanionDeviceManagerService extends SystemService implements Bind if (DEBUG) { Slog.i(LOG_TAG, "Device " + address + " managed by " + association.getPackageName() - + " disappeared; last seen on " + mDevicesLastNearby.get(address)); + + " disappeared; last seen on " + + sDateFormat.format(mDevicesLastNearby.get(address))); } getDeviceListenerServiceConnector(association).run( diff --git a/services/core/Android.bp b/services/core/Android.bp index 8ccfad6fe061..cdffa3bae681 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -81,10 +81,19 @@ genrule { out: ["services.core.protolog.json"], } +genrule { + name: "statslog-art-java-gen", + tools: ["stats-log-api-gen"], + cmd: "$(location stats-log-api-gen) --java $(out) --module art" + + " --javaPackage com.android.internal.art --javaClass ArtStatsLog --worksource", + out: ["com/android/internal/art/ArtStatsLog.java"], +} + java_library_static { name: "services.core.unboosted", defaults: ["platform_service_defaults"], srcs: [ + ":statslog-art-java-gen", ":services.core-sources", ":services.core.protologsrc", ":dumpstate_aidl", @@ -147,7 +156,7 @@ java_library_static { "android.hardware.configstore-V1.0-java", "android.hardware.contexthub-V1.0-java", "android.hardware.rebootescrow-V1-java", - "android.hardware.soundtrigger-V2.3-java", + "android.hardware.soundtrigger-V2.4-java", "android.hardware.power.stats-V1-java", "android.hidl.manager-V1.2-java", "capture_state_listener-aidl-java", diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java index fdda239e7fde..c49b8e8e77c6 100644 --- a/services/core/java/com/android/server/BinderCallsStatsService.java +++ b/services/core/java/com/android/server/BinderCallsStatsService.java @@ -43,6 +43,7 @@ import com.android.internal.os.AppIdToPackageMap; import com.android.internal.os.BackgroundThread; import com.android.internal.os.BinderCallsStats; import com.android.internal.os.BinderInternal; +import com.android.internal.os.BinderLatencyObserver; import com.android.internal.os.CachedDeviceState; import com.android.internal.util.DumpUtils; @@ -124,6 +125,7 @@ public class BinderCallsStatsService extends Binder { /** Listens for flag changes. */ private static class SettingsObserver extends ContentObserver { + // Settings for BinderCallsStats. private static final String SETTINGS_ENABLED_KEY = "enabled"; private static final String SETTINGS_DETAILED_TRACKING_KEY = "detailed_tracking"; private static final String SETTINGS_UPLOAD_DATA_KEY = "upload_data"; @@ -132,6 +134,16 @@ public class BinderCallsStatsService extends Binder { private static final String SETTINGS_TRACK_DIRECT_CALLING_UID_KEY = "track_calling_uid"; private static final String SETTINGS_MAX_CALL_STATS_KEY = "max_call_stats_count"; private static final String SETTINGS_IGNORE_BATTERY_STATUS_KEY = "ignore_battery_status"; + // Settings for BinderLatencyObserver. + private static final String SETTINGS_COLLECT_LATENCY_DATA_KEY = "collect_Latency_data"; + private static final String SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY = + "latency_observer_sampling_interval"; + private static final String SETTINGS_LATENCY_HISTOGRAM_BUCKET_COUNT_KEY = + "latency_histogram_bucket_count"; + private static final String SETTINGS_LATENCY_HISTOGRAM_FIRST_BUCKET_SIZE_KEY = + "latency_histogram_first_bucket_size"; + private static final String SETTINGS_LATENCY_HISTOGRAM_BUCKET_SCALE_FACTOR_KEY = + "latency_histogram_bucket_scale_factor"; private boolean mEnabled; private final Uri mUri = Settings.Global.getUriFor(Settings.Global.BINDER_CALLS_STATS); @@ -188,6 +200,24 @@ public class BinderCallsStatsService extends Binder { mBinderCallsStats.setIgnoreBatteryStatus( mParser.getBoolean(SETTINGS_IGNORE_BATTERY_STATUS_KEY, BinderCallsStats.DEFAULT_IGNORE_BATTERY_STATUS)); + mBinderCallsStats.setCollectLatencyData( + mParser.getBoolean(SETTINGS_COLLECT_LATENCY_DATA_KEY, + BinderCallsStats.DEFAULT_COLLECT_LATENCY_DATA)); + // Binder latency observer settings. + BinderLatencyObserver binderLatencyObserver = mBinderCallsStats.getLatencyObserver(); + binderLatencyObserver.setSamplingInterval(mParser.getInt( + SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY, + BinderLatencyObserver.PERIODIC_SAMPLING_INTERVAL_DEFAULT)); + binderLatencyObserver.setHistogramBucketsParams( + mParser.getInt( + SETTINGS_LATENCY_HISTOGRAM_BUCKET_COUNT_KEY, + BinderLatencyObserver.BUCKET_COUNT_DEFAULT), + mParser.getInt( + SETTINGS_LATENCY_HISTOGRAM_FIRST_BUCKET_SIZE_KEY, + BinderLatencyObserver.FIRST_BUCKET_SIZE_DEFAULT), + mParser.getFloat( + SETTINGS_LATENCY_HISTOGRAM_BUCKET_SCALE_FACTOR_KEY, + BinderLatencyObserver.BUCKET_SCALE_FACTOR_DEFAULT)); final boolean enabled = @@ -206,6 +236,7 @@ public class BinderCallsStatsService extends Binder { mEnabled = enabled; mBinderCallsStats.reset(); mBinderCallsStats.setAddDebugEntries(enabled); + mBinderCallsStats.getLatencyObserver().reset(); } } } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 27b648e53a38..35b730a5e931 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -3375,40 +3375,7 @@ class StorageManagerService extends IStorageManager.Stub } } - @Override - public void notifyAppIoBlocked(String volumeUuid, int uid, int tid, int reason) { - enforceExternalStorageService(); - - mStorageSessionController.notifyAppIoBlocked(volumeUuid, uid, tid, reason); - } - - @Override - public void notifyAppIoResumed(String volumeUuid, int uid, int tid, int reason) { - enforceExternalStorageService(); - - mStorageSessionController.notifyAppIoResumed(volumeUuid, uid, tid, reason); - } - - private boolean isAppIoBlocked(int uid) { - return mStorageSessionController.isAppIoBlocked(uid); - } - - /** - * Enforces that the caller is the {@link ExternalStorageService} - * - * @throws SecurityException if the caller doesn't have the - * {@link android.Manifest.permission.WRITE_MEDIA_STORAGE} permission or is not the - * {@link ExternalStorageService} - */ - private void enforceExternalStorageService() { - enforcePermission(android.Manifest.permission.WRITE_MEDIA_STORAGE); - int callingAppId = UserHandle.getAppId(Binder.getCallingUid()); - if (callingAppId != mMediaStoreAuthorityAppId) { - throw new SecurityException("Only the ExternalStorageService is permitted"); - } - } - - /** + /* * Returns PendingIntent which can be used by Apps with MANAGE_EXTERNAL_STORAGE permission * to launch the manageSpaceActivity of the App specified by packageName. */ @@ -3455,6 +3422,39 @@ class StorageManagerService extends IStorageManager.Stub Binder.restoreCallingIdentity(token); } } + + @Override + public void notifyAppIoBlocked(String volumeUuid, int uid, int tid, int reason) { + enforceExternalStorageService(); + + mStorageSessionController.notifyAppIoBlocked(volumeUuid, uid, tid, reason); + } + + @Override + public void notifyAppIoResumed(String volumeUuid, int uid, int tid, int reason) { + enforceExternalStorageService(); + + mStorageSessionController.notifyAppIoResumed(volumeUuid, uid, tid, reason); + } + + private boolean isAppIoBlocked(int uid) { + return mStorageSessionController.isAppIoBlocked(uid); + } + + /** + * Enforces that the caller is the {@link ExternalStorageService} + * + * @throws SecurityException if the caller doesn't have the + * {@link android.Manifest.permission.WRITE_MEDIA_STORAGE} permission or is not the + * {@link ExternalStorageService} + */ + private void enforceExternalStorageService() { + enforcePermission(android.Manifest.permission.WRITE_MEDIA_STORAGE); + int callingAppId = UserHandle.getAppId(Binder.getCallingUid()); + if (callingAppId != mMediaStoreAuthorityAppId) { + throw new SecurityException("Only the ExternalStorageService is permitted"); + } + } /** Not thread safe */ class AppFuseMountScope extends AppFuseBridge.MountScope { @@ -4553,6 +4553,13 @@ class StorageManagerService extends IStorageManager.Stub private final List<StorageManagerInternal.ResetListener> mResetListeners = new ArrayList<>(); + @Override + public boolean isFuseMounted(int userId) { + synchronized (mLock) { + return mFuseMountedUser.contains(userId); + } + } + /** * Check if fuse is running in target user, if it's running then setup its storage dirs. * Return true if storage dirs are mounted. diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING index 95af84293377..a09dbc7e599d 100644 --- a/services/core/java/com/android/server/TEST_MAPPING +++ b/services/core/java/com/android/server/TEST_MAPPING @@ -21,7 +21,9 @@ } ], "file_patterns": ["NotificationManagerService\\.java"] - }, + } + ], + "presubmit-large": [ { "name": "CtsScopedStorageCoreHostTest", "file_patterns": ["StorageManagerService\\.java"] diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index f768db1d0821..d308ba442f11 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -161,6 +161,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.function.Predicate; @@ -560,6 +561,45 @@ public final class ActiveServices { return smap != null ? smap.mStartingBackground.size() >= mMaxStartingBackground : false; } + boolean hasForegroundServiceNotificationLocked(String pkg, int userId, String channelId) { + final ServiceMap smap = mServiceMap.get(userId); + if (smap != null) { + for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) { + final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i); + if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) { + if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) { + if (DEBUG_FOREGROUND_SERVICE) { + Slog.d(TAG_SERVICE, "Channel u" + userId + "/pkg=" + pkg + + "/channelId=" + channelId + + " has fg service notification"); + } + return true; + } + } + } + } + return false; + } + + void stopForegroundServicesForChannelLocked(String pkg, int userId, String channelId) { + final ServiceMap smap = mServiceMap.get(userId); + if (smap != null) { + for (int i = 0; i < smap.mServicesByInstanceName.size(); i++) { + final ServiceRecord sr = smap.mServicesByInstanceName.valueAt(i); + if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) { + if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) { + if (DEBUG_FOREGROUND_SERVICE) { + Slog.d(TAG_SERVICE, "Stopping FGS u" + userId + "/pkg=" + pkg + + "/channelId=" + channelId + + " for conversation channel clear"); + } + stopServiceLocked(sr, false); + } + } + } + } + } + private ServiceMap getServiceMapLocked(int callingUser) { ServiceMap smap = mServiceMap.get(callingUser); if (smap == null) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 8ea6194a9535..2727f424d7ce 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -15890,6 +15890,22 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public boolean hasForegroundServiceNotification(String pkg, int userId, + String channelId) { + synchronized (ActivityManagerService.this) { + return mServices.hasForegroundServiceNotificationLocked(pkg, userId, channelId); + } + } + + @Override + public void stopForegroundServicesForChannel(String pkg, int userId, + String channelId) { + synchronized (ActivityManagerService.this) { + mServices.stopForegroundServicesForChannelLocked(pkg, userId, channelId); + } + } + + @Override public void registerProcessObserver(IProcessObserver processObserver) { ActivityManagerService.this.registerProcessObserver(processObserver); } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 38330fe770fb..ed8d696f98c4 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -2315,11 +2315,12 @@ public final class ProcessList { StorageManagerInternal storageManagerInternal = LocalServices.getService( StorageManagerInternal.class); if (needsStorageDataIsolation(storageManagerInternal, app)) { - bindMountAppStorageDirs = true; - if (pkgDataInfoMap == null || - !storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(), - app.processName)) { - // Cannot prepare Android/app and Android/obb directory or inode == 0, + // We will run prepareStorageDirs() after we trigger zygote fork, so it won't + // slow down app starting speed as those dirs might not be cached. + if (pkgDataInfoMap != null && storageManagerInternal.isFuseMounted(userId)) { + bindMountAppStorageDirs = true; + } else { + // Fuse is not mounted or inode == 0, // so we won't mount it in zygote, but resume the mount after unlocking device. app.setBindMountPending(true); bindMountAppStorageDirs = false; @@ -2367,6 +2368,13 @@ public final class ProcessList { allowlistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs, new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()}); } + // This runs after Process.start() as this method may block app process starting time + // if dir is not cached. Running this method after Process.start() can make it + // cache the dir asynchronously, so zygote can use it without waiting for it. + if (bindMountAppStorageDirs) { + storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(), + app.processName); + } checkSlow(startTime, "startProcess: returned from zygote!"); return startResult; } finally { diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index e022e977e02f..52ab4c8f7bd6 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -92,6 +92,7 @@ public class SettingsToPropertiesMapper { DeviceConfig.NAMESPACE_STATSD_NATIVE, DeviceConfig.NAMESPACE_STATSD_NATIVE_BOOT, DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, + DeviceConfig.NAMESPACE_SWCODEC_NATIVE, DeviceConfig.NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT, }; diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java index 88b26680631e..aa9bbf680004 100644 --- a/services/core/java/com/android/server/display/color/ColorDisplayService.java +++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java @@ -162,7 +162,8 @@ public final class ColorDisplayService extends SystemService { private final ReduceBrightColorsTintController mReduceBrightColorsTintController = new ReduceBrightColorsTintController(); - private final Handler mHandler; + @VisibleForTesting + final Handler mHandler; private final AppSaturationController mAppSaturationController = new AppSaturationController(); @@ -404,13 +405,13 @@ public final class ColorDisplayService extends SystemService { // existing activated state. This ensures consistency of tint across the color mode change. onDisplayColorModeChanged(getColorModeInternal()); + final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); if (mNightDisplayTintController.isAvailable(getContext())) { // Reset the activated state. mNightDisplayTintController.setActivated(null); // Prepare the night display color transformation matrix. - mNightDisplayTintController - .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix()); + mNightDisplayTintController.setUp(getContext(), dtm.needsLinearColorMatrix()); mNightDisplayTintController .setMatrix(mNightDisplayTintController.getColorTemperatureSetting()); @@ -432,8 +433,7 @@ public final class ColorDisplayService extends SystemService { } if (mReduceBrightColorsTintController.isAvailable(getContext())) { - mReduceBrightColorsTintController - .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix()); + mReduceBrightColorsTintController.setUp(getContext(), dtm.needsLinearColorMatrix()); onReduceBrightColorsStrengthLevelChanged(); final boolean reset = resetReduceBrightColors(); if (!reset) { @@ -540,8 +540,8 @@ public final class ColorDisplayService extends SystemService { mDisplayWhiteBalanceTintController.cancelAnimator(); if (mNightDisplayTintController.isAvailable(getContext())) { - mNightDisplayTintController - .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode)); + final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); + mNightDisplayTintController.setUp(getContext(), dtm.needsLinearColorMatrix(mode)); mNightDisplayTintController .setMatrix(mNightDisplayTintController.getColorTemperatureSetting()); } @@ -731,10 +731,11 @@ public final class ColorDisplayService extends SystemService { @VisibleForTesting void updateDisplayWhiteBalanceStatus() { boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated(); + final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled() && !mNightDisplayTintController.isActivated() && !isAccessibilityEnabled() - && DisplayTransformManager.needsLinearColorMatrix()); + && dtm.needsLinearColorMatrix()); boolean activated = mDisplayWhiteBalanceTintController.isActivated(); if (mDisplayWhiteBalanceListener != null && oldActivated != activated) { diff --git a/services/core/java/com/android/server/display/color/DisplayTransformManager.java b/services/core/java/com/android/server/display/color/DisplayTransformManager.java index 5c68c51ad7a3..0dba9e1b0af1 100644 --- a/services/core/java/com/android/server/display/color/DisplayTransformManager.java +++ b/services/core/java/com/android/server/display/color/DisplayTransformManager.java @@ -239,7 +239,7 @@ public class DisplayTransformManager { /** * Return true when the color matrix works in linear space. */ - public static boolean needsLinearColorMatrix() { + public boolean needsLinearColorMatrix() { return SystemProperties.getInt(PERSISTENT_PROPERTY_DISPLAY_COLOR, DISPLAY_COLOR_UNMANAGED) != DISPLAY_COLOR_UNMANAGED; } @@ -247,7 +247,7 @@ public class DisplayTransformManager { /** * Return true when the specified colorMode requires the color matrix to work in linear space. */ - public static boolean needsLinearColorMatrix(int colorMode) { + public boolean needsLinearColorMatrix(int colorMode) { return colorMode != ColorDisplayManager.COLOR_MODE_SATURATED; } diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java index 8405bbe38b12..d422d51d4087 100644 --- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java +++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java @@ -88,7 +88,7 @@ final class ActiveSourceHandler { tv.updateActiveSource(current, "ActiveSourceHandler"); invokeCallback(HdmiControlManager.RESULT_SUCCESS); } else { - tv.startRoutingControl(newActive.physicalAddress, current.physicalAddress, true, + tv.startRoutingControl(newActive.physicalAddress, current.physicalAddress, mCallback); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 7235a921254d..917d34072ab0 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -370,12 +370,11 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { return; } int newPath = mService.portIdToPath(portId); - startRoutingControl(oldPath, newPath, true, callback); + startRoutingControl(oldPath, newPath, callback); } @ServiceThreadOnly - void startRoutingControl(int oldPath, int newPath, boolean queryDevicePowerStatus, - IHdmiControlCallback callback) { + void startRoutingControl(int oldPath, int newPath, IHdmiControlCallback callback) { assertRunOnServiceThread(); if (oldPath == newPath) { return; @@ -385,7 +384,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { mService.sendCecCommand(routingChange); removeAction(RoutingControlAction.class); addAndStartAction( - new RoutingControlAction(this, newPath, queryDevicePowerStatus, callback)); + new RoutingControlAction(this, newPath, callback)); } @ServiceThreadOnly @@ -554,7 +553,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { if (isTailOfActivePath(path, getActivePath())) { int newPath = mService.portIdToPath(getActivePortId()); setActivePath(newPath); - startRoutingControl(getActivePath(), newPath, false, null); + startRoutingControl(getActivePath(), newPath, null); return true; } return false; @@ -598,7 +597,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { getActiveSource().invalidate(); removeAction(RoutingControlAction.class); int newPath = HdmiUtils.twoBytesToInt(params, 2); - addAndStartAction(new RoutingControlAction(this, newPath, true, null)); + addAndStartAction(new RoutingControlAction(this, newPath, null)); } return true; } @@ -1168,7 +1167,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // Seq #23 if (isTailOfActivePath(path, getActivePath())) { int newPath = mService.portIdToPath(getActivePortId()); - startRoutingControl(getActivePath(), newPath, true, null); + startRoutingControl(getActivePath(), newPath, null); } } @@ -1186,7 +1185,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { if (!routingForBootup && !isProhibitMode()) { int newPath = mService.portIdToPath(getActivePortId()); setActivePath(newPath); - startRoutingControl(getActivePath(), newPath, routingForBootup, null); + startRoutingControl(getActivePath(), newPath, null); } } else { int activePath = mService.getPhysicalAddress(); diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 115cafedca93..0e8719c46525 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -2307,6 +2307,7 @@ public class HdmiControlService extends SystemService { @Override public void setCecSettingStringValue(String name, String value) { + Slog.i(TAG, "Setting '" + name + "' to '" + value + "'."); initBinderCall(); long token = Binder.clearCallingIdentity(); try { @@ -2329,6 +2330,7 @@ public class HdmiControlService extends SystemService { @Override public void setCecSettingIntValue(String name, int value) { + Slog.i(TAG, "Setting '" + name + "' to '" + value + "'."); initBinderCall(); long token = Binder.clearCallingIdentity(); try { @@ -3493,6 +3495,7 @@ public class HdmiControlService extends SystemService { new HdmiCecConfig.SettingChangeListener() { @Override public void onChange(String name) { + Slog.i(TAG, "Change listener fired for '" + name + "' setting."); synchronized (mLock) { if (!mHdmiCecSettingChangeListenerRecords.containsKey(name)) { return; @@ -3512,6 +3515,7 @@ public class HdmiControlService extends SystemService { mHdmiCecConfig.registerChangeListener(name, mSettingChangeListener); } mHdmiCecSettingChangeListenerRecords.get(name).register(listener); + Slog.i(TAG, "Added change listener for '" + name + "' setting."); } } @@ -3525,12 +3529,14 @@ public class HdmiControlService extends SystemService { if (mHdmiCecSettingChangeListenerRecords.get(name).getRegisteredCallbackCount() == 0) { mHdmiCecSettingChangeListenerRecords.remove(name); mHdmiCecConfig.removeChangeListener(name, mSettingChangeListener); + Slog.i(TAG, "Removed change listener for '" + name + "' setting."); } } } private void invokeCecSettingChangeListenerLocked(String name, final IHdmiCecSettingChangeListener listener) { + Slog.i(TAG, "Listener.onChange() invoked for '" + name + "' setting."); try { listener.onChange(name); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java index b9404e407b88..0c4fb26ce3b1 100644 --- a/services/core/java/com/android/server/hdmi/RoutingControlAction.java +++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java @@ -17,11 +17,10 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiControlManager; -import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.IHdmiControlCallback; import android.util.Slog; -import com.android.server.hdmi.HdmiControlService.SendMessageCallback; +import com.android.internal.annotations.VisibleForTesting; /** * Feature action for routing control. Exchanges routing-related commands with other devices @@ -41,23 +40,12 @@ final class RoutingControlAction extends HdmiCecFeatureAction { // State in which we wait for <Routing Information> to arrive. If timed out, we use the // latest routing path to set the new active source. - private static final int STATE_WAIT_FOR_ROUTING_INFORMATION = 1; - - // State in which we wait for <Report Power Status> in response to <Give Device Power Status> - // we have sent. If the response tells us the device power is on, we send <Set Stream Path> - // to make it the active source. Otherwise we do not send <Set Stream Path>, and possibly - // just show the blank screen. - private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 2; + @VisibleForTesting + static final int STATE_WAIT_FOR_ROUTING_INFORMATION = 1; // Time out in millseconds used for <Routing Information> private static final int TIMEOUT_ROUTING_INFORMATION_MS = 1000; - // Time out in milliseconds used for <Report Power Status> - private static final int TIMEOUT_REPORT_POWER_STATUS_MS = 1000; - - // true if <Give Power Status> should be sent once the new active routing path is determined. - private final boolean mQueryDevicePowerStatus; - // If set to true, call {@link HdmiControlService#invokeInputChangeListener()} when // the routing control/active source change happens. The listener should be called if // the events are triggered by external events such as manual switch port change or incoming @@ -67,11 +55,9 @@ final class RoutingControlAction extends HdmiCecFeatureAction { // The latest routing path. Updated by each <Routing Information> from CEC switches. private int mCurrentRoutingPath; - RoutingControlAction(HdmiCecLocalDevice localDevice, int path, boolean queryDevicePowerStatus, - IHdmiControlCallback callback) { + RoutingControlAction(HdmiCecLocalDevice localDevice, int path, IHdmiControlCallback callback) { super(localDevice, callback); mCurrentRoutingPath = path; - mQueryDevicePowerStatus = queryDevicePowerStatus; // Callback is non-null when routing control action is brought up by binder API. Use // this as an indicator for the input change notification. These API calls will get // the result through this callback, not through notification. Any other events that @@ -104,39 +90,16 @@ final class RoutingControlAction extends HdmiCecFeatureAction { removeActionExcept(RoutingControlAction.class, this); addTimer(mState, TIMEOUT_ROUTING_INFORMATION_MS); return true; - } else if (mState == STATE_WAIT_FOR_REPORT_POWER_STATUS - && opcode == Constants.MESSAGE_REPORT_POWER_STATUS) { - handleReportPowerStatus(cmd.getParams()[0]); - return true; } return false; } - private void handleReportPowerStatus(int devicePowerStatus) { - if (isPowerOnOrTransient(getTvPowerStatus())) { - updateActiveInput(); - if (isPowerOnOrTransient(devicePowerStatus)) { - sendSetStreamPath(); - } - } - finishWithCallback(HdmiControlManager.RESULT_SUCCESS); - } - private void updateActiveInput() { HdmiCecLocalDeviceTv tv = tv(); tv.setPrevPortId(tv.getActivePortId()); tv.updateActiveInput(mCurrentRoutingPath, mNotifyInputChange); } - private int getTvPowerStatus() { - return tv().getPowerStatus(); - } - - private static boolean isPowerOnOrTransient(int status) { - return status == HdmiControlManager.POWER_STATUS_ON - || status == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; - } - private void sendSetStreamPath() { sendCommand(HdmiCecMessageBuilder.buildSetStreamPath(getSourceAddress(), mCurrentRoutingPath)); @@ -150,46 +113,13 @@ final class RoutingControlAction extends HdmiCecFeatureAction { } switch (timeoutState) { case STATE_WAIT_FOR_ROUTING_INFORMATION: - HdmiDeviceInfo device = - localDevice().mService.getHdmiCecNetwork().getDeviceInfoByPath( - mCurrentRoutingPath); - if (device != null && mQueryDevicePowerStatus) { - int deviceLogicalAddress = device.getLogicalAddress(); - queryDevicePowerStatus(deviceLogicalAddress, new SendMessageCallback() { - @Override - public void onSendCompleted(int error) { - handlDevicePowerStatusAckResult( - error == HdmiControlManager.RESULT_SUCCESS); - } - }); - } else { - updateActiveInput(); - finishWithCallback(HdmiControlManager.RESULT_SUCCESS); - } - return; - case STATE_WAIT_FOR_REPORT_POWER_STATUS: - if (isPowerOnOrTransient(getTvPowerStatus())) { - updateActiveInput(); - sendSetStreamPath(); - } + updateActiveInput(); + sendSetStreamPath(); finishWithCallback(HdmiControlManager.RESULT_SUCCESS); return; - } - } - - private void queryDevicePowerStatus(int address, SendMessageCallback callback) { - sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), address), - callback); - } - - private void handlDevicePowerStatusAckResult(boolean acked) { - if (acked) { - mState = STATE_WAIT_FOR_REPORT_POWER_STATUS; - addTimer(mState, TIMEOUT_REPORT_POWER_STATUS_MS); - } else { - updateActiveInput(); - sendSetStreamPath(); - finishWithCallback(HdmiControlManager.RESULT_SUCCESS); + default: + Slog.e("CEC", "Invalid timeoutState (" + timeoutState + ")."); + return; } } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 0cc9f9e150c6..43bbc06a65b2 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2165,14 +2165,16 @@ public class NotificationManagerService extends SystemService { mUserProfiles.updateCache(getContext()); - telephonyManager.listen(new PhoneStateListener() { - @Override - public void onCallStateChanged(int state, String incomingNumber) { - if (mCallState == state) return; - if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state)); - mCallState = state; - } - }, PhoneStateListener.LISTEN_CALL_STATE); + if (mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { + telephonyManager.listen(new PhoneStateListener() { + @Override + public void onCallStateChanged(int state, String incomingNumber) { + if (mCallState == state) return; + if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state)); + mCallState = state; + } + }, PhoneStateListener.LISTEN_CALL_STATE); + } mSettingsObserver = new SettingsObserver(mHandler); @@ -3576,15 +3578,30 @@ public class NotificationManagerService extends SystemService { pkg, uid, channelId, conversationId, true, includeDeleted); } + // Returns 'true' if the given channel has a notification associated + // with an active foreground service. + private void enforceDeletingChannelHasNoFgService(String pkg, int userId, + String channelId) { + if (mAmi.hasForegroundServiceNotification(pkg, userId, channelId)) { + Slog.w(TAG, "Package u" + userId + "/" + pkg + + " may not delete notification channel '" + + channelId + "' with fg service"); + throw new SecurityException("Not allowed to delete channel " + channelId + + " with a foreground service"); + } + } + @Override public void deleteNotificationChannel(String pkg, String channelId) { checkCallerIsSystemOrSameApp(pkg); final int callingUid = Binder.getCallingUid(); + final int callingUser = UserHandle.getUserId(callingUid); if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { throw new IllegalArgumentException("Cannot delete default channel"); } + enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId); cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true, - UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null); + callingUser, REASON_CHANNEL_BANNED, null); mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId); mListeners.notifyNotificationChannelChanged(pkg, UserHandle.getUserHandleForUid(callingUid), @@ -3597,19 +3614,23 @@ public class NotificationManagerService extends SystemService { public void deleteConversationNotificationChannels(String pkg, int uid, String conversationId) { checkCallerIsSystem(); - final int callingUid = Binder.getCallingUid(); List<NotificationChannel> channels = mPreferencesHelper.getNotificationChannelsByConversationId( pkg, uid, conversationId); if (!channels.isEmpty()) { + // Preflight for fg service notifications in these channels: do nothing + // unless they're all eligible + final int appUserId = UserHandle.getUserId(uid); for (NotificationChannel nc : channels) { + final String channelId = nc.getId(); + mAmi.stopForegroundServicesForChannel(pkg, appUserId, channelId); cancelAllNotificationsInt(MY_UID, MY_PID, pkg, nc.getId(), 0, 0, true, - UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null); - mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, nc.getId()); + appUserId, REASON_CHANNEL_BANNED, null); + mPreferencesHelper.deleteNotificationChannel(pkg, uid, channelId); mListeners.notifyNotificationChannelChanged(pkg, - UserHandle.getUserHandleForUid(callingUid), + UserHandle.getUserHandleForUid(uid), mPreferencesHelper.getNotificationChannel( - pkg, callingUid, nc.getId(), true), + pkg, uid, channelId, true), NOTIFICATION_CHANNEL_OR_GROUP_DELETED); } handleSavePolicyFile(); @@ -3640,13 +3661,20 @@ public class NotificationManagerService extends SystemService { NotificationChannelGroup groupToDelete = mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, callingUid); if (groupToDelete != null) { + // Preflight for allowability + final int userId = UserHandle.getUserId(callingUid); + List<NotificationChannel> groupChannels = groupToDelete.getChannels(); + for (int i = 0; i < groupChannels.size(); i++) { + enforceDeletingChannelHasNoFgService(pkg, userId, + groupChannels.get(i).getId()); + } List<NotificationChannel> deletedChannels = mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId); for (int i = 0; i < deletedChannels.size(); i++) { final NotificationChannel deletedChannel = deletedChannels.get(i); cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0, true, - UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, + userId, REASON_CHANNEL_BANNED, null); mListeners.notifyNotificationChannelChanged(pkg, UserHandle.getUserHandleForUid(callingUid), diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 0a443f3fd7f9..7aaab0c4d40b 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -51,6 +51,7 @@ import android.os.FileUtils; import android.os.PowerManager; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.Trace; import android.os.UserHandle; import android.os.WorkSource; import android.os.storage.StorageManager; @@ -62,6 +63,8 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.dex.ArtManagerService; +import com.android.server.pm.dex.ArtStatsLogUtils; +import com.android.server.pm.dex.ArtStatsLogUtils.ArtStatsLogger; import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.DexoptOptions; import com.android.server.pm.dex.DexoptUtils; @@ -99,6 +102,8 @@ public class PackageDexOptimizer { private final PowerManager.WakeLock mDexoptWakeLock; private volatile boolean mSystemReady; + private final ArtStatsLogger mArtStatsLogger = new ArtStatsLogger(); + PackageDexOptimizer(Installer installer, Object installLock, Context context, String wakeLockTag) { this.mInstaller = installer; @@ -252,6 +257,28 @@ public class PackageDexOptimizer { profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid, packageStats, options.isDowngrade(), profileName, dexMetadataPath, options.getCompilationReason()); + + // Only report metrics for base apk for now. + // TODO: add ISA and APK type to metrics. + if (pkg.getBaseApkPath().equals(path)) { + Trace.traceBegin(Trace.TRACE_TAG_PACKAGE_MANAGER, "dex2oat-metrics"); + try { + long sessionId = Math.randomLongInternal(); + ArtStatsLogUtils.writeStatsLog( + mArtStatsLogger, + sessionId, + path, + compilerFilter, + sharedGid, + packageStats.getCompileTime(path), + dexMetadataPath, + options.getCompilationReason(), + newResult); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_PACKAGE_MANAGER); + } + } + // The end result is: // - FAILED if any path failed, // - PERFORMED if at least one path needed compilation, diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index ec7b451c6ec9..b596deafd2b2 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -2910,6 +2910,17 @@ public final class Settings implements Watchable, Snappable { mReadMessages.append("Error reading: " + e.toString()); PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); Slog.wtf(PackageManagerService.TAG, "Error reading package manager settings", e); + } finally { + if (!mVersion.containsKey(StorageManager.UUID_PRIVATE_INTERNAL)) { + Slog.wtf(PackageManagerService.TAG, + "No internal VersionInfo found in settings, using current."); + findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent(); + } + if (!mVersion.containsKey(StorageManager.UUID_PRIMARY_PHYSICAL)) { + Slog.wtf(PackageManagerService.TAG, + "No external VersionInfo found in settings, using current."); + findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent(); + } } // If the build is setup to drop runtime permissions diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java new file mode 100644 index 000000000000..3b77c39cc31b --- /dev/null +++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java @@ -0,0 +1,258 @@ +/* + * 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.dex; + +import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED; +import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY; +import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED; +import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK; +import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK; + +import android.util.jar.StrictJarFile; +import android.util.Slog; + +import com.android.internal.art.ArtStatsLog; +import com.android.server.pm.PackageManagerService; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.zip.ZipEntry; + +/** Utils class to report ART metrics to statsd. */ +public class ArtStatsLogUtils { + private static final String TAG = ArtStatsLogUtils.class.getSimpleName(); + private static final String PROFILE_DEX_METADATA = "primary.prof"; + private static final String VDEX_DEX_METADATA = "primary.vdex"; + + + private static final int ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY = + ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY; + private static final int ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED = + ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED; + private static final int ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED = + ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED; + + private static final int ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK = + ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK; + private static final int ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK = + ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK; + + private static final Map<Integer, Integer> COMPILATION_REASON_MAP = new HashMap(); + + static { + COMPILATION_REASON_MAP.put(PackageManagerService.REASON_UNKNOWN, ArtStatsLog. + ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_UNKNOWN); + COMPILATION_REASON_MAP.put(PackageManagerService.REASON_FIRST_BOOT, ArtStatsLog. + ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_FIRST_BOOT); + COMPILATION_REASON_MAP.put(PackageManagerService.REASON_BOOT_AFTER_OTA, ArtStatsLog. + ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_BOOT); + COMPILATION_REASON_MAP.put(PackageManagerService.REASON_POST_BOOT, ArtStatsLog. + ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_POST_BOOT); + COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL, ArtStatsLog. + ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL); + COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_FAST, ArtStatsLog. + ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_FAST); + COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK, ArtStatsLog. + ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INSTALL_BULK); + COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_SECONDARY, + ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY); + COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_DOWNGRADED, + ART_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED); + COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED, + ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED); + COMPILATION_REASON_MAP.put(PackageManagerService.REASON_BACKGROUND_DEXOPT, ArtStatsLog. + ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_BG_DEXOPT); + COMPILATION_REASON_MAP.put(PackageManagerService.REASON_AB_OTA, ArtStatsLog. + ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_AB_OTA); + COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE, + ArtStatsLog. + ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INACTIVE); + COMPILATION_REASON_MAP.put(PackageManagerService.REASON_SHARED, + ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_SHARED); + } + + private static final Map<String, Integer> COMPILE_FILTER_MAP = new HashMap(); + + static { + COMPILE_FILTER_MAP.put("error", ArtStatsLog. + ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_ERROR); + COMPILE_FILTER_MAP.put("unknown", ArtStatsLog. + ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_UNKNOWN); + COMPILE_FILTER_MAP.put("assume-verified", ArtStatsLog. + ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_ASSUMED_VERIFIED); + COMPILE_FILTER_MAP.put("extract", ArtStatsLog. + ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EXTRACT); + COMPILE_FILTER_MAP.put("verify", ArtStatsLog. + ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_VERIFY); + COMPILE_FILTER_MAP.put("quicken", ArtStatsLog. + ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_QUICKEN); + COMPILE_FILTER_MAP.put("space-profile", ArtStatsLog. + ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPACE_PROFILE); + COMPILE_FILTER_MAP.put("space", ArtStatsLog. + ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPACE); + COMPILE_FILTER_MAP.put("speed-profile", ArtStatsLog. + ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPEED_PROFILE); + COMPILE_FILTER_MAP.put("speed", ArtStatsLog. + ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_SPEED); + COMPILE_FILTER_MAP.put("everything-profile", ArtStatsLog. + ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EVERYTHING_PROFILE); + COMPILE_FILTER_MAP.put("everything", ArtStatsLog. + ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_EVERYTHING); + COMPILE_FILTER_MAP.put("run-from-apk", ArtStatsLog. + ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK); + COMPILE_FILTER_MAP.put("run-from-apk-fallback", + ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK); + COMPILE_FILTER_MAP.put("run-from-vdex-fallback", + ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK); + } + + public static void writeStatsLog( + ArtStatsLogger logger, + long sessionId, + String path, + String compilerFilter, + int uid, + long compileTime, + String dexMetadataPath, + int compilationReason, + int result) { + int dexMetadataType = getDexMetadataType(dexMetadataPath); + logger.write( + sessionId, + uid, + compilationReason, + compilerFilter, + ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_RESULT_CODE, + result, + dexMetadataType); + logger.write( + sessionId, + uid, + compilationReason, + compilerFilter, + ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES, + getDexBytes(path), + dexMetadataType); + logger.write( + sessionId, + uid, + compilationReason, + compilerFilter, + ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME, + compileTime, + dexMetadataType); + } + + private static long getDexBytes(String apkPath) { + StrictJarFile jarFile = null; + long dexBytes = 0; + try { + jarFile = new StrictJarFile(apkPath, + /*verify=*/ false, + /*signatureSchemeRollbackProtectionsEnforced=*/ false); + Iterator<ZipEntry> it = jarFile.iterator(); + while (it.hasNext()) { + ZipEntry entry = it.next(); + if (entry.getName().matches("classes(\\d)*[.]dex")) { + dexBytes += entry.getSize(); + } + } + return dexBytes; + } catch (IOException ignore) { + Slog.e(TAG, "Error when parsing APK " + apkPath); + return -1L; + } finally { + try { + if (jarFile != null) { + jarFile.close(); + } + } catch (IOException ignore) { + } + } + } + + private static int getDexMetadataType(String dexMetadataPath) { + if (dexMetadataPath == null) { + return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__NONE_DEX_METADATA; + } + StrictJarFile jarFile = null; + try { + jarFile = new StrictJarFile(dexMetadataPath, + /*verify=*/ false, + /*signatureSchemeRollbackProtectionsEnforced=*/false); + boolean hasProfile = findFileName(jarFile, PROFILE_DEX_METADATA); + boolean hasVdex = findFileName(jarFile, VDEX_DEX_METADATA); + if (hasProfile && hasVdex) { + return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__PROFILE_AND_VDEX; + } else if (hasProfile) { + return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__PROFILE; + } else if (hasVdex) { + return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__VDEX; + } else { + return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__UNKNOWN_DEX_METADATA; + } + } catch (IOException ignore) { + Slog.e(TAG, "Error when parsing dex metadata " + dexMetadataPath); + return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__ERROR_DEX_METADATA; + } finally { + try { + if (jarFile != null) { + jarFile.close(); + } + } catch (IOException ignore) { + } + } + } + + private static boolean findFileName(StrictJarFile jarFile, String filename) throws IOException { + Iterator<ZipEntry> it = jarFile.iterator(); + while (it.hasNext()) { + ZipEntry entry = it.next(); + if (entry.getName().equals(filename)) { + return true; + } + } + return false; + } + + public static class ArtStatsLogger { + public void write( + long sessionId, + int uid, + int compilationReason, + String compilerFilter, + int kind, + long value, + int dexMetadataType) { + ArtStatsLog.write( + ArtStatsLog.ART_DATUM_REPORTED, + sessionId, + uid, + COMPILE_FILTER_MAP.getOrDefault(compilerFilter, ArtStatsLog. + ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_UNKNOWN), + COMPILATION_REASON_MAP.getOrDefault(compilationReason, ArtStatsLog. + ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_UNKNOWN), + /*timestamp_millis=*/ 0L, + ArtStatsLog.ART_DATUM_REPORTED__THREAD_TYPE__ART_THREAD_MAIN, + kind, + value, + dexMetadataType); + } + } +} diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java b/services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java index 940490411b49..d195fbedcf2f 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java @@ -16,42 +16,55 @@ package com.android.server.soundtrigger_middleware; +import android.annotation.NonNull; import android.util.Log; +import java.util.LinkedList; +import java.util.List; import java.util.concurrent.Semaphore; -import java.util.function.Consumer; /** * This is a never-give-up listener for sound trigger external capture state notifications, as * published by the audio policy service. * * This class will constantly try to connect to the service over a background thread and tolerate - * its death. The client will be notified by a single provided function that is called in a - * synchronized manner. - * For simplicity, there is currently no way to stop the tracker. This is possible to add if the - * need ever arises. + * its death. */ -class ExternalCaptureStateTracker { +class ExternalCaptureStateTracker implements ICaptureStateNotifier { private static final String TAG = "CaptureStateTracker"; - /** Our client's listener. */ - private final Consumer<Boolean> mListener; + + /** Our client's listeners. Also used as lock. */ + private final List<Listener> mListeners = new LinkedList<>(); + + /** Conservatively, until notified otherwise, we assume capture is active. */ + private boolean mCaptureActive = true; + /** This semaphore will get a permit every time we need to reconnect. */ private final Semaphore mNeedToConnect = new Semaphore(1); /** * Constructor. Will start a background thread to do the work. - * - * @param listener A client provided listener that will be called on state - * changes. May be - * called multiple consecutive times with the same value. Never - * called - * concurrently. */ - ExternalCaptureStateTracker(Consumer<Boolean> listener) { - mListener = listener; + ExternalCaptureStateTracker() { new Thread(this::run).start(); } + + @Override + public boolean registerListener(@NonNull Listener listener) { + synchronized (mListeners) { + mListeners.add(listener); + return mCaptureActive; + } + } + + @Override + public void unregisterListener(Listener listener) { + synchronized (mListeners) { + mListeners.remove(listener); + } + } + /** * Routine for the background thread. Keeps trying to reconnect. */ @@ -74,7 +87,12 @@ class ExternalCaptureStateTracker { */ private void setCaptureState(boolean active) { try { - mListener.accept(active); + synchronized (mListeners) { + mCaptureActive = active; + for (Listener listener : mListeners) { + listener.onCaptureStateChange(active); + } + } } catch (Exception e) { Log.e(TAG, "Exception caught while setting capture state", e); } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/HalFactory.java b/services/core/java/com/android/server/soundtrigger_middleware/HalFactory.java index b19e2ed1a91b..fce75d0e92bc 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/HalFactory.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/HalFactory.java @@ -16,16 +16,14 @@ package com.android.server.soundtrigger_middleware; -import android.hardware.soundtrigger.V2_0.ISoundTriggerHw; - /** - * A factory for creating instances of {@link ISoundTriggerHw}. + * A factory for creating instances of {@link ISoundTriggerHw2}. * * @hide */ public interface HalFactory { /** - * @return An instance of {@link ISoundTriggerHw}. + * @return An instance of {@link ISoundTriggerHw2}. */ - ISoundTriggerHw create(); + ISoundTriggerHw2 create(); } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ICaptureStateNotifier.java b/services/core/java/com/android/server/soundtrigger_middleware/ICaptureStateNotifier.java new file mode 100644 index 000000000000..07d83cabcf83 --- /dev/null +++ b/services/core/java/com/android/server/soundtrigger_middleware/ICaptureStateNotifier.java @@ -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.server.soundtrigger_middleware; + +import android.annotation.NonNull; + +/** + * Allow registering listeners for tracking changes in audio capture state (when recording starts / + * stops). The client will be notified in a synchronized manner. + */ +interface ICaptureStateNotifier { + interface Listener { + void onCaptureStateChange(boolean state); + } + + /** + * Register a listener for state change notifications. Returns the current capture state and + * any subsequent changes will be sent to the listener. + * @param listener The listener. + * @return The state at the time of registration. + */ + boolean registerListener(@NonNull Listener listener); + + /** + * Unregister a listener, previously registered with {@link #registerListener(Listener)}. + * Once this call returns, no more invocations of the listener will be made. + */ + void unregisterListener(@NonNull Listener listener); +} diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerHw2.java b/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerHw2.java index 8b434bd84363..d04e31489662 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerHw2.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerHw2.java @@ -17,12 +17,16 @@ package com.android.server.soundtrigger_middleware; import android.hardware.soundtrigger.V2_3.ModelParameterRange; +import android.hardware.soundtrigger.V2_3.Properties; +import android.hardware.soundtrigger.V2_3.RecognitionConfig; +import android.hardware.soundtrigger.V2_4.ISoundTriggerHw; +import android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback; +import android.hardware.soundtrigger.V2_4.ISoundTriggerHwGlobalCallback; import android.hidl.base.V1_0.IBase; import android.os.IHwBinder; /** - * This interface mimics android.hardware.soundtrigger.V2_x.ISoundTriggerHw and - * android.hardware.soundtrigger.V2_x.ISoundTriggerHwCallback, with a few key differences: + * This interface mimics ISoundTriggerHw and ISoundTriggerHwCallback, with a few key differences: * <ul> * <li>Methods in the original interface generally have a status return value and potentially a * second return value which is the actual return value. This is reflected via a synchronous @@ -51,74 +55,78 @@ import android.os.IHwBinder; * so that clients have access to the entire functionality without having to burden themselves with * compatibility, as much as possible. */ -public interface ISoundTriggerHw2 { +interface ISoundTriggerHw2 { /** - * @see android.hardware.soundtrigger.V2_3.ISoundTriggerHw#getPropertiesEx( - * android.hardware.soundtrigger.V2_3.ISoundTriggerHw.getPropertiesExCallback) + * Kill and restart the HAL instance. This is typically a last resort for error recovery and may + * result in other related services being killed. */ - android.hardware.soundtrigger.V2_3.Properties getProperties(); + void reboot(); /** - * @see android.hardware.soundtrigger.V2_2.ISoundTriggerHw#loadSoundModel_2_1(android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel, - * android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback, int, - * android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadSoundModel_2_1Callback) + * Called when this interface is guaranteed to no longer be used and can free up any resources + * used. */ - int loadSoundModel( - android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel soundModel, - SoundTriggerHw2Compat.Callback callback, int cookie); + void detach(); /** - * @see android.hardware.soundtrigger.V2_2.ISoundTriggerHw#loadPhraseSoundModel_2_1(android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel, - * android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback, int, - * android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadPhraseSoundModel_2_1Callback) + * @see ISoundTriggerHw#getProperties_2_3(ISoundTriggerHw.getProperties_2_3Callback) */ - int loadPhraseSoundModel( - android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel soundModel, - SoundTriggerHw2Compat.Callback callback, int cookie); + Properties getProperties(); /** - * @see android.hardware.soundtrigger.V2_2.ISoundTriggerHw#unloadSoundModel(int) + * @see ISoundTriggerHw#registerGlobalCallback(ISoundTriggerHwGlobalCallback) */ - void unloadSoundModel(int modelHandle); + void registerCallback(GlobalCallback callback); /** - * @see android.hardware.soundtrigger.V2_2.ISoundTriggerHw#stopRecognition(int) + * @see ISoundTriggerHw#loadSoundModel_2_4( + * ISoundTriggerHw.SoundModel, + * ISoundTriggerHwCallback, + * ISoundTriggerHw.loadSoundModel_2_4Callback) */ - void stopRecognition(int modelHandle); + int loadSoundModel(ISoundTriggerHw.SoundModel soundModel, ModelCallback callback); + + /** + * @see ISoundTriggerHw#loadPhraseSoundModel_2_4( + * ISoundTriggerHw.PhraseSoundModel, + * ISoundTriggerHwCallback, + * ISoundTriggerHw.loadPhraseSoundModel_2_4Callback) + */ + int loadPhraseSoundModel(ISoundTriggerHw.PhraseSoundModel soundModel, ModelCallback callback); + + /** + * @see ISoundTriggerHw#unloadSoundModel(int) + */ + void unloadSoundModel(int modelHandle); /** - * @see android.hardware.soundtrigger.V2_2.ISoundTriggerHw#stopAllRecognitions() + * @see ISoundTriggerHw#stopRecognition(int) */ - void stopAllRecognitions(); + void stopRecognition(int modelHandle); /** - * @see android.hardware.soundtrigger.V2_3.ISoundTriggerHw#startRecognition_2_3(int, - * android.hardware.soundtrigger.V2_3.RecognitionConfig, - * android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback, int) + * @see ISoundTriggerHw#startRecognition_2_4(int, RecognitionConfig) */ - void startRecognition(int modelHandle, - android.hardware.soundtrigger.V2_3.RecognitionConfig config, - SoundTriggerHw2Compat.Callback callback, int cookie); + void startRecognition(int modelHandle, RecognitionConfig config); /** - * @see android.hardware.soundtrigger.V2_2.ISoundTriggerHw#getModelState(int) + * @see ISoundTriggerHw#getModelState(int) */ void getModelState(int modelHandle); /** - * @see android.hardware.soundtrigger.V2_3.ISoundTriggerHw#getParameter(int, int, - * ISoundTriggerHw.getParameterCallback) + * @see ISoundTriggerHw#getParameter(int, int, ISoundTriggerHw.getParameterCallback) */ int getModelParameter(int modelHandle, int param); /** - * @see android.hardware.soundtrigger.V2_3.ISoundTriggerHw#setParameter(int, int, int) + * @see ISoundTriggerHw#setParameter(int, int, int) */ void setModelParameter(int modelHandle, int param, int value); /** * @return null if not supported. - * @see android.hardware.soundtrigger.V2_3.ISoundTriggerHw#queryParameter(int, int, + * @see ISoundTriggerHw#queryParameter(int, int, * ISoundTriggerHw.queryParameterCallback) */ ModelParameterRange queryParameter(int modelHandle, int param); @@ -138,21 +146,45 @@ public interface ISoundTriggerHw2 { */ String interfaceDescriptor() throws android.os.RemoteException; - interface Callback { + /* + * This is only useful for testing decorators and doesn't actually do anything with the real + * HAL. This method would block until all callbacks that were previously generated have been + * invoked. For most decorators, this merely flushes the delegate, but for delegates that may + * additional buffers for callbacks this should flush them. + */ + void flushCallbacks(); + + /** + * Callback interface for model-related events. + */ + interface ModelCallback { + /** + * @see ISoundTriggerHwCallback#recognitionCallback_2_1( + * ISoundTriggerHwCallback.RecognitionEvent, + * int) + */ + void recognitionCallback(ISoundTriggerHwCallback.RecognitionEvent event); + /** - * @see android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback#recognitionCallback_2_1(android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent, - * int) + * @see ISoundTriggerHwCallback#phraseRecognitionCallback_2_1( + * ISoundTriggerHwCallback.PhraseRecognitionEvent, + * int) */ - void recognitionCallback( - android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent event, - int cookie); + void phraseRecognitionCallback(ISoundTriggerHwCallback.PhraseRecognitionEvent event); /** - * @see android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback#phraseRecognitionCallback_2_1(android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent, - * int) + * @see ISoundTriggerHwCallback#modelUnloaded(int) + */ + void modelUnloaded(int modelHandle); + } + + /** + * Callback interface for global events. + */ + interface GlobalCallback { + /** + * @see ISoundTriggerHwGlobalCallback#onResourcesAvailable() */ - void phraseRecognitionCallback( - android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent event, - int cookie); + void onResourcesAvailable(); } } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java b/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java index a90053a23dea..e2fe301bda36 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java @@ -16,7 +16,6 @@ package com.android.server.soundtrigger_middleware; -import android.media.ICaptureStateListener; import android.media.soundtrigger_middleware.ISoundTriggerCallback; import android.media.soundtrigger_middleware.ISoundTriggerModule; import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; @@ -27,7 +26,7 @@ import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; * The ISoundTriggerMiddlewareService have been modified to exclude identity information and the * RemoteException signature, both of which are only relevant at the service boundary layer. */ -public interface ISoundTriggerMiddlewareInternal extends ICaptureStateListener { +public interface ISoundTriggerMiddlewareInternal { /** * Query the available modules and their capabilities. */ diff --git a/services/core/java/com/android/server/soundtrigger_middleware/README.md b/services/core/java/com/android/server/soundtrigger_middleware/README.md index 416548d9bc5e..f75828bafbbf 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/README.md +++ b/services/core/java/com/android/server/soundtrigger_middleware/README.md @@ -4,16 +4,48 @@ TODO: Add component description. ## Notes about thread synchronization This component has some tricky thread synchronization considerations due to its layered design and due to the fact that it is involved in both in-bound and out-bound calls from / to -external components. To avoid potential deadlocks, a strict locking order must be ensured whenever -nesting locks. The order is: -- `SoundTriggerMiddlewareValidation` lock. -- Audio policy service lock. This one is external - it should be assumed to be held whenever we're +external components. + +The following mutexes need to be considered: +- Typically, a one or more mutexes that exist in every layer of the sound trigger middleware stack + to serialize access to its internal state or to external components. +- Audio Policy Service lock. This one is external - it should be assumed to be held whenever we're inside the `ExternalCaptureStateTracker.setCaptureState()` call stack *AND* to be acquired from - within our calls into `AudioSessionProvider.acquireSession()`. -- `SoundTriggerModule` lock. + within our calls into `AudioSessionProvider.acquireSession()` / + `AudioSessionProvider.releaseSession()`. + +To avoid potential deadlocks, a strict locking order must be ensured whenever nesting locks. The +order is: +- Upper layers of the stack, starting from the top (i.e. may not attempt to acquire a higher-layer + mutex while a lower-layer mutex is being held) until `ISoundTriggerHw2`. +- Audio Policy Service lock. +- Lower layers of the stack, starting from `ISoundTriggerHw2` all the way down to the HAL. -This dictates careful consideration of callbacks going from `SoundTriggerModule` to -`SoundTriggerMiddlewareValidation` and especially those coming from the `setCaptureState()` path. -We always invoke those calls outside of the `SoundTriggerModule` lock, so we can lock -`SoundTriggerMiddlewareValidation`. However, in the `setCaptureState()` case, we have to use atomics -in `SoundTriggerMiddlewareValidation` and avoid the lock. +In order to enforce this order, some conventions are established around when it is safe for a module +to call another module, while having its local mutex(es) held: +- Most calls (see exceptions below) originating from SoundTriggerMiddlewareService simply propagate + down the decorator stack. It is legal to call into the next layer down while holding a local + mutex. It is illegal to invoke a callback with a local mutex held. +- Callbacks propagate from the lower layers up to the upper layers. It is legal to hold a local + mutex within a callback, but **not** while call to an upper layer. +- In order to be able to synchronize, despite the asynchronous nature of callbacks, + `stopRecognition()` and `unloadModel()` work differently. They guarantee that once they return, + the callbacks associated with them will no longer be called. This implies that they have to block + until any pending callbacks are done processing and since these callbacks are potentially holding + locks of higher-order mutexes, we must not be holding a local mutex while calling down. The proper + sequence for these calls is: + - Obtain the local lock if needed. Update/check local state as necessary. + - Call the respective method of the delegate ("downwards"). Once it returns, not more callbacks + related to this operation will be called. + - Obtain the local lock if needed. Update local state as necessary. Assume that state might have + changed while the lock has been released. + - Release the local lock. + - Invoke any synchronous callbacks if needed. +- Calling from `SoundTriggerMiddlewareImpl` / `SoundTriggerModule` into the audio policy service via + `acquireSession()` / `releaseSession()` while holding the local lock is legal. +- `setCaptureState()` calls, originating from Audio Policy Service, into the lower layers of the + stack may call into the HAL (specificall, they must invoke `stopRecognition()`, but must not block + on callbacks. For this reason, `SoundTriggerHw2ConcurrentCaptureHandler`, which is the recipient + of these calls, features a buffer and an additional thread, which allows the actual stopping to be + synchronous, as required, without having to block the call upon higher layers processing the + callbacks. diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java index 2f087f46da86..9da6562a40ac 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java @@ -18,11 +18,15 @@ package com.android.server.soundtrigger_middleware; import android.annotation.NonNull; import android.annotation.Nullable; +import android.hardware.soundtrigger.V2_0.ISoundTriggerHw; import android.media.soundtrigger_middleware.Status; import android.os.IHwBinder; import android.os.RemoteException; +import android.system.OsConstants; import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; @@ -42,36 +46,75 @@ import java.util.concurrent.atomic.AtomicReference; * </ul> */ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { - private final @NonNull - IHwBinder mBinder; - private final @NonNull - android.hardware.soundtrigger.V2_0.ISoundTriggerHw mUnderlying_2_0; - private final @Nullable - android.hardware.soundtrigger.V2_1.ISoundTriggerHw mUnderlying_2_1; - private final @Nullable - android.hardware.soundtrigger.V2_2.ISoundTriggerHw mUnderlying_2_2; - private final @Nullable - android.hardware.soundtrigger.V2_3.ISoundTriggerHw mUnderlying_2_3; - - public SoundTriggerHw2Compat( - @NonNull android.hardware.soundtrigger.V2_0.ISoundTriggerHw underlying) { - this(underlying.asBinder()); + private final @NonNull Runnable mRebootRunnable; + private final @NonNull IHwBinder mBinder; + private @NonNull android.hardware.soundtrigger.V2_0.ISoundTriggerHw mUnderlying_2_0; + private @Nullable android.hardware.soundtrigger.V2_1.ISoundTriggerHw mUnderlying_2_1; + private @Nullable android.hardware.soundtrigger.V2_2.ISoundTriggerHw mUnderlying_2_2; + private @Nullable android.hardware.soundtrigger.V2_3.ISoundTriggerHw mUnderlying_2_3; + private @Nullable android.hardware.soundtrigger.V2_4.ISoundTriggerHw mUnderlying_2_4; + + // HAL <=2.1 requires us to pass a callback argument to startRecognition. We will store the one + // passed on load and then pass it on start. We don't bother storing the callback on newer + // versions. + private final @NonNull ConcurrentMap<Integer, ModelCallback> mModelCallbacks = + new ConcurrentHashMap<>(); + + // The properties are read at construction time and cached, since we need to use some of them + // to enforce constraints. + private final @NonNull android.hardware.soundtrigger.V2_3.Properties mProperties; + + static ISoundTriggerHw2 create( + @NonNull ISoundTriggerHw underlying, + @NonNull Runnable rebootRunnable, + ICaptureStateNotifier notifier) { + return create(underlying.asBinder(), rebootRunnable, notifier); } - public SoundTriggerHw2Compat(IHwBinder binder) { - Objects.requireNonNull(binder); + static ISoundTriggerHw2 create(@NonNull IHwBinder binder, + @NonNull Runnable rebootRunnable, + ICaptureStateNotifier notifier) { + SoundTriggerHw2Compat compat = new SoundTriggerHw2Compat(binder, rebootRunnable); + ISoundTriggerHw2 result = compat; + // Add max model limiter for versions <2.4. + if (compat.mUnderlying_2_4 == null) { + result = new SoundTriggerHw2MaxModelLimiter(result, + compat.mProperties.base.maxSoundModels); + } + // Add concurrent capture handler for versions <2.4 which do not support concurrent capture. + if (compat.mUnderlying_2_4 == null && !compat.mProperties.base.concurrentCapture) { + result = new SoundTriggerHw2ConcurrentCaptureHandler(result, notifier); + } + return result; + } - mBinder = binder; + private SoundTriggerHw2Compat(@NonNull IHwBinder binder, @NonNull Runnable rebootRunnable) { + mRebootRunnable = Objects.requireNonNull(rebootRunnable); + mBinder = Objects.requireNonNull(binder); + initUnderlying(binder); + mProperties = Objects.requireNonNull(getPropertiesInternal()); + } + private void initUnderlying(IHwBinder binder) { // We want to share the proxy instances rather than create a separate proxy for every // version, so we go down the versions in descending order to find the latest one supported, // and then simply up-cast it to obtain all the versions that are earlier. + // Attempt 2.4 + android.hardware.soundtrigger.V2_4.ISoundTriggerHw as2_4 = + android.hardware.soundtrigger.V2_4.ISoundTriggerHw.asInterface(binder); + if (as2_4 != null) { + mUnderlying_2_0 = + mUnderlying_2_1 = mUnderlying_2_2 = mUnderlying_2_3 = mUnderlying_2_4 = as2_4; + return; + } + // Attempt 2.3 android.hardware.soundtrigger.V2_3.ISoundTriggerHw as2_3 = android.hardware.soundtrigger.V2_3.ISoundTriggerHw.asInterface(binder); if (as2_3 != null) { mUnderlying_2_0 = mUnderlying_2_1 = mUnderlying_2_2 = mUnderlying_2_3 = as2_3; + mUnderlying_2_4 = null; return; } @@ -80,7 +123,7 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { android.hardware.soundtrigger.V2_2.ISoundTriggerHw.asInterface(binder); if (as2_2 != null) { mUnderlying_2_0 = mUnderlying_2_1 = mUnderlying_2_2 = as2_2; - mUnderlying_2_3 = null; + mUnderlying_2_3 = mUnderlying_2_4 = null; return; } @@ -89,7 +132,7 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { android.hardware.soundtrigger.V2_1.ISoundTriggerHw.asInterface(binder); if (as2_1 != null) { mUnderlying_2_0 = mUnderlying_2_1 = as2_1; - mUnderlying_2_2 = mUnderlying_2_3 = null; + mUnderlying_2_2 = mUnderlying_2_3 = mUnderlying_2_4 = null; return; } @@ -98,7 +141,7 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { android.hardware.soundtrigger.V2_0.ISoundTriggerHw.asInterface(binder); if (as2_0 != null) { mUnderlying_2_0 = as2_0; - mUnderlying_2_1 = mUnderlying_2_2 = mUnderlying_2_3 = null; + mUnderlying_2_1 = mUnderlying_2_2 = mUnderlying_2_3 = mUnderlying_2_4 = null; return; } @@ -111,8 +154,29 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { } } + private static void handleHalStatusAllowBusy(int status, String methodName) { + if (status == -OsConstants.EBUSY) { + throw new RecoverableException(Status.RESOURCE_CONTENTION); + } + handleHalStatus(status, methodName); + } + + @Override + public void reboot() { + mRebootRunnable.run(); + } + + @Override + public void detach() { + // No-op. + } + @Override public android.hardware.soundtrigger.V2_3.Properties getProperties() { + return mProperties; + } + + private android.hardware.soundtrigger.V2_3.Properties getPropertiesInternal() { try { AtomicInteger retval = new AtomicInteger(-1); AtomicReference<android.hardware.soundtrigger.V2_3.Properties> @@ -136,23 +200,50 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { } @Override + public void registerCallback(GlobalCallback callback) { + try { + try { + as2_4().registerGlobalCallback(new GlobalCallbackWrapper(callback)); + } catch (NotSupported e) { + // In versions < 2.4 the events represented by this callback don't exist, we can + // safely ignore this. + } + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + @Override public int loadSoundModel( android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel soundModel, - Callback callback, int cookie) { + ModelCallback callback) { try { AtomicInteger retval = new AtomicInteger(-1); AtomicInteger handle = new AtomicInteger(0); + try { - as2_1().loadSoundModel_2_1(soundModel, new SoundTriggerCallback(callback), cookie, + as2_4().loadSoundModel_2_4(soundModel, new ModelCallbackWrapper(callback), (r, h) -> { retval.set(r); handle.set(h); }); + handleHalStatusAllowBusy(retval.get(), "loadSoundModel_2_4"); } catch (NotSupported e) { - // Fall-back to the 2.0 version: - return loadSoundModel_2_0(soundModel, callback, cookie); + // Fall-back to the 2.1 version: + try { + as2_1().loadSoundModel_2_1(soundModel, new ModelCallbackWrapper(callback), + 0, + (r, h) -> { + retval.set(r); + handle.set(h); + }); + handleHalStatus(retval.get(), "loadSoundModel_2_1"); + mModelCallbacks.put(handle.get(), callback); + } catch (NotSupported ee) { + // Fall-back to the 2.0 version: + return loadSoundModel_2_0(soundModel, callback); + } } - handleHalStatus(retval.get(), "loadSoundModel_2_1"); return handle.get(); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); @@ -162,22 +253,33 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { @Override public int loadPhraseSoundModel( android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel soundModel, - Callback callback, int cookie) { + ModelCallback callback) { try { AtomicInteger retval = new AtomicInteger(-1); AtomicInteger handle = new AtomicInteger(0); try { - as2_1().loadPhraseSoundModel_2_1(soundModel, new SoundTriggerCallback(callback), - cookie, + as2_4().loadPhraseSoundModel_2_4(soundModel, new ModelCallbackWrapper(callback), (r, h) -> { retval.set(r); handle.set(h); }); + handleHalStatusAllowBusy(retval.get(), "loadPhraseSoundModel_2_4"); } catch (NotSupported e) { - // Fall-back to the 2.0 version: - return loadPhraseSoundModel_2_0(soundModel, callback, cookie); + // Fall-back to the 2.1 version: + try { + as2_1().loadPhraseSoundModel_2_1(soundModel, new ModelCallbackWrapper(callback), + 0, + (r, h) -> { + retval.set(r); + handle.set(h); + }); + handleHalStatus(retval.get(), "loadPhraseSoundModel_2_1"); + mModelCallbacks.put(handle.get(), callback); + } catch (NotSupported ee) { + // Fall-back to the 2.0 version: + return loadPhraseSoundModel_2_0(soundModel, callback); + } } - handleHalStatus(retval.get(), "loadSoundModel_2_1"); return handle.get(); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); @@ -187,6 +289,8 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { @Override public void unloadSoundModel(int modelHandle) { try { + // Safe if key doesn't exist. + mModelCallbacks.remove(modelHandle); int retval = as2_0().unloadSoundModel(modelHandle); handleHalStatus(retval, "unloadSoundModel"); } catch (RemoteException e) { @@ -206,26 +310,21 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { } @Override - public void stopAllRecognitions() { - try { - int retval = as2_0().stopAllRecognitions(); - handleHalStatus(retval, "stopAllRecognitions"); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - } - - @Override public void startRecognition(int modelHandle, - android.hardware.soundtrigger.V2_3.RecognitionConfig config, - Callback callback, int cookie) { + android.hardware.soundtrigger.V2_3.RecognitionConfig config) { try { try { - int retval = as2_3().startRecognition_2_3(modelHandle, config); - handleHalStatus(retval, "startRecognition_2_3"); + int retval = as2_4().startRecognition_2_4(modelHandle, config); + handleHalStatusAllowBusy(retval, "startRecognition_2_4"); } catch (NotSupported e) { - // Fall-back to the 2.0 version: - startRecognition_2_1(modelHandle, config, callback, cookie); + // Fall-back to the 2.3 version: + try { + int retval = as2_3().startRecognition_2_3(modelHandle, config); + handleHalStatus(retval, "startRecognition_2_3"); + } catch (NotSupported ee) { + // Fall-back to the 2.0 version: + startRecognition_2_1(modelHandle, config); + } } } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); @@ -316,6 +415,11 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { return as2_0().interfaceDescriptor(); } + @Override + public void flushCallbacks() { + // This is a no-op. Only implemented for decorators. + } + private android.hardware.soundtrigger.V2_3.Properties getProperties_2_0() throws RemoteException { AtomicInteger retval = new AtomicInteger(-1); @@ -333,7 +437,7 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { private int loadSoundModel_2_0( android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel soundModel, - Callback callback, int cookie) + ModelCallback callback) throws RemoteException { // Convert the soundModel to V2.0. android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel model_2_0 = @@ -341,17 +445,18 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { AtomicInteger retval = new AtomicInteger(-1); AtomicInteger handle = new AtomicInteger(0); - as2_0().loadSoundModel(model_2_0, new SoundTriggerCallback(callback), cookie, (r, h) -> { + as2_0().loadSoundModel(model_2_0, new ModelCallbackWrapper(callback), 0, (r, h) -> { retval.set(r); handle.set(h); }); handleHalStatus(retval.get(), "loadSoundModel"); + mModelCallbacks.put(handle.get(), callback); return handle.get(); } private int loadPhraseSoundModel_2_0( android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel soundModel, - Callback callback, int cookie) + ModelCallback callback) throws RemoteException { // Convert the soundModel to V2.0. android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel model_2_0 = @@ -359,28 +464,28 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { AtomicInteger retval = new AtomicInteger(-1); AtomicInteger handle = new AtomicInteger(0); - as2_0().loadPhraseSoundModel(model_2_0, new SoundTriggerCallback(callback), cookie, + as2_0().loadPhraseSoundModel(model_2_0, new ModelCallbackWrapper(callback), 0, (r, h) -> { retval.set(r); handle.set(h); }); handleHalStatus(retval.get(), "loadSoundModel"); + mModelCallbacks.put(handle.get(), callback); return handle.get(); } private void startRecognition_2_1(int modelHandle, - android.hardware.soundtrigger.V2_3.RecognitionConfig config, - Callback callback, int cookie) { + android.hardware.soundtrigger.V2_3.RecognitionConfig config) { try { try { android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig config_2_1 = Hw2CompatUtil.convertRecognitionConfig_2_3_to_2_1(config); int retval = as2_1().startRecognition_2_1(modelHandle, config_2_1, - new SoundTriggerCallback(callback), cookie); + new ModelCallbackWrapper(mModelCallbacks.get(modelHandle)), 0); handleHalStatus(retval, "startRecognition_2_1"); } catch (NotSupported e) { // Fall-back to the 2.0 version: - startRecognition_2_0(modelHandle, config, callback, cookie); + startRecognition_2_0(modelHandle, config); } } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); @@ -388,13 +493,12 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { } private void startRecognition_2_0(int modelHandle, - android.hardware.soundtrigger.V2_3.RecognitionConfig config, - Callback callback, int cookie) + android.hardware.soundtrigger.V2_3.RecognitionConfig config) throws RemoteException { android.hardware.soundtrigger.V2_0.ISoundTriggerHw.RecognitionConfig config_2_0 = Hw2CompatUtil.convertRecognitionConfig_2_3_to_2_0(config); int retval = as2_0().startRecognition(modelHandle, config_2_0, - new SoundTriggerCallback(callback), cookie); + new ModelCallbackWrapper(mModelCallbacks.get(modelHandle)), 0); handleHalStatus(retval, "startRecognition"); } @@ -427,6 +531,14 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { return mUnderlying_2_3; } + private @NonNull + android.hardware.soundtrigger.V2_4.ISoundTriggerHw as2_4() throws NotSupported { + if (mUnderlying_2_4 == null) { + throw new NotSupported("Underlying driver version < 2.4"); + } + return mUnderlying_2_4; + } + /** * A checked exception representing the requested interface version not being supported. * At the public interface layer, use {@link #throwAsRecoverableException()} to propagate it to @@ -448,28 +560,46 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { } } - private static class SoundTriggerCallback extends - android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.Stub { - private final @NonNull - Callback mDelegate; + private static class GlobalCallbackWrapper extends + android.hardware.soundtrigger.V2_4.ISoundTriggerHwGlobalCallback.Stub { + private final @NonNull GlobalCallback mDelegate; + + private GlobalCallbackWrapper(@NonNull GlobalCallback delegate) { + mDelegate = delegate; + } + + @Override + public void onResourcesAvailable() { + mDelegate.onResourcesAvailable(); + } + } + + private static class ModelCallbackWrapper extends + android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback.Stub { + private final @NonNull ModelCallback mDelegate; - private SoundTriggerCallback( - @NonNull Callback delegate) { + private ModelCallbackWrapper( + @NonNull ModelCallback delegate) { mDelegate = Objects.requireNonNull(delegate); } @Override + public void modelUnloaded(int modelHandle) { + mDelegate.modelUnloaded(modelHandle); + } + + @Override public void recognitionCallback_2_1( android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent event, int cookie) { - mDelegate.recognitionCallback(event, cookie); + mDelegate.recognitionCallback(event); } @Override public void phraseRecognitionCallback_2_1( android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent event, int cookie) { - mDelegate.phraseRecognitionCallback(event, cookie); + mDelegate.phraseRecognitionCallback(event); } @Override @@ -485,7 +615,7 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { int cookie) { android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent event_2_1 = Hw2CompatUtil.convertRecognitionEvent_2_0_to_2_1(event); - mDelegate.recognitionCallback(event_2_1, cookie); + mDelegate.recognitionCallback(event_2_1); } @Override @@ -494,7 +624,7 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHw2 { int cookie) { android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent event_2_1 = Hw2CompatUtil.convertPhraseRecognitionEvent_2_0_to_2_1(event); - mDelegate.phraseRecognitionCallback(event_2_1, cookie); + mDelegate.phraseRecognitionCallback(event_2_1); } @Override diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2ConcurrentCaptureHandler.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2ConcurrentCaptureHandler.java new file mode 100644 index 000000000000..429f2a8ab5e9 --- /dev/null +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2ConcurrentCaptureHandler.java @@ -0,0 +1,465 @@ +/* + * 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.soundtrigger_middleware; + +import android.annotation.NonNull; +import android.hardware.soundtrigger.V2_1.ISoundTriggerHw; +import android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback; +import android.hardware.soundtrigger.V2_3.ModelParameterRange; +import android.hardware.soundtrigger.V2_3.Properties; +import android.hardware.soundtrigger.V2_3.RecognitionConfig; +import android.media.permission.SafeCloseable; +import android.media.soundtrigger_middleware.RecognitionStatus; +import android.media.soundtrigger_middleware.SoundModelType; +import android.media.soundtrigger_middleware.Status; +import android.os.IHwBinder; +import android.os.RemoteException; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * This is a decorator around ISoundTriggerHw2, which implements enforcement of concurrent capture + * constraints, for HAL implementations older than V2.4 (later versions support this feature at the + * HAL level). + * <p> + * Decorating an instance with this class would result in all active recognitions being aborted as + * soon as capture state becomes active. This class ensures consistent handling of abortions coming + * from that HAL and abortions coming from concurrent capture, in that only one abort event will be + * delivered, irrespective of the relative timing of the two events. + * <p> + * There are some delicate thread-safety issues handled here: + * <ul> + * <li>When a model is stopped via stopRecognition(), we guarantee that by the time the call + * returns, there will be no more recognition events (including abort) delivered for this model. + * This implies synchronous stopping and blocking until all pending events have been delivered. + * <li>When a model is stopped via onCaptureStateChange(true), the stopping of the recognition at + * the HAL level must be synchronous, but the call must not block on the delivery of the + * callbacks, due to the risk of a deadlock: the onCaptureStateChange() calls are typically + * invoked with the audio policy mutex held, so must not call method which may attempt to lock + * higher-level mutexes. See README.md in this directory for further details. + * </ul> + * The way this behavior is achieved is by having an additional thread with an event queue, which + * joins together model events coming from the delegate module with abort events originating from + * this layer (as result of external capture). + */ +public class SoundTriggerHw2ConcurrentCaptureHandler implements ISoundTriggerHw2, + ICaptureStateNotifier.Listener { + private final @NonNull ISoundTriggerHw2 mDelegate; + private GlobalCallback mGlobalCallback; + + /** + * Information about a model that is currently loaded. This is needed in order to be able to + * send abort events to its designated callback. + */ + private static class LoadedModel { + final int type; + final @NonNull ModelCallback callback; + + private LoadedModel(int type, @NonNull ModelCallback callback) { + this.type = type; + this.callback = callback; + } + } + + /** + * This map holds the model type for every model that is loaded. + */ + private final @NonNull Map<Integer, LoadedModel> mLoadedModels = new ConcurrentHashMap<>(); + + /** + * A set of all models that are currently active. + * We use this in order to know which models to stop in case of external capture. + * Used as a lock to synchronize operations that effect activity. + */ + private final @NonNull Set<Integer> mActiveModels = new HashSet<>(); + + /** + * Notifier for changes in capture state. + */ + private final @NonNull ICaptureStateNotifier mNotifier; + + /** + * Whether capture is active. + */ + private boolean mCaptureState; + + /** + * Since we're wrapping the death recipient, we need to keep a translation map for unlinking. + * Key is the client recipient, value is the wrapper. + */ + private final @NonNull Map<IHwBinder.DeathRecipient, IHwBinder.DeathRecipient> + mDeathRecipientMap = new ConcurrentHashMap<>(); + + private final @NonNull CallbackThread mCallbackThread = new CallbackThread(); + + public SoundTriggerHw2ConcurrentCaptureHandler( + @NonNull ISoundTriggerHw2 delegate, + @NonNull ICaptureStateNotifier notifier) { + mDelegate = delegate; + mNotifier = notifier; + mCaptureState = mNotifier.registerListener(this); + } + + @Override + public void startRecognition(int modelHandle, RecognitionConfig config) { + synchronized (mActiveModels) { + if (mCaptureState) { + throw new RecoverableException(Status.RESOURCE_CONTENTION); + } + mDelegate.startRecognition(modelHandle, config); + mActiveModels.add(modelHandle); + } + } + + @Override + public void stopRecognition(int modelHandle) { + synchronized (mActiveModels) { + mDelegate.stopRecognition(modelHandle); + mActiveModels.remove(modelHandle); + } + // Block until all previous events are delivered. Since this is potentially blocking on + // upward calls, it must be done outside the lock. + mCallbackThread.flush(); + } + + @Override + public void onCaptureStateChange(boolean active) { + synchronized (mActiveModels) { + if (active) { + // Abort all active models. This must be done as one transaction to the event + // thread, in order to be able to dedupe events before they are delivered. + try (SafeCloseable ignored = mCallbackThread.stallReader()) { + for (int modelHandle : mActiveModels) { + mDelegate.stopRecognition(modelHandle); + LoadedModel model = mLoadedModels.get(modelHandle); + // An abort event must be the last one for its model. + mCallbackThread.pushWithDedupe(modelHandle, true, + () -> notifyAbort(modelHandle, model)); + } + } + } else { + mGlobalCallback.onResourcesAvailable(); + } + + mCaptureState = active; + } + } + + @Override + public int loadSoundModel(ISoundTriggerHw.SoundModel soundModel, ModelCallback callback) { + int handle = mDelegate.loadSoundModel(soundModel, new CallbackWrapper(callback)); + mLoadedModels.put(handle, new LoadedModel(SoundModelType.GENERIC, callback)); + return handle; + } + + @Override + public int loadPhraseSoundModel(ISoundTriggerHw.PhraseSoundModel soundModel, + ModelCallback callback) { + int handle = mDelegate.loadPhraseSoundModel(soundModel, new CallbackWrapper(callback)); + mLoadedModels.put(handle, new LoadedModel(SoundModelType.KEYPHRASE, callback)); + return handle; + } + + @Override + public void unloadSoundModel(int modelHandle) { + mLoadedModels.remove(modelHandle); + mDelegate.unloadSoundModel(modelHandle); + } + + @Override + public void registerCallback(GlobalCallback callback) { + mGlobalCallback = new GlobalCallback() { + @Override + public void onResourcesAvailable() { + mCallbackThread.push(callback::onResourcesAvailable); + } + }; + mDelegate.registerCallback(mGlobalCallback); + } + + @Override + public boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) { + IHwBinder.DeathRecipient wrapper = new IHwBinder.DeathRecipient() { + @Override + public void serviceDied(long cookieBack) { + mCallbackThread.push(() -> recipient.serviceDied(cookieBack)); + } + }; + if (mDelegate.linkToDeath(wrapper, cookie)) { + mDeathRecipientMap.put(recipient, wrapper); + return true; + } + return false; + } + + @Override + public boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) { + return mDelegate.unlinkToDeath(mDeathRecipientMap.remove(recipient)); + } + + private class CallbackWrapper implements ISoundTriggerHw2.ModelCallback { + private final @NonNull ISoundTriggerHw2.ModelCallback mDelegateCallback; + + private CallbackWrapper(@NonNull ModelCallback delegateCallback) { + mDelegateCallback = delegateCallback; + } + + @Override + public void recognitionCallback(ISoundTriggerHwCallback.RecognitionEvent event) { + // A recognition event must be the last one for its model, unless it is a forced one + // (those leave the model active). + mCallbackThread.pushWithDedupe(event.header.model, + event.header.status != RecognitionStatus.FORCED, + () -> mDelegateCallback.recognitionCallback(event)); + } + + @Override + public void phraseRecognitionCallback( + ISoundTriggerHwCallback.PhraseRecognitionEvent event) { + // A recognition event must be the last one for its model, unless it is a forced one + // (those leave the model active). + mCallbackThread.pushWithDedupe(event.common.header.model, + event.common.header.status != RecognitionStatus.FORCED, + () -> mDelegateCallback.phraseRecognitionCallback(event)); + } + + @Override + public void modelUnloaded(int modelHandle) { + mCallbackThread.push(() -> mDelegateCallback.modelUnloaded(modelHandle)); + } + } + + @Override + public void flushCallbacks() { + mDelegate.flushCallbacks(); + mCallbackThread.flush(); + } + + /** + * This is a thread for asynchronous delivery of callback events, having the following features: + * <ul> + * <li>Events are processed on a separate thread than the thread that pushed them, in the order + * they were pushed. + * <li>Events can be deduped upon entry to the queue. This is achieved as follows: + * <ul> + * <li>Temporarily stall the reader via {@link #stallReader()}. + * <li>Within this scope, push as many events as needed via + * {@link #pushWithDedupe(int, boolean, Runnable)}. + * If an event with the same model handle as the one being pushed is already in the queue + * and has been marked as "lastForModel", the new event will be discarded before entering + * the queue. + * <li>Finally, un-stall the reader by existing the scope. + * <li>Events that do not require deduping can be pushed via {@link #push(Runnable)}. + * </ul> + * <li>Events can be flushed via {@link #flush()}. This will block until all events pushed prior + * to this call have been fully processed. + * </ul> + */ + private static class CallbackThread { + private static class Entry { + final boolean lastForModel; + final int modelHandle; + final Runnable runnable; + + private Entry(boolean lastForModel, int modelHandle, Runnable runnable) { + this.lastForModel = lastForModel; + this.modelHandle = modelHandle; + this.runnable = runnable; + } + } + + private boolean mStallReader = false; + private final Queue<Entry> mList = new LinkedList<>(); + private int mPushCount = 0; + private int mProcessedCount = 0; + + /** + * Ctor. Starts the thread. + */ + CallbackThread() { + new Thread(() -> { + try { + while (true) { + pop().run(); + synchronized (mList) { + mProcessedCount++; + mList.notifyAll(); + } + } + } catch (InterruptedException e) { + // If interrupted, exit. + } + }).start(); + } + + /** + * Push a new runnable to the queue, with no deduping. + * + * @param runnable The runnable to push. + */ + void push(Runnable runnable) { + pushEntry(new Entry(false, 0, runnable), false); + } + + + /** + * Push a new runnable to the queue, with deduping. + * If an entry with the same model handle is already in the queue and was designated as + * last for model, this one will be discarded. + * + * @param modelHandle The model handle, used for deduping purposes. + * @param lastForModel If true, this entry will be considered the last one for this model + * and any subsequence calls for this handle (whether lastForModel or + * not) will be discarded while this entry is in the queue. + * @param runnable The runnable to push. + */ + void pushWithDedupe(int modelHandle, boolean lastForModel, Runnable runnable) { + pushEntry(new Entry(lastForModel, modelHandle, runnable), true); + } + + /** + * Block until every entry pushed prior to this call has been processed. + */ + void flush() { + try { + synchronized (mList) { + int pushCount = mPushCount; + while (mProcessedCount != pushCount) { + mList.wait(); + } + } + } catch (InterruptedException ignored) { + } + } + + /** + * Creates a scope (using a try-with-resources block), within which events that are pushed + * remain queued and processed. This is useful in order to utilize deduping. + */ + SafeCloseable stallReader() { + synchronized (mList) { + mStallReader = true; + return () -> { + synchronized (mList) { + mStallReader = false; + mList.notifyAll(); + } + }; + } + } + + private void pushEntry(Entry entry, boolean dedupe) { + synchronized (mList) { + if (dedupe) { + for (Entry existing : mList) { + if (existing.lastForModel && existing.modelHandle == entry.modelHandle) { + return; + } + } + } + mList.add(entry); + mPushCount++; + mList.notifyAll(); + } + } + + private Runnable pop() throws InterruptedException { + synchronized (mList) { + while (mStallReader || mList.isEmpty()) { + mList.wait(); + } + return mList.remove().runnable; + } + } + } + + /** Notify the client that recognition has been aborted. */ + private static void notifyAbort(int modelHandle, LoadedModel model) { + switch (model.type) { + case SoundModelType.GENERIC: { + ISoundTriggerHwCallback.RecognitionEvent event = + new ISoundTriggerHwCallback.RecognitionEvent(); + event.header.model = modelHandle; + event.header.status = + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT; + event.header.type = android.hardware.soundtrigger.V2_0.SoundModelType.GENERIC; + model.callback.recognitionCallback(event); + } + break; + + case SoundModelType.KEYPHRASE: { + ISoundTriggerHwCallback.PhraseRecognitionEvent event = + new ISoundTriggerHwCallback.PhraseRecognitionEvent(); + event.common.header.model = modelHandle; + event.common.header.status = + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT; + event.common.header.type = + android.hardware.soundtrigger.V2_0.SoundModelType.KEYPHRASE; + model.callback.phraseRecognitionCallback(event); + } + break; + } + } + + @Override + public void detach() { + mDelegate.detach(); + mNotifier.unregisterListener(this); + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + // All methods below do trivial delegation - no interesting logic. + @Override + public void reboot() { + mDelegate.reboot(); + } + + @Override + public Properties getProperties() { + return mDelegate.getProperties(); + } + + @Override + public void getModelState(int modelHandle) { + mDelegate.getModelState(modelHandle); + } + + @Override + public int getModelParameter(int modelHandle, int param) { + return mDelegate.getModelParameter(modelHandle, param); + } + + @Override + public void setModelParameter(int modelHandle, int param, int value) { + mDelegate.setModelParameter(modelHandle, param, value); + } + + @Override + public ModelParameterRange queryParameter(int modelHandle, int param) { + return mDelegate.queryParameter(modelHandle, param); + } + + @Override + public String interfaceDescriptor() throws RemoteException { + return mDelegate.interfaceDescriptor(); + } +} diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java index cf7460b306cd..6276b996045c 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java @@ -21,11 +21,11 @@ import android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback; import android.hardware.soundtrigger.V2_3.ModelParameterRange; import android.hardware.soundtrigger.V2_3.Properties; import android.hardware.soundtrigger.V2_3.RecognitionConfig; +import android.media.soundtrigger_middleware.RecognitionStatus; import android.media.soundtrigger_middleware.Status; import android.os.DeadObjectException; import android.os.IHwBinder; import android.os.RemoteException; -import android.os.SystemProperties; import android.util.Log; import java.util.HashMap; @@ -39,10 +39,20 @@ import java.util.Map; * The class is thread-safe. */ public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 { - static final String TAG = "SoundTriggerHw2Enforcer"; + private static final String TAG = "SoundTriggerHw2Enforcer"; - final ISoundTriggerHw2 mUnderlying; - Map<Integer, Boolean> mModelStates = new HashMap<>(); + /** The state of a model. */ + private enum ModelState { + /** Model is loaded, but inactive. */ + INACTIVE, + /** Model is active. */ + ACTIVE, + /** A request to stop is being made, which may or may not have been processed yet. */ + PENDING_STOP, + } + + private final ISoundTriggerHw2 mUnderlying; + private final Map<Integer, ModelState> mModelStates = new HashMap<>(); public SoundTriggerHw2Enforcer( ISoundTriggerHw2 underlying) { @@ -59,42 +69,37 @@ public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 { } @Override - public int loadSoundModel(ISoundTriggerHw.SoundModel soundModel, Callback callback, - int cookie) { + public void registerCallback(GlobalCallback callback) { try { - int handle = mUnderlying.loadSoundModel(soundModel, new CallbackEnforcer(callback), - cookie); - synchronized (mModelStates) { - mModelStates.put(handle, false); - } - return handle; + mUnderlying.registerCallback(callback); } catch (RuntimeException e) { throw handleException(e); } } @Override - public int loadPhraseSoundModel(ISoundTriggerHw.PhraseSoundModel soundModel, Callback callback, - int cookie) { + public int loadSoundModel(ISoundTriggerHw.SoundModel soundModel, ModelCallback callback) { try { - int handle = mUnderlying.loadPhraseSoundModel(soundModel, - new CallbackEnforcer(callback), - cookie); synchronized (mModelStates) { - mModelStates.put(handle, false); + int handle = mUnderlying.loadSoundModel(soundModel, + new ModelCallbackEnforcer(callback)); + mModelStates.put(handle, ModelState.INACTIVE); + return handle; } - return handle; } catch (RuntimeException e) { throw handleException(e); } } @Override - public void unloadSoundModel(int modelHandle) { + public int loadPhraseSoundModel(ISoundTriggerHw.PhraseSoundModel soundModel, + ModelCallback callback) { try { - mUnderlying.unloadSoundModel(modelHandle); synchronized (mModelStates) { - mModelStates.remove(modelHandle); + int handle = mUnderlying.loadPhraseSoundModel(soundModel, + new ModelCallbackEnforcer(callback)); + mModelStates.put(handle, ModelState.INACTIVE); + return handle; } } catch (RuntimeException e) { throw handleException(e); @@ -102,11 +107,16 @@ public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 { } @Override - public void stopRecognition(int modelHandle) { + public void unloadSoundModel(int modelHandle) { try { - mUnderlying.stopRecognition(modelHandle); + // This call into the HAL may block on callback processing, thus must be done outside + // of the critical section. After this call returns we are guaranteed to no longer be + // getting unload events for that model. + mUnderlying.unloadSoundModel(modelHandle); synchronized (mModelStates) { - mModelStates.replace(modelHandle, false); + // At this point, the model may have already been removed by a HAL callback, but the + // remove() method is a no-op in this case, so thus safe. + mModelStates.remove(modelHandle); } } catch (RuntimeException e) { throw handleException(e); @@ -114,13 +124,19 @@ public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 { } @Override - public void stopAllRecognitions() { + public void stopRecognition(int modelHandle) { try { - mUnderlying.stopAllRecognitions(); + // This call into the HAL may block on callback processing, thus must be done outside + // of the critical section. After this call returns we are guaranteed to no longer be + // getting stop events for that model. synchronized (mModelStates) { - for (Map.Entry<Integer, Boolean> entry : mModelStates.entrySet()) { - entry.setValue(false); - } + mModelStates.replace(modelHandle, ModelState.PENDING_STOP); + } + mUnderlying.stopRecognition(modelHandle); + synchronized (mModelStates) { + // At this point, the model might have been preemptively unloaded, but replace() + // do nothing when the entry does not exist, so all good. + mModelStates.replace(modelHandle, ModelState.INACTIVE); } } catch (RuntimeException e) { throw handleException(e); @@ -128,16 +144,12 @@ public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 { } @Override - public void startRecognition(int modelHandle, RecognitionConfig config, Callback callback, - int cookie) { - // It is possible that an event will be sent before the HAL returns from the - // startRecognition call, thus it is important to set the state to active before the call. - synchronized (mModelStates) { - mModelStates.replace(modelHandle, true); - } + public void startRecognition(int modelHandle, RecognitionConfig config) { try { - mUnderlying.startRecognition(modelHandle, config, new CallbackEnforcer(callback), - cookie); + synchronized (mModelStates) { + mUnderlying.startRecognition(modelHandle, config); + mModelStates.replace(modelHandle, ModelState.ACTIVE); + } } catch (RuntimeException e) { throw handleException(e); } @@ -194,64 +206,102 @@ public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 { return mUnderlying.interfaceDescriptor(); } - private static RuntimeException handleException(RuntimeException e) { + @Override + public void flushCallbacks() { + mUnderlying.flushCallbacks(); + } + + private RuntimeException handleException(RuntimeException e) { + if (e instanceof RecoverableException) { + throw e; + } if (e.getCause() instanceof DeadObjectException) { // Server is dead, no need to reboot. Log.e(TAG, "HAL died"); throw new RecoverableException(Status.DEAD_OBJECT); } Log.e(TAG, "Exception caught from HAL, rebooting HAL"); - rebootHal(); + reboot(); throw e; } - private static void rebootHal() { - // This property needs to be defined in an init.rc script and trigger a HAL reboot. - SystemProperties.set("sys.audio.restart.hal", "1"); + @Override + public void reboot() { + mUnderlying.reboot(); + } + + @Override + public void detach() { + mUnderlying.detach(); } - private class CallbackEnforcer implements Callback { - private final Callback mUnderlying; + private class ModelCallbackEnforcer implements ModelCallback { + private final ModelCallback mUnderlying; - private CallbackEnforcer( - Callback underlying) { + private ModelCallbackEnforcer( + ModelCallback underlying) { mUnderlying = underlying; } @Override - public void recognitionCallback(ISoundTriggerHwCallback.RecognitionEvent event, - int cookie) { + public void recognitionCallback(ISoundTriggerHwCallback.RecognitionEvent event) { int model = event.header.model; + int status = event.header.status; + synchronized (mModelStates) { - if (!mModelStates.getOrDefault(model, false)) { + ModelState state = mModelStates.get(model); + if (state == null || state == ModelState.INACTIVE) { Log.wtfStack(TAG, "Unexpected recognition event for model: " + model); - rebootHal(); + reboot(); return; } - if (event.header.status - != android.media.soundtrigger_middleware.RecognitionStatus.FORCED) { - mModelStates.replace(model, false); + if (status != RecognitionStatus.FORCED) { + mModelStates.replace(model, ModelState.INACTIVE); } } - mUnderlying.recognitionCallback(event, cookie); + // Always invoke the delegate from outside the critical section. + mUnderlying.recognitionCallback(event); } @Override - public void phraseRecognitionCallback(ISoundTriggerHwCallback.PhraseRecognitionEvent event, - int cookie) { + public void phraseRecognitionCallback( + ISoundTriggerHwCallback.PhraseRecognitionEvent event) { int model = event.common.header.model; + int status = event.common.header.status; synchronized (mModelStates) { - if (!mModelStates.getOrDefault(model, false)) { + ModelState state = mModelStates.get(model); + if (state == null || state == ModelState.INACTIVE) { Log.wtfStack(TAG, "Unexpected recognition event for model: " + model); - rebootHal(); + reboot(); + return; + } + if (status != RecognitionStatus.FORCED) { + mModelStates.replace(model, ModelState.INACTIVE); + } + } + // Always invoke the delegate from outside the critical section. + mUnderlying.phraseRecognitionCallback(event); + } + + @Override + public void modelUnloaded(int modelHandle) { + synchronized (mModelStates) { + ModelState state = mModelStates.get(modelHandle); + if (state == null) { + Log.wtfStack(TAG, "Unexpected unload event for model: " + modelHandle); + reboot(); return; } - if (event.common.header.status - != android.media.soundtrigger_middleware.RecognitionStatus.FORCED) { - mModelStates.replace(model, false); + + if (state == ModelState.ACTIVE) { + Log.wtfStack(TAG, "Trying to unload an active model: " + modelHandle); + reboot(); + return; } + mModelStates.remove(modelHandle); } - mUnderlying.phraseRecognitionCallback(event, cookie); + // Always invoke the delegate from outside the critical section. + mUnderlying.modelUnloaded(modelHandle); } } } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2MaxModelLimiter.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2MaxModelLimiter.java new file mode 100644 index 000000000000..7b1dedd9e346 --- /dev/null +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2MaxModelLimiter.java @@ -0,0 +1,167 @@ +/* + * 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.soundtrigger_middleware; + +import android.annotation.NonNull; +import android.hardware.soundtrigger.V2_1.ISoundTriggerHw; +import android.hardware.soundtrigger.V2_3.ModelParameterRange; +import android.hardware.soundtrigger.V2_3.Properties; +import android.hardware.soundtrigger.V2_3.RecognitionConfig; +import android.media.soundtrigger_middleware.Status; +import android.os.IHwBinder; +import android.os.RemoteException; + +/** + * This is a decorator around ISoundTriggerHw2, which implements enforcement of the maximum number + * of models supported by the HAL, for HAL implementations older than V2.4 that do not support + * rejection of model loading at the HAL layer. + * Since preemptive model unloading has been introduced in V2.4, it should never be used in + * conjunction with this class, hence we don't bother considering preemtive unloading when counting + * the number of currently loaded models. + */ +public class SoundTriggerHw2MaxModelLimiter implements ISoundTriggerHw2 { + private final @NonNull ISoundTriggerHw2 mDelegate; + private final int mMaxModels; + + // This counter is used to enforce the maximum number of loaded models. + private int mNumLoadedModels = 0; + + private GlobalCallback mGlobalCallback; + + public SoundTriggerHw2MaxModelLimiter( + ISoundTriggerHw2 delegate, int maxModels) { + mDelegate = delegate; + this.mMaxModels = maxModels; + } + + @Override + public void reboot() { + mDelegate.reboot(); + } + + @Override + public void detach() { + mDelegate.detach(); + } + + @Override + public Properties getProperties() { + return mDelegate.getProperties(); + } + + @Override + public void registerCallback(GlobalCallback callback) { + mGlobalCallback = callback; + mDelegate.registerCallback(mGlobalCallback); + } + + @Override + public int loadSoundModel(ISoundTriggerHw.SoundModel soundModel, ModelCallback callback) { + synchronized (this) { + if (mNumLoadedModels == mMaxModels) { + throw new RecoverableException(Status.RESOURCE_CONTENTION); + } + int result = mDelegate.loadSoundModel(soundModel, callback); + ++mNumLoadedModels; + return result; + } + } + + @Override + public int loadPhraseSoundModel(ISoundTriggerHw.PhraseSoundModel soundModel, + ModelCallback callback) { + synchronized (this) { + if (mNumLoadedModels == mMaxModels) { + throw new RecoverableException(Status.RESOURCE_CONTENTION); + } + int result = mDelegate.loadPhraseSoundModel(soundModel, callback); + ++mNumLoadedModels; + return result; + } + } + + @Override + public void unloadSoundModel(int modelHandle) { + boolean wasAtMaxCapacity; + synchronized (this) { + wasAtMaxCapacity = mNumLoadedModels-- == mMaxModels; + } + try { + mDelegate.unloadSoundModel(modelHandle); + } catch (Exception e) { + synchronized (this) { + ++mNumLoadedModels; + } + throw e; + } + if (wasAtMaxCapacity) { + // It is legal to invoke callbacks from within unloadSoundModel(). + // See README.md for details. + mGlobalCallback.onResourcesAvailable(); + } + } + + @Override + public void stopRecognition(int modelHandle) { + mDelegate.stopRecognition(modelHandle); + } + + @Override + public void startRecognition(int modelHandle, RecognitionConfig config) { + mDelegate.startRecognition(modelHandle, config); + } + + @Override + public void getModelState(int modelHandle) { + mDelegate.getModelState(modelHandle); + } + + @Override + public int getModelParameter(int modelHandle, int param) { + return mDelegate.getModelParameter(modelHandle, param); + } + + @Override + public void setModelParameter(int modelHandle, int param, int value) { + mDelegate.setModelParameter(modelHandle, param, value); + } + + @Override + public ModelParameterRange queryParameter(int modelHandle, int param) { + return mDelegate.queryParameter(modelHandle, param); + } + + @Override + public boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) { + return mDelegate.linkToDeath(recipient, cookie); + } + + @Override + public boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) { + return mDelegate.unlinkToDeath(recipient); + } + + @Override + public String interfaceDescriptor() throws RemoteException { + return mDelegate.interfaceDescriptor(); + } + + @Override + public void flushCallbacks() { + mDelegate.flushCallbacks(); + } +} diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java index 212f81f72b24..0c0304ccf775 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java @@ -23,7 +23,6 @@ import android.hardware.soundtrigger.V2_3.Properties; import android.hardware.soundtrigger.V2_3.RecognitionConfig; import android.os.IHwBinder; import android.os.RemoteException; -import android.os.SystemProperties; import android.util.Log; import java.util.Objects; @@ -38,10 +37,8 @@ public class SoundTriggerHw2Watchdog implements ISoundTriggerHw2 { private static final long TIMEOUT_MS = 3000; private static final String TAG = "SoundTriggerHw2Watchdog"; - private final @NonNull - ISoundTriggerHw2 mUnderlying; - private final @NonNull - Timer mTimer; + private final @NonNull ISoundTriggerHw2 mUnderlying; + private final @NonNull Timer mTimer; public SoundTriggerHw2Watchdog(@NonNull ISoundTriggerHw2 underlying) { mUnderlying = Objects.requireNonNull(underlying); @@ -56,47 +53,45 @@ public class SoundTriggerHw2Watchdog implements ISoundTriggerHw2 { } @Override - public int loadSoundModel(ISoundTriggerHw.SoundModel soundModel, Callback callback, - int cookie) { + public void registerCallback(GlobalCallback callback) { try (Watchdog ignore = new Watchdog()) { - return mUnderlying.loadSoundModel(soundModel, callback, cookie); + mUnderlying.registerCallback(callback); } } @Override - public int loadPhraseSoundModel(ISoundTriggerHw.PhraseSoundModel soundModel, Callback callback, - int cookie) { + public int loadSoundModel(ISoundTriggerHw.SoundModel soundModel, ModelCallback callback) { try (Watchdog ignore = new Watchdog()) { - return mUnderlying.loadPhraseSoundModel(soundModel, callback, cookie); + return mUnderlying.loadSoundModel(soundModel, callback); } } @Override - public void unloadSoundModel(int modelHandle) { + public int loadPhraseSoundModel(ISoundTriggerHw.PhraseSoundModel soundModel, + ModelCallback callback) { try (Watchdog ignore = new Watchdog()) { - mUnderlying.unloadSoundModel(modelHandle); + return mUnderlying.loadPhraseSoundModel(soundModel, callback); } } @Override - public void stopRecognition(int modelHandle) { + public void unloadSoundModel(int modelHandle) { try (Watchdog ignore = new Watchdog()) { - mUnderlying.stopRecognition(modelHandle); + mUnderlying.unloadSoundModel(modelHandle); } } @Override - public void stopAllRecognitions() { + public void stopRecognition(int modelHandle) { try (Watchdog ignore = new Watchdog()) { - mUnderlying.stopAllRecognitions(); + mUnderlying.stopRecognition(modelHandle); } } @Override - public void startRecognition(int modelHandle, RecognitionConfig config, Callback callback, - int cookie) { + public void startRecognition(int modelHandle, RecognitionConfig config) { try (Watchdog ignore = new Watchdog()) { - mUnderlying.startRecognition(modelHandle, config, callback, cookie); + mUnderlying.startRecognition(modelHandle, config); } } @@ -143,9 +138,19 @@ public class SoundTriggerHw2Watchdog implements ISoundTriggerHw2 { return mUnderlying.interfaceDescriptor(); } - private static void rebootHal() { - // This property needs to be defined in an init.rc script and trigger a HAL reboot. - SystemProperties.set("sys.audio.restart.hal", "1"); + @Override + public void flushCallbacks() { + mUnderlying.flushCallbacks(); + } + + @Override + public void reboot() { + mUnderlying.reboot(); + } + + @Override + public void detach() { + mUnderlying.detach(); } private class Watchdog implements AutoCloseable { @@ -160,7 +165,7 @@ public class SoundTriggerHw2Watchdog implements ISoundTriggerHw2 { @Override public void run() { Log.e(TAG, "HAL deadline expired. Rebooting.", mException); - rebootHal(); + reboot(); } }; mTimer.schedule(mTask, TIMEOUT_MS); diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java index d76b1bf71a1c..9495e01391f0 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java @@ -17,12 +17,9 @@ package com.android.server.soundtrigger_middleware; import android.annotation.NonNull; -import android.hardware.soundtrigger.V2_0.ISoundTriggerHw; import android.media.soundtrigger_middleware.ISoundTriggerCallback; -import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService; import android.media.soundtrigger_middleware.ISoundTriggerModule; import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; -import android.os.IBinder; import android.util.Log; import java.util.ArrayList; @@ -84,15 +81,15 @@ public class SoundTriggerMiddlewareImpl implements ISoundTriggerMiddlewareIntern @NonNull AudioSessionProvider audioSessionProvider) { List<SoundTriggerModule> modules = new ArrayList<>(halFactories.length); - for (int i = 0; i < halFactories.length; ++i) { + for (HalFactory halFactory : halFactories) { try { - modules.add(new SoundTriggerModule(halFactories[i], audioSessionProvider)); + modules.add(new SoundTriggerModule(halFactory, audioSessionProvider)); } catch (Exception e) { Log.e(TAG, "Failed to add a SoundTriggerModule instance", e); } } - mModules = modules.toArray(new SoundTriggerModule[modules.size()]); + mModules = modules.toArray(new SoundTriggerModule[0]); } /** @@ -122,18 +119,4 @@ public class SoundTriggerMiddlewareImpl implements ISoundTriggerMiddlewareIntern ISoundTriggerModule attach(int handle, @NonNull ISoundTriggerCallback callback) { return mModules[handle].attach(callback); } - - @Override - public void setCaptureState(boolean active) { - for (SoundTriggerModule module : mModules) { - module.setExternalCaptureState(active); - } - } - - @Override - public @NonNull - IBinder asBinder() { - throw new UnsupportedOperationException( - "This implementation is not inteded to be used directly with Binder."); - } }
\ No newline at end of file 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 2ef0759719fc..e3dd360ab6fc 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java @@ -57,9 +57,10 @@ import java.util.Objects; * } * } * </code></pre> - * The actual handling of these events is then done inside of {@link #logReturnWithObject(Object, - * String, Object, Object[])}, {@link #logVoidReturnWithObject(Object, String, Object[])} and {@link - * #logExceptionWithObject(Object, String, Exception, Object[])}. + * The actual handling of these events is then done inside of + * {@link #logReturnWithObject(Object, Identity, String, Object, Object[])}, + * {@link #logVoidReturnWithObject(Object, Identity, String, Object[])} and {@link + * #logExceptionWithObject(Object, Identity, String, Exception, Object[])}. */ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInternal, Dumpable { private static final String TAG = "SoundTriggerMiddlewareLogging"; @@ -96,23 +97,6 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt } } - @Override - public void setCaptureState(boolean active) throws RemoteException { - try { - mDelegate.setCaptureState(active); - logVoidReturn("setCaptureState", active); - } catch (Exception e) { - logException("setCaptureState", e, active); - throw e; - } - } - - @Override - public IBinder asBinder() { - throw new UnsupportedOperationException( - "This implementation is not inteded to be used directly with Binder."); - } - // Override toString() in order to have the delegate's ID in it. @Override public String toString() { @@ -322,12 +306,23 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt } @Override - public void onRecognitionAvailabilityChange(boolean available) throws RemoteException { + public void onModelUnloaded(int modelHandle) throws RemoteException { + try { + mCallbackDelegate.onModelUnloaded(modelHandle); + logVoidReturn("onModelUnloaded", modelHandle); + } catch (Exception e) { + logException("onModelUnloaded", e, modelHandle); + throw e; + } + } + + @Override + public void onResourcesAvailable() throws RemoteException { try { - mCallbackDelegate.onRecognitionAvailabilityChange(available); - logVoidReturn("onRecognitionAvailabilityChange", available); + mCallbackDelegate.onResourcesAvailable(); + logVoidReturn("onResourcesAvailable"); } catch (Exception e) { - logException("onRecognitionAvailabilityChange", e, available); + logException("onResourcesAvailable", e); throw e; } } 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 d5ab574b5617..38e4bc272e7c 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java @@ -89,24 +89,12 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware return wrapper.attach(mDelegate.attach(handle, wrapper.getCallbackWrapper())); } - @Override - public void setCaptureState(boolean active) throws RemoteException { - // This is an internal call. No permissions needed. - mDelegate.setCaptureState(active); - } - // Override toString() in order to have the delegate's ID in it. @Override public String toString() { return Objects.toString(mDelegate); } - @Override - public IBinder asBinder() { - throw new UnsupportedOperationException( - "This implementation is not inteded to be used directly with Binder."); - } - /** * Get the identity context, or throws an InternalServerError if it has not been established. * @@ -320,8 +308,13 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware } @Override - public void onRecognitionAvailabilityChange(boolean available) throws RemoteException { - mDelegate.onRecognitionAvailabilityChange(available); + public void onResourcesAvailable() throws RemoteException { + mDelegate.onResourcesAvailable(); + } + + @Override + public void onModelUnloaded(int modelHandle) throws RemoteException { + mDelegate.onModelUnloaded(modelHandle); } @Override diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java index db7a575b08e2..e882f5525c57 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java @@ -34,6 +34,7 @@ import android.media.soundtrigger_middleware.RecognitionConfig; import android.media.soundtrigger_middleware.SoundModel; import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; import android.os.RemoteException; +import android.os.SystemProperties; import android.util.Log; import com.android.server.SystemService; @@ -69,6 +70,8 @@ public class SoundTriggerMiddlewareService extends ISoundTriggerMiddlewareServic static private final String TAG = "SoundTriggerMiddlewareService"; private final @NonNull ISoundTriggerMiddlewareInternal mDelegate; + private static final @NonNull ICaptureStateNotifier mCaptureStateNotifier = + new ExternalCaptureStateTracker(); private final @NonNull Context mContext; /** @@ -79,13 +82,6 @@ public class SoundTriggerMiddlewareService extends ISoundTriggerMiddlewareServic @NonNull Context context) { mDelegate = Objects.requireNonNull(delegate); mContext = context; - new ExternalCaptureStateTracker(active -> { - try { - mDelegate.setCaptureState(active); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - }); } @Override @@ -235,7 +231,12 @@ public class SoundTriggerMiddlewareService extends ISoundTriggerMiddlewareServic HalFactory[] factories = new HalFactory[]{() -> { try { Log.d(TAG, "Connecting to default ISoundTriggerHw"); - return ISoundTriggerHw.getService(true); + return SoundTriggerHw2Compat.create(ISoundTriggerHw.getService(true), + () -> { + // This property needs to be defined in an init.rc script and + // trigger a HAL reboot. + SystemProperties.set("sys.audio.restart.hal", "1"); + }, mCaptureStateNotifier); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } 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 95a30c7f0278..148e90960827 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java @@ -46,10 +46,6 @@ import java.util.HashSet; import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; /** * This is a decorator of an {@link ISoundTriggerMiddlewareService}, which enforces correct usage by @@ -89,7 +85,8 @@ import java.util.concurrent.atomic.AtomicReference; * } * </pre></code> * Following this patterns ensures a consistent and rigorous handling of all aspects associated - * with client-server separation. + * with client-server separation. Notable exceptions are stopRecognition() and unloadModel(), which + * follow slightly more complicated rules for synchronization (see README.md for details). * <p> * <b>Exception handling approach:</b><br> * We make sure all client faults (argument and state validation) happen first, and @@ -123,13 +120,10 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware } } - private AtomicReference<Boolean> mCaptureState = new AtomicReference<>(); - private final @NonNull ISoundTriggerMiddlewareInternal mDelegate; private Map<Integer, ModuleState> mModules; - public SoundTriggerMiddlewareValidation( - @NonNull ISoundTriggerMiddlewareInternal delegate) { + public SoundTriggerMiddlewareValidation(@NonNull ISoundTriggerMiddlewareInternal delegate) { mDelegate = delegate; } @@ -137,8 +131,8 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware * Generic exception handling for exceptions thrown by the underlying implementation. * * Would throw any {@link RecoverableException} as a {@link ServiceSpecificException} (passed - * by Binder to the caller) and <i>any other</i> exception as {@link InternalServerError} - * (<b>not</b> passed by Binder to the caller). + * by Binder to the caller) and <i>any other</i> exception as a {@link ServiceSpecificException} + * with a {@link Status#INTERNAL_ERROR} code. * <p> * Typical usage: * <code><pre> @@ -149,8 +143,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware * } * </pre></code> */ - static @NonNull - RuntimeException handleException(@NonNull Exception e) { + static @NonNull RuntimeException handleException(@NonNull Exception e) { if (e instanceof RecoverableException) { throw new ServiceSpecificException(((RecoverableException) e).errorCode, e.getMessage()); @@ -161,8 +154,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware } @Override - public @NonNull - SoundTriggerModuleDescriptor[] listModules() { + public @NonNull SoundTriggerModuleDescriptor[] listModules() { // Input validation (always valid). synchronized (this) { @@ -223,23 +215,6 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware } } - @Override - public void setCaptureState(boolean active) { - // This is an internal call. No permissions needed. - // - // Normally, we would acquire a lock here. However, we do not access any state here so it - // is safe to not lock. This call is typically done from a different context than all the - // other calls and may result in a deadlock if we lock here (between the audio server and - // the system server). - try { - mDelegate.setCaptureState(active); - } catch (Exception e) { - throw handleException(e); - } finally { - mCaptureState.set(active); - } - } - // Override toString() in order to have the delegate's ID in it. @Override public String toString() { @@ -247,17 +222,8 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware } @Override - public IBinder asBinder() { - throw new UnsupportedOperationException( - "This implementation is not inteded to be used directly with Binder."); - } - - @Override public void dump(PrintWriter pw) { synchronized (this) { - Boolean captureState = mCaptureState.get(); - pw.printf("Capture state is %s\n\n", captureState == null ? "uninitialized" - : (captureState ? "active" : "inactive")); if (mModules != null) { for (int handle : mModules.keySet()) { final ModuleState module = mModules.get(handle); @@ -303,10 +269,14 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware * delivered to the caller (most commonly, for permission reasons). */ INTERCEPTED, + /** + * Model has been preemptively unloaded by the HAL. + */ + PREEMPTED, } /** Activity state. */ - private AtomicInteger mActivityState = new AtomicInteger(Activity.LOADED.ordinal()); + Activity activityState = Activity.LOADED; /** Human-readable description of the model. */ final String description; @@ -316,7 +286,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware * parameter is supported. A null value means it is known to not be supported. A non-null * value indicates the valid value range. */ - private Map<Integer, ModelParameterRange> parameterSupport = new HashMap<>(); + private final Map<Integer, ModelParameterRange> parameterSupport = new HashMap<>(); /** * Check that the given parameter is known to be supported for this model. @@ -351,24 +321,6 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware Preconditions.checkArgumentInRange(value, range.minInclusive, range.maxInclusive, "value"); } - - /** - * Update support state for the given parameter for this model. - * - * @param modelParam The parameter key. - * @param range The parameter value range, or null if not supported. - */ - void updateParameterSupport(int modelParam, @Nullable ModelParameterRange range) { - parameterSupport.put(modelParam, range); - } - - Activity getActivityState() { - return Activity.values()[mActivityState.get()]; - } - - void setActivityState(Activity activity) { - mActivityState.set(activity.ordinal()); - } } /** @@ -377,13 +329,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware */ private class Session extends ISoundTriggerModule.Stub { private ISoundTriggerModule mDelegate; - // While generally all the fields of this class must be changed under a lock, an exception - // is made for the specific case of changing a model state from ACTIVE to LOADED, which - // may happen as result of a recognition callback. This would happen atomically and is - // necessary in order to avoid deadlocks associated with locking from within callbacks - // possibly originating from the audio server. - private @NonNull - ConcurrentMap<Integer, ModelState> mLoadedModels = new ConcurrentHashMap<>(); + private final @NonNull Map<Integer, ModelState> mLoadedModels = new HashMap<>(); private final int mHandle; private ModuleStatus mState = ModuleStatus.ALIVE; private final CallbackWrapper mCallbackWrapper; @@ -451,7 +397,6 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware @Override public void unloadModel(int modelHandle) { // Input validation (always valid). - synchronized (SoundTriggerMiddlewareValidation.this) { // State validation. if (mState == ModuleStatus.DETACHED) { @@ -462,18 +407,24 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware if (modelState == null) { throw new IllegalStateException("Invalid handle: " + modelHandle); } - if (modelState.getActivityState() != ModelState.Activity.LOADED) { + // To avoid race conditions, we treat LOADED and PREEMPTED exactly the same. + if (modelState.activityState != ModelState.Activity.LOADED + && modelState.activityState != ModelState.Activity.PREEMPTED) { throw new IllegalStateException("Model with handle: " + modelHandle + " has invalid state for unloading"); } + } - // From here on, every exception isn't client's fault. - try { - mDelegate.unloadModel(modelHandle); - mLoadedModels.remove(modelHandle); - } catch (Exception e) { - throw handleException(e); - } + // From here on, every exception isn't client's fault. + try { + // Calling the delegate must be done outside the lock. + mDelegate.unloadModel(modelHandle); + } catch (Exception e) { + throw handleException(e); + } + + synchronized (SoundTriggerMiddlewareValidation.this) { + mLoadedModels.remove(modelHandle); } } @@ -492,20 +443,19 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware if (modelState == null) { throw new IllegalStateException("Invalid handle: " + modelHandle); } - if (modelState.getActivityState() != ModelState.Activity.LOADED) { + ModelState.Activity activityState = modelState.activityState; + // To avoid race conditions, we treat LOADED and PREEMPTED exactly the same. + if (activityState != ModelState.Activity.LOADED + && activityState != ModelState.Activity.PREEMPTED) { throw new IllegalStateException("Model with handle: " + modelHandle + " has invalid state for starting recognition"); } // From here on, every exception isn't client's fault. try { - // Normally, we would set the state after the operation succeeds. However, since - // the activity state may be reset outside of the lock, we set it here first, - // and reset it in case of exception. - modelState.setActivityState(ModelState.Activity.ACTIVE); mDelegate.startRecognition(modelHandle, config); + modelState.activityState = ModelState.Activity.ACTIVE; } catch (Exception e) { - modelState.setActivityState(ModelState.Activity.LOADED); throw handleException(e); } } @@ -529,17 +479,36 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware // From here on, every exception isn't client's fault. try { - // If the activity state is LOADED or INTERCEPTED, we skip delegating the - // command, but still consider the call valid. In either case, the resulting - // state is LOADED. - if (modelState.getActivityState() == ModelState.Activity.ACTIVE) { - mDelegate.stopRecognition(modelHandle); + // If the activity state is INTERCEPTED, we skip delegating the command, but + // still consider the call valid. + if (modelState.activityState == ModelState.Activity.INTERCEPTED) { + modelState.activityState = ModelState.Activity.LOADED; + return; } - modelState.setActivityState(ModelState.Activity.LOADED); } catch (Exception e) { throw handleException(e); } } + + // Calling the delegate's stop must be done without the lock. + try { + mDelegate.stopRecognition(modelHandle); + } catch (Exception e) { + throw handleException(e); + } + + synchronized (SoundTriggerMiddlewareValidation.this) { + ModelState modelState = mLoadedModels.get(modelHandle); + if (modelState == null) { + // The model was unloaded while we let go of the lock. + return; + } + + // After the call, the state is LOADED, unless it has been first preempted. + if (modelState.activityState != ModelState.Activity.PREEMPTED) { + modelState.activityState = ModelState.Activity.LOADED; + } + } } @Override @@ -562,7 +531,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware try { // If the activity state is LOADED or INTERCEPTED, we skip delegating the // command, but still consider the call valid. - if (modelState.getActivityState() == ModelState.Activity.ACTIVE) { + if (modelState.activityState == ModelState.Activity.ACTIVE) { mDelegate.forceRecognitionEvent(modelHandle); } } catch (Exception e) { @@ -644,7 +613,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware try { ModelParameterRange result = mDelegate.queryModelParameterSupport(modelHandle, modelParam); - modelState.updateParameterSupport(modelParam, result); + modelState.parameterSupport.put(modelParam, result); return result; } catch (Exception e) { throw handleException(e); @@ -702,7 +671,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware for (Map.Entry<Integer, ModelState> entry : mLoadedModels.entrySet()) { pw.print(entry.getKey()); pw.print('\t'); - pw.print(entry.getValue().getActivityState().name()); + pw.print(entry.getValue().activityState.name()); pw.print('\t'); pw.print(entry.getValue().description); pw.println(); @@ -732,70 +701,78 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware } @Override - public void onRecognition(int modelHandle, @NonNull RecognitionEvent event) { - // We cannot obtain a lock on SoundTriggerMiddlewareValidation.this, since this call - // might be coming from the audio server (via setCaptureState()) while it is holding - // a lock that is also acquired while loading / unloading models. Thus, we require a - // strict locking order here, where obtaining our lock must always come first. - // To avoid this problem, we use an atomic model activity state. There is a risk of the - // model not being in the mLoadedModels map here, since it might have been stopped / - // unloaded while the event was in flight. - ModelState modelState = mLoadedModels.get(modelHandle); - if (modelState != null) { - if (event.status != RecognitionStatus.FORCED) { - modelState.setActivityState(ModelState.Activity.LOADED); + public void onRecognition(int modelHandle, @NonNull RecognitionEvent event) { + synchronized (SoundTriggerMiddlewareValidation.this) { + ModelState modelState = mLoadedModels.get(modelHandle); + if (event.status != RecognitionStatus.FORCED) { + modelState.activityState = ModelState.Activity.LOADED; + } } + + // Calling the delegate callback must be done outside the lock. try { mCallback.onRecognition(modelHandle, event); } catch (Exception e) { - // Dead client will be handled by binderDied() - no need to handle here. - // In any case, client callbacks are considered best effort. - Log.e(TAG, "Client callback exception.", e); - if (event.status != RecognitionStatus.FORCED) { - modelState.setActivityState(ModelState.Activity.INTERCEPTED); + Log.w(TAG, "Client callback exception.", e); + synchronized (SoundTriggerMiddlewareValidation.this) { + ModelState modelState = mLoadedModels.get(modelHandle); + if (event.status != RecognitionStatus.FORCED) { + modelState.activityState = ModelState.Activity.INTERCEPTED; + } } } } - } - @Override - public void onPhraseRecognition(int modelHandle, @NonNull PhraseRecognitionEvent event) { - // We cannot obtain a lock on SoundTriggerMiddlewareValidation.this, since this call - // might be coming from the audio server (via setCaptureState()) while it is holding - // a lock that is also acquired while loading / unloading models. Thus, we require a - // strict locking order here, where obtaining our lock must always come first. - // To avoid this problem, we use an atomic model activity state. There is a risk of the - // model not being in the mLoadedModels map here, since it might have been stopped / - // unloaded while the event was in flight. - ModelState modelState = mLoadedModels.get(modelHandle); - if (modelState != null) { - if (event.common.status != RecognitionStatus.FORCED) { - modelState.setActivityState(ModelState.Activity.LOADED); + @Override + public void onPhraseRecognition(int modelHandle, + @NonNull PhraseRecognitionEvent event) { + synchronized (SoundTriggerMiddlewareValidation.this) { + ModelState modelState = mLoadedModels.get(modelHandle); + if (event.common.status != RecognitionStatus.FORCED) { + modelState.activityState = ModelState.Activity.LOADED; + } } + + // Calling the delegate callback must be done outside the lock. try { mCallback.onPhraseRecognition(modelHandle, event); } catch (Exception e) { - // Dead client will be handled by binderDied() - no need to handle here. - // In any case, client callbacks are considered best effort. - Log.e(TAG, "Client callback exception.", e); - if (event.common.status != RecognitionStatus.FORCED) { - modelState.setActivityState(ModelState.Activity.INTERCEPTED); + Log.w(TAG, "Client callback exception.", e); + synchronized (SoundTriggerMiddlewareValidation.this) { + ModelState modelState = mLoadedModels.get(modelHandle); + if (event.common.status != RecognitionStatus.FORCED) { + modelState.activityState = ModelState.Activity.INTERCEPTED; + } } } } - } - @Override - public void onRecognitionAvailabilityChange(boolean available) { - // Not locking to avoid deadlocks (not affecting any state). - try { - mCallback.onRecognitionAvailabilityChange(available); - } catch (RemoteException e) { - // Dead client will be handled by binderDied() - no need to handle here. - // In any case, client callbacks are considered best effort. - Log.e(TAG, "Client callback exception.", e); + @Override + public void onModelUnloaded(int modelHandle) { + synchronized (SoundTriggerMiddlewareValidation.this) { + ModelState modelState = mLoadedModels.get(modelHandle); + modelState.activityState = ModelState.Activity.PREEMPTED; + } + + // Calling the delegate callback must be done outside the lock. + try { + mCallback.onModelUnloaded(modelHandle); + } catch (Exception e) { + Log.w(TAG, "Client callback exception.", e); + } + } + + @Override + public void onResourcesAvailable() { + // Not locking to avoid deadlocks (not affecting any state). + try { + mCallback.onResourcesAvailable(); + } catch (RemoteException e) { + // Dead client will be handled by binderDied() - no need to handle here. + // In any case, client callbacks are considered best effort. + Log.e(TAG, "Client callback exception.", e); + } } - } @Override public void onModuleDied() { @@ -820,8 +797,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware // Gracefully stop all active recognitions and unload the models. for (Map.Entry<Integer, ModelState> entry : mLoadedModels.entrySet()) { - if (entry.getValue().getActivityState() - == ModelState.Activity.ACTIVE) { + if (entry.getValue().activityState == ModelState.Activity.ACTIVE) { mDelegate.stopRecognition(entry.getKey()); } mDelegate.unloadModel(entry.getKey()); diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java index 02d978dfdf99..32e95755b31c 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java @@ -24,13 +24,11 @@ import android.media.soundtrigger_middleware.ISoundTriggerCallback; import android.media.soundtrigger_middleware.ISoundTriggerModule; import android.media.soundtrigger_middleware.ModelParameterRange; import android.media.soundtrigger_middleware.PhraseRecognitionEvent; -import android.media.soundtrigger_middleware.PhraseRecognitionExtra; import android.media.soundtrigger_middleware.PhraseSoundModel; import android.media.soundtrigger_middleware.RecognitionConfig; import android.media.soundtrigger_middleware.RecognitionEvent; import android.media.soundtrigger_middleware.RecognitionStatus; import android.media.soundtrigger_middleware.SoundModel; -import android.media.soundtrigger_middleware.SoundModelType; import android.media.soundtrigger_middleware.SoundTriggerModuleProperties; import android.media.soundtrigger_middleware.Status; import android.os.IBinder; @@ -41,7 +39,6 @@ import android.util.Log; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -88,15 +85,13 @@ import java.util.Set; * * @hide */ -class SoundTriggerModule implements IHwBinder.DeathRecipient { +class SoundTriggerModule implements IHwBinder.DeathRecipient, ISoundTriggerHw2.GlobalCallback { static private final String TAG = "SoundTriggerModule"; - @NonNull private HalFactory mHalFactory; + @NonNull private final HalFactory mHalFactory; @NonNull private ISoundTriggerHw2 mHalService; @NonNull private final SoundTriggerMiddlewareImpl.AudioSessionProvider mAudioSessionProvider; private final Set<Session> mActiveSessions = new HashSet<>(); - private int mNumLoadedModels = 0; - private SoundTriggerModuleProperties mProperties; - private boolean mRecognitionAvailable; + private final SoundTriggerModuleProperties mProperties; /** * Ctor. @@ -111,8 +106,6 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { attachToHal(); mProperties = ConversionUtil.hidl2aidlProperties(mHalService.getProperties()); - // We conservatively assume that external capture is active until explicitly told otherwise. - mRecognitionAvailable = mProperties.concurrentCapture; } /** @@ -144,46 +137,9 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { return mProperties; } - /** - * Notify the module that external capture has started / finished, using the same input device - * used for recognition. - * If the underlying driver does not support recognition while capturing, capture will be - * aborted, and the recognition callback will receive and abort event. In addition, all active - * clients will be notified of the change in state. - * - * @param active true iff external capture is active. - */ - void setExternalCaptureState(boolean active) { - // We should never invoke callbacks while holding the lock, since this may deadlock with - // forward calls. Thus, we first gather all the callbacks we need to invoke while holding - // the lock, but invoke them after releasing it. - List<Runnable> callbacks = new LinkedList<>(); - - synchronized (this) { - if (mProperties.concurrentCapture) { - // If we support concurrent capture, we don't care about any of this. - return; - } - mRecognitionAvailable = !active; - if (!mRecognitionAvailable) { - // Our module does not support recognition while a capture is active - - // need to abort all active recognitions. - for (Session session : mActiveSessions) { - session.abortActiveRecognitions(callbacks); - } - } - } - for (Runnable callback : callbacks) { - callback.run(); - } - for (Session session : mActiveSessions) { - session.notifyRecognitionAvailability(); - } - } - @Override public void serviceDied(long cookie) { - Log.w(TAG, String.format("Underlying HAL driver died.")); + Log.w(TAG, "Underlying HAL driver died."); List<ISoundTriggerCallback> callbacks; synchronized (this) { callbacks = new ArrayList<>(mActiveSessions.size()); @@ -207,10 +163,8 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { * Resets the transient state of this object. */ private void reset() { + mHalService.detach(); attachToHal(); - // We conservatively assume that external capture is active until explicitly told otherwise. - mRecognitionAvailable = mProperties.concurrentCapture; - mNumLoadedModels = 0; } /** @@ -218,9 +172,9 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { */ private void attachToHal() { mHalService = new SoundTriggerHw2Enforcer( - new SoundTriggerHw2Watchdog( - new SoundTriggerHw2Compat(mHalFactory.create()))); + new SoundTriggerHw2Watchdog(mHalFactory.create())); mHalService.linkToDeath(this, 0); + mHalService.registerCallback(this); } /** @@ -232,6 +186,25 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { mActiveSessions.remove(session); } + @Override + public void onResourcesAvailable() { + List<ISoundTriggerCallback> callbacks; + synchronized (this) { + callbacks = new ArrayList<>(mActiveSessions.size()); + for (Session session : mActiveSessions) { + callbacks.add(session.mCallback); + } + } + // Trigger the callbacks outside of the lock to avoid deadlocks. + for (ISoundTriggerCallback callback : callbacks) { + try { + callback.onResourcesAvailable(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + } + /** State of a single sound model. */ private enum ModelState { /** Initial state, until load() is called. */ @@ -249,7 +222,7 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { */ private class Session implements ISoundTriggerModule { private ISoundTriggerCallback mCallback; - private Map<Integer, Model> mLoadedModels = new HashMap<>(); + private final Map<Integer, Model> mLoadedModels = new HashMap<>(); /** * Ctor. @@ -258,7 +231,6 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { */ private Session(@NonNull ISoundTriggerCallback callback) { mCallback = callback; - notifyRecognitionAvailability(); } @Override @@ -274,95 +246,65 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { @Override public int loadModel(@NonNull SoundModel model) { - // We must do this outside the lock, to avoid possible deadlocks with the remote process - // that provides the audio sessions, which may also be calling into us. - SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession = - mAudioSessionProvider.acquireSession(); - - try { - synchronized (SoundTriggerModule.this) { + synchronized (SoundTriggerModule.this) { + SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession = + mAudioSessionProvider.acquireSession(); + try { checkValid(); - if (mNumLoadedModels == mProperties.maxSoundModels) { - throw new RecoverableException(Status.RESOURCE_CONTENTION, - "Maximum number of models loaded."); - } Model loadedModel = new Model(); - int result = loadedModel.load(model, audioSession); - ++mNumLoadedModels; - return result; - } - } catch (Exception e) { - // We must do this outside the lock, to avoid possible deadlocks with the remote - // process that provides the audio sessions, which may also be calling into us. - try { - mAudioSessionProvider.releaseSession(audioSession.mSessionHandle); - } catch (Exception ee) { - Log.e(TAG, "Failed to release session.", ee); + return loadedModel.load(model, audioSession); + } catch (Exception e) { + // We must do this outside the lock, to avoid possible deadlocks with the remote + // process that provides the audio sessions, which may also be calling into us. + try { + mAudioSessionProvider.releaseSession(audioSession.mSessionHandle); + } catch (Exception ee) { + Log.e(TAG, "Failed to release session.", ee); + } + throw e; } - throw e; } } @Override public int loadPhraseModel(@NonNull PhraseSoundModel model) { - // We must do this outside the lock, to avoid possible deadlocks with the remote process - // that provides the audio sessions, which may also be calling into us. - SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession = - mAudioSessionProvider.acquireSession(); - - try { - synchronized (SoundTriggerModule.this) { + synchronized (SoundTriggerModule.this) { + SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession = + mAudioSessionProvider.acquireSession(); + try { checkValid(); - if (mNumLoadedModels == mProperties.maxSoundModels) { - throw new RecoverableException(Status.RESOURCE_CONTENTION, - "Maximum number of models loaded."); - } Model loadedModel = new Model(); int result = loadedModel.load(model, audioSession); - ++mNumLoadedModels; Log.d(TAG, String.format("loadPhraseModel()->%d", result)); return result; + } catch (Exception e) { + // We must do this outside the lock, to avoid possible deadlocks with the remote + // process that provides the audio sessions, which may also be calling into us. + try { + mAudioSessionProvider.releaseSession(audioSession.mSessionHandle); + } catch (Exception ee) { + Log.e(TAG, "Failed to release session.", ee); + } + throw e; } - } catch (Exception e) { - // We must do this outside the lock, to avoid possible deadlocks with the remote - // process that provides the audio sessions, which may also be calling into us. - try { - mAudioSessionProvider.releaseSession(audioSession.mSessionHandle); - } catch (Exception ee) { - Log.e(TAG, "Failed to release session.", ee); - } - throw e; } } @Override public void unloadModel(int modelHandle) { - int sessionId; synchronized (SoundTriggerModule.this) { + int sessionId; checkValid(); sessionId = mLoadedModels.get(modelHandle).unload(); - --mNumLoadedModels; + mAudioSessionProvider.releaseSession(sessionId); } - - // We must do this outside the lock, to avoid possible deadlocks with the remote process - // that provides the audio sessions, which may also be calling into us. - mAudioSessionProvider.releaseSession(sessionId); } @Override public void startRecognition(int modelHandle, @NonNull RecognitionConfig config) { - // We should never invoke callbacks while holding the lock, since this may deadlock with - // forward calls. Thus, we first gather all the callbacks we need to invoke while holding - // the lock, but invoke them after releasing it. - List<Runnable> callbacks = new LinkedList<>(); - synchronized (SoundTriggerModule.this) { checkValid(); - mLoadedModels.get(modelHandle).startRecognition(config, callbacks); - } - - for (Runnable callback : callbacks) { - callback.run(); + mLoadedModels.get(modelHandle).startRecognition(config); } } @@ -407,27 +349,6 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { } /** - * Abort all currently active recognitions. - * @param callbacks Will be appended with a list of callbacks that need to be invoked - * after this method returns, without holding the module lock. - */ - private void abortActiveRecognitions(@NonNull List<Runnable> callbacks) { - for (Model model : mLoadedModels.values()) { - model.abortActiveRecognition(callbacks); - } - } - - private void notifyRecognitionAvailability() { - try { - mCallback.onRecognitionAvailabilityChange(mRecognitionAvailable); - } catch (RemoteException e) { - // Dead client will be handled by binderDied() - no need to handle here. - // In any case, client callbacks are considered best effort. - Log.e(TAG, "Client callback execption.", e); - } - } - - /** * The underlying module HAL is dead. * @return The client callback that needs to be invoked to notify the client. */ @@ -455,10 +376,9 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { * * All model-based operations are delegated to this class and implemented here. */ - private class Model implements ISoundTriggerHw2.Callback { + private class Model implements ISoundTriggerHw2.ModelCallback { public int mHandle; private ModelState mState = ModelState.INIT; - private int mModelType = SoundModelType.UNKNOWN; private SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession mSession; private @NonNull @@ -473,11 +393,10 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { private int load(@NonNull SoundModel model, SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession) { - mModelType = model.type; mSession = audioSession; ISoundTriggerHw.SoundModel hidlModel = ConversionUtil.aidl2hidlSoundModel(model); - mHandle = mHalService.loadSoundModel(hidlModel, this, 0); + mHandle = mHalService.loadSoundModel(hidlModel, this); setState(ModelState.LOADED); mLoadedModels.put(mHandle, this); return mHandle; @@ -485,12 +404,11 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { private int load(@NonNull PhraseSoundModel model, SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession) { - mModelType = model.common.type; mSession = audioSession; ISoundTriggerHw.PhraseSoundModel hidlModel = ConversionUtil.aidl2hidlPhraseSoundModel(model); - mHandle = mHalService.loadPhraseSoundModel(hidlModel, this, 0); + mHandle = mHalService.loadPhraseSoundModel(hidlModel, this); setState(ModelState.LOADED); mLoadedModels.put(mHandle, this); @@ -507,18 +425,12 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { return mSession.mSessionHandle; } - private void startRecognition(@NonNull RecognitionConfig config, - @NonNull List<Runnable> callbacks) { - if (!mRecognitionAvailable) { - // Recognition is unavailable - send an abort event immediately. - callbacks.add(this::notifyAbort); - return; - } + private void startRecognition(@NonNull RecognitionConfig config) { android.hardware.soundtrigger.V2_3.RecognitionConfig hidlConfig = ConversionUtil.aidl2hidlRecognitionConfig(config); hidlConfig.base.header.captureDevice = mSession.mDeviceHandle; hidlConfig.base.header.captureHandle = mSession.mIoHandle; - mHalService.startRecognition(mHandle, hidlConfig, this, 0); + mHalService.startRecognition(mHandle, hidlConfig); setState(ModelState.ACTIVE); } @@ -558,62 +470,10 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { ConversionUtil.aidl2hidlModelParameter(modelParam))); } - /** - * Abort the recognition, if active. - * @param callbacks Will be appended with a list of callbacks that need to be invoked - * after this method returns, without holding the module lock. - */ - private void abortActiveRecognition(List<Runnable> callbacks) { - // If we're inactive, do nothing. - if (getState() != ModelState.ACTIVE) { - return; - } - // Stop recognition. - stopRecognition(); - - // Notify the client that recognition has been aborted. - callbacks.add(this::notifyAbort); - } - - /** Notify the client that recognition has been aborted. */ - private void notifyAbort() { - try { - switch (mModelType) { - case SoundModelType.GENERIC: { - android.media.soundtrigger_middleware.RecognitionEvent event = - newEmptyRecognitionEvent(); - event.status = - android.media.soundtrigger_middleware.RecognitionStatus.ABORTED; - event.type = SoundModelType.GENERIC; - mCallback.onRecognition(mHandle, event); - } - break; - - case SoundModelType.KEYPHRASE: { - android.media.soundtrigger_middleware.PhraseRecognitionEvent event = - newEmptyPhraseRecognitionEvent(); - event.common.status = - android.media.soundtrigger_middleware.RecognitionStatus.ABORTED; - event.common.type = SoundModelType.KEYPHRASE; - mCallback.onPhraseRecognition(mHandle, event); - } - break; - - default: - Log.e(TAG, "Unknown model type: " + mModelType); - - } - } catch (RemoteException e) { - // Dead client will be handled by binderDied() - no need to handle here. - // In any case, client callbacks are considered best effort. - Log.e(TAG, "Client callback execption.", e); - } - } - @Override public void recognitionCallback( - @NonNull ISoundTriggerHwCallback.RecognitionEvent recognitionEvent, - int cookie) { + @NonNull ISoundTriggerHwCallback.RecognitionEvent recognitionEvent) { + ISoundTriggerCallback callback; RecognitionEvent aidlEvent = ConversionUtil.hidl2aidlRecognitionEvent(recognitionEvent); aidlEvent.captureSession = mSession.mSessionHandle; @@ -621,10 +481,13 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { if (aidlEvent.status != RecognitionStatus.FORCED) { setState(ModelState.LOADED); } + callback = mCallback; } // The callback must be invoked outside of the lock. try { - mCallback.onRecognition(mHandle, aidlEvent); + if (callback != null) { + callback.onRecognition(mHandle, aidlEvent); + } } catch (RemoteException e) { // We're not expecting any exceptions here. throw e.rethrowAsRuntimeException(); @@ -633,8 +496,8 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { @Override public void phraseRecognitionCallback( - @NonNull ISoundTriggerHwCallback.PhraseRecognitionEvent phraseRecognitionEvent, - int cookie) { + @NonNull ISoundTriggerHwCallback.PhraseRecognitionEvent phraseRecognitionEvent) { + ISoundTriggerCallback callback; PhraseRecognitionEvent aidlEvent = ConversionUtil.hidl2aidlPhraseRecognitionEvent(phraseRecognitionEvent); aidlEvent.common.captureSession = mSession.mSessionHandle; @@ -643,45 +506,37 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { if (aidlEvent.common.status != RecognitionStatus.FORCED) { setState(ModelState.LOADED); } + callback = mCallback; } // The callback must be invoked outside of the lock. try { - mCallback.onPhraseRecognition(mHandle, aidlEvent); + if (callback != null) { + mCallback.onPhraseRecognition(mHandle, aidlEvent); + } } catch (RemoteException e) { // We're not expecting any exceptions here. throw e.rethrowAsRuntimeException(); } } - } - } - /** - * Creates a default-initialized recognition event. - * - * Non-nullable object fields are default constructed. - * Non-nullable array fields are initialized to 0 length. - * - * @return The event. - */ - private static RecognitionEvent newEmptyRecognitionEvent() { - RecognitionEvent result = new RecognitionEvent(); - result.data = new byte[0]; - return result; - } + @Override + public void modelUnloaded(int modelHandle) { + ISoundTriggerCallback callback; + synchronized (SoundTriggerModule.this) { + callback = mCallback; + } - /** - * Creates a default-initialized phrase recognition event. - * - * Non-nullable object fields are default constructed. - * Non-nullable array fields are initialized to 0 length. - * - * @return The event. - */ - private static PhraseRecognitionEvent newEmptyPhraseRecognitionEvent() { - PhraseRecognitionEvent result = new PhraseRecognitionEvent(); - result.common = newEmptyRecognitionEvent(); - result.phraseExtras = new PhraseRecognitionExtra[0]; - return result; + // The callback must be invoked outside of the lock. + try { + if (callback != null) { + callback.onModelUnloaded(modelHandle); + } + } catch (RemoteException e) { + // We're not expecting any exceptions here. + throw e.rethrowAsRuntimeException(); + } + } + } } } diff --git a/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java b/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java index c0c9e6d58622..8e4a18243a00 100644 --- a/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java +++ b/services/core/java/com/android/server/timezonedetector/location/BinderLocationTimeZoneProvider.java @@ -47,7 +47,7 @@ class BinderLocationTimeZoneProvider extends LocationTimeZoneProvider { @NonNull ThreadingDomain threadingDomain, @NonNull String providerName, @NonNull LocationTimeZoneProviderProxy proxy) { - super(threadingDomain, providerName); + super(threadingDomain, providerName, new ZoneInfoDbTimeZoneIdValidator()); mProxy = Objects.requireNonNull(proxy); } diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java index 0d1692a8781d..588382158bc9 100644 --- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java +++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java @@ -520,6 +520,12 @@ public class LocationTimeZoneManagerService extends Binder { } } + static void infoLog(String msg) { + if (Log.isLoggable(TAG, Log.INFO)) { + Slog.i(TAG, msg); + } + } + static void warnLog(String msg) { warnLog(msg, null); } diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java index ef2f357b8c3e..b97c838017eb 100644 --- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java +++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneProvider.java @@ -20,6 +20,7 @@ import static android.service.timezone.TimeZoneProviderService.TEST_COMMAND_RESU import static android.service.timezone.TimeZoneProviderService.TEST_COMMAND_RESULT_SUCCESS_KEY; import static com.android.server.timezonedetector.location.LocationTimeZoneManagerService.debugLog; +import static com.android.server.timezonedetector.location.LocationTimeZoneManagerService.infoLog; import static com.android.server.timezonedetector.location.LocationTimeZoneManagerService.warnLog; import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DESTROYED; import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED; @@ -85,6 +86,18 @@ abstract class LocationTimeZoneProvider implements Dumpable { } /** + * Used by {@link LocationTimeZoneProvider} to check if time zone IDs are understood + * by the platform. + */ + interface TimeZoneIdValidator { + + /** + * Returns whether {@code timeZoneId} is supported by the platform or not. + */ + boolean isValid(@NonNull String timeZoneId); + } + + /** * Information about the provider's current state. */ static class ProviderState { @@ -364,13 +377,17 @@ abstract class LocationTimeZoneProvider implements Dumpable { // Non-null and effectively final after initialize() is called. ProviderListener mProviderListener; + @NonNull private TimeZoneIdValidator mTimeZoneIdValidator; + /** Creates the instance. */ LocationTimeZoneProvider(@NonNull ThreadingDomain threadingDomain, - @NonNull String providerName) { + @NonNull String providerName, + @NonNull TimeZoneIdValidator timeZoneIdValidator) { mThreadingDomain = Objects.requireNonNull(threadingDomain); mInitializationTimeoutQueue = threadingDomain.createSingleRunnableQueue(); mSharedLock = threadingDomain.getLockObject(); mProviderName = Objects.requireNonNull(providerName); + mTimeZoneIdValidator = Objects.requireNonNull(timeZoneIdValidator); } /** @@ -610,6 +627,25 @@ abstract class LocationTimeZoneProvider implements Dumpable { mThreadingDomain.assertCurrentThread(); Objects.requireNonNull(timeZoneProviderEvent); + // If the provider has made a suggestion with unknown time zone IDs it cannot be used to set + // the device's time zone. This logic prevents bad time zone IDs entering the time zone + // detection logic from third party code. + // + // An event containing an unknown time zone ID could occur if the provider is using a + // different TZDB version than the device. Provider developers are expected to take steps to + // avoid version skew problem, e.g. by ensuring atomic updates with the platform time zone + // rules, or providing IDs based on the device's TZDB version, so this is not considered a + // common case. + // + // Treating a suggestion containing unknown time zone IDs as "uncertain" in the primary + // enables immediate failover to a secondary provider, one that might provide valid IDs for + // the same location, which should provide better behavior than just ignoring the event. + if (hasInvalidTimeZones(timeZoneProviderEvent)) { + infoLog("event=" + timeZoneProviderEvent + " has unsupported time zones. " + + "Replacing it with uncertain event."); + timeZoneProviderEvent = TimeZoneProviderEvent.createUncertainEvent(); + } + synchronized (mSharedLock) { debugLog("handleTimeZoneProviderEvent: mProviderName=" + mProviderName + ", timeZoneProviderEvent=" + timeZoneProviderEvent); @@ -707,6 +743,20 @@ abstract class LocationTimeZoneProvider implements Dumpable { } } + private boolean hasInvalidTimeZones(@NonNull TimeZoneProviderEvent event) { + if (event.getSuggestion() == null) { + return false; + } + + for (String timeZone : event.getSuggestion().getTimeZoneIds()) { + if (!mTimeZoneIdValidator.isValid(timeZone)) { + return true; + } + } + + return false; + } + @GuardedBy("mSharedLock") private void assertIsStarted() { ProviderState currentState = mCurrentState.get(); diff --git a/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidator.java b/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidator.java new file mode 100644 index 000000000000..cab5ad25c54e --- /dev/null +++ b/services/core/java/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidator.java @@ -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.server.timezonedetector.location; + +import android.annotation.NonNull; + +import com.android.i18n.timezone.ZoneInfoDb; + +class ZoneInfoDbTimeZoneIdValidator implements + LocationTimeZoneProvider.TimeZoneIdValidator { + + @Override + public boolean isValid(@NonNull String timeZoneId) { + return ZoneInfoDb.getInstance().hasTimeZone(timeZoneId); + } +} diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java index 5723e1dcceb5..ee30fa2ac928 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java @@ -50,8 +50,6 @@ public final class ClientProfile { */ private final int mProcessId; - private boolean mIsForeground; - /** * All the clients that share the same resource would be under the same group id. * @@ -90,6 +88,12 @@ public final class ClientProfile { private int mUsingCiCamId = INVALID_RESOURCE_ID; /** + * If the priority is overwritten through + * {@link TunerResourceManagerService#setPriority(int, int)}. + */ + private boolean mIsPriorityOverwritten = false; + + /** * Optional arbitrary priority value given by the client. * * <p>This value can override the default priorotiy calculated from @@ -121,17 +125,10 @@ public final class ClientProfile { } /** - * Set the current isForeground status. - */ - public void setForeground(boolean isForeground) { - mIsForeground = isForeground; - } - - /** - * Get the previous recorded isForeground status. + * If the client priority is overwrttien. */ - public boolean isForeground() { - return mIsForeground; + public boolean isPriorityOverwritten() { + return mIsPriorityOverwritten; } public int getGroupId() { @@ -153,6 +150,17 @@ public final class ClientProfile { mPriority = priority; } + /** + * Overwrite the client priority. + */ + public void overwritePriority(int priority) { + if (priority < 0) { + return; + } + mIsPriorityOverwritten = true; + mPriority = priority; + } + public void setNiceValue(int niceValue) { mNiceValue = niceValue; } diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java index 988582da53ea..0c04b075485a 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java @@ -507,9 +507,8 @@ public class TunerResourceManagerService extends SystemService implements IBinde .useCase(profile.useCase) .processId(pid) .build(); - clientProfile.setForeground(checkIsForeground(pid)); clientProfile.setPriority( - getClientPriority(profile.useCase, clientProfile.isForeground())); + getClientPriority(profile.useCase, checkIsForeground(pid))); addClientProfile(clientId[0], clientProfile, listener); } @@ -547,8 +546,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde return false; } - profile.setForeground(checkIsForeground(profile.getProcessId())); - profile.setPriority(priority); + profile.overwritePriority(priority); profile.setNiceValue(niceValue); return true; @@ -694,7 +692,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde } else if (grantingFrontendHandle == TunerResourceManager.INVALID_RESOURCE_HANDLE) { // Record the frontend id with the lowest client priority among all the // in use frontends when no available frontend has been found. - int priority = getOwnerClientPriority(fr.getOwnerClientId()); + int priority = updateAndGetOwnerClientPriority(fr.getOwnerClientId()); if (currentLowestPriority > priority) { inUseLowestPriorityFrHandle = fr.getHandle(); currentLowestPriority = priority; @@ -760,7 +758,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde } else { // Record the lnb id with the lowest client priority among all the // in use lnb when no available lnb has been found. - int priority = getOwnerClientPriority(lnb.getOwnerClientId()); + int priority = updateAndGetOwnerClientPriority(lnb.getOwnerClientId()); if (currentLowestPriority > priority) { inUseLowestPriorityLnbHandle = lnb.getHandle(); currentLowestPriority = priority; @@ -818,7 +816,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde } for (int ownerId : cas.getOwnerClientIds()) { // Record the client id with lowest priority that is using the current Cas system. - int priority = getOwnerClientPriority(ownerId); + int priority = updateAndGetOwnerClientPriority(ownerId); if (currentLowestPriority > priority) { lowestPriorityOwnerId = ownerId; currentLowestPriority = priority; @@ -867,7 +865,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde } for (int ownerId : ciCam.getOwnerClientIds()) { // Record the client id with lowest priority that is using the current Cas system. - int priority = getOwnerClientPriority(ownerId); + int priority = updateAndGetOwnerClientPriority(ownerId); if (currentLowestPriority > priority) { lowestPriorityOwnerId = ownerId; currentLowestPriority = priority; @@ -966,18 +964,17 @@ public class TunerResourceManagerService extends SystemService implements IBinde } @VisibleForTesting - // This mothod is to sync up the request client's foreground/background status and update - // the client priority accordingly whenever new resource request comes in. - protected void clientPriorityUpdateOnRequest(ClientProfile requestProfile) { - int pid = requestProfile.getProcessId(); - boolean currentIsForeground = checkIsForeground(pid); - if (requestProfile.isForeground() == currentIsForeground) { + // This mothod is to sync up the request/holder client's foreground/background status and update + // the client priority accordingly whenever a new resource request comes in. + protected void clientPriorityUpdateOnRequest(ClientProfile profile) { + if (profile.isPriorityOverwritten()) { // To avoid overriding the priority set through updateClientPriority API. return; } - requestProfile.setForeground(currentIsForeground); - requestProfile.setPriority( - getClientPriority(requestProfile.getUseCase(), currentIsForeground)); + int pid = profile.getProcessId(); + boolean currentIsForeground = checkIsForeground(pid); + profile.setPriority( + getClientPriority(profile.getUseCase(), currentIsForeground)); } @VisibleForTesting @@ -1154,13 +1151,15 @@ public class TunerResourceManagerService extends SystemService implements IBinde } /** - * Get the owner client's priority. + * Update and get the owner client's priority. * * @param clientId the owner client id. * @return the priority of the owner client. */ - private int getOwnerClientPriority(int clientId) { - return getClientProfile(clientId).getPriority(); + private int updateAndGetOwnerClientPriority(int clientId) { + ClientProfile profile = getClientProfile(clientId); + clientPriorityUpdateOnRequest(profile); + return profile.getPriority(); } @VisibleForTesting diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index a3dadd835202..9abe5b65bc5e 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -8811,6 +8811,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return null; } final ComponentName supervisorComponent = ComponentName.unflattenFromString(supervisor); + if (supervisorComponent == null) { + return null; + } if (supervisorComponent.equals(doComponent) || supervisorComponent.equals( poComponent)) { return supervisorComponent; diff --git a/services/musicrecognition/java/com/android/server/musicrecognition/MusicRecognitionManagerPerUserService.java b/services/musicrecognition/java/com/android/server/musicrecognition/MusicRecognitionManagerPerUserService.java index 87b2c84a30f7..4c5bbebdfd45 100644 --- a/services/musicrecognition/java/com/android/server/musicrecognition/MusicRecognitionManagerPerUserService.java +++ b/services/musicrecognition/java/com/android/server/musicrecognition/MusicRecognitionManagerPerUserService.java @@ -48,6 +48,8 @@ import com.android.server.infra.AbstractPerUserSystemService; import java.io.IOException; import java.io.OutputStream; import java.util.Objects; +import java.util.concurrent.CompletableFuture; + /** * Handles per-user requests received by @@ -60,6 +62,11 @@ public final class MusicRecognitionManagerPerUserService extends implements RemoteMusicRecognitionService.Callbacks { private static final String TAG = MusicRecognitionManagerPerUserService.class.getSimpleName(); + private static final String MUSIC_RECOGNITION_MANAGER_ATTRIBUTION_TAG = + "MusicRecognitionManagerService"; + private static final String KEY_MUSIC_RECOGNITION_SERVICE_ATTRIBUTION_TAG = + "android.media.musicrecognition.attributiontag"; + // Number of bytes per sample of audio (which is a short). private static final int BYTES_PER_SAMPLE = 2; private static final int MAX_STREAMING_SECONDS = 24; @@ -68,18 +75,24 @@ public final class MusicRecognitionManagerPerUserService extends @GuardedBy("mLock") private RemoteMusicRecognitionService mRemoteService; private final AppOpsManager mAppOpsManager; + private final String mAttributionMessage; - private String mAttributionTag; - private String mAttributionMessage; + // Service info of the remote MusicRecognitionService (which the audio gets forwarded to). private ServiceInfo mServiceInfo; + private CompletableFuture<String> mAttributionTagFuture; MusicRecognitionManagerPerUserService( @NonNull MusicRecognitionManagerService primary, @NonNull Object lock, int userId) { super(primary, lock, userId); - mAppOpsManager = getContext().getSystemService(AppOpsManager.class); + + // When attributing audio-access, this establishes that audio access is performed by + // MusicRecognitionManager (on behalf of the receiving service, whose attribution tag, + // provided by mAttributionTagFuture, is used for the actual calls to startProxyOp(...). + mAppOpsManager = getContext().createAttributionContext( + MUSIC_RECOGNITION_MANAGER_ATTRIBUTION_TAG).getSystemService(AppOpsManager.class); mAttributionMessage = String.format("MusicRecognitionManager.invokedByUid.%s", userId); - mAttributionTag = null; + mAttributionTagFuture = null; mServiceInfo = null; } @@ -126,10 +139,13 @@ public final class MusicRecognitionManagerPerUserService extends new MusicRecognitionServiceCallback(clientCallback), mMaster.isBindInstantServiceAllowed(), mMaster.verbose); + try { mServiceInfo = getContext().getPackageManager().getServiceInfo( - mRemoteService.getComponentName(), 0); + mRemoteService.getComponentName(), PackageManager.GET_META_DATA); + mAttributionTagFuture = mRemoteService.getAttributionTag(); + Slog.i(TAG, "Remote service bound: " + mRemoteService.getComponentName()); } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "Service was not found.", e); } @@ -172,11 +188,13 @@ public final class MusicRecognitionManagerPerUserService extends ParcelFileDescriptor audioSink = clientPipe.second; ParcelFileDescriptor clientRead = clientPipe.first; - mMaster.mExecutorService.execute(() -> { - streamAudio(recognitionRequest, clientCallback, audioSink); - }); + mAttributionTagFuture.thenAcceptAsync( + tag -> { + streamAudio(tag, recognitionRequest, clientCallback, audioSink); + }, mMaster.mExecutorService); + // Send the pipe down to the lookup service while we write to it asynchronously. - mRemoteService.writeAudioToPipe(clientRead, recognitionRequest.getAudioFormat()); + mRemoteService.onAudioStreamStarted(clientRead, recognitionRequest.getAudioFormat()); } /** @@ -186,10 +204,12 @@ public final class MusicRecognitionManagerPerUserService extends * @param clientCallback the callback to notify on errors. * @param audioSink the sink to which to stream audio to. */ - private void streamAudio(@NonNull RecognitionRequest recognitionRequest, - IMusicRecognitionManagerCallback clientCallback, ParcelFileDescriptor audioSink) { + private void streamAudio(@Nullable String attributionTag, + @NonNull RecognitionRequest recognitionRequest, + IMusicRecognitionManagerCallback clientCallback, + ParcelFileDescriptor audioSink) { try { - startRecordAudioOp(); + startRecordAudioOp(attributionTag); } catch (SecurityException e) { // A security exception can occur if the MusicRecognitionService (receiving the audio) // does not (or does no longer) hold the necessary permissions to record audio. @@ -214,7 +234,7 @@ public final class MusicRecognitionManagerPerUserService extends Slog.e(TAG, "Audio streaming stopped.", e); } finally { audioRecord.release(); - finishRecordAudioOp(); + finishRecordAudioOp(attributionTag); try { clientCallback.onAudioStreamClosed(); } catch (RemoteException ignored) { @@ -323,23 +343,32 @@ public final class MusicRecognitionManagerPerUserService extends * Tracks that the RECORD_AUDIO operation started (attributes it to the service receiving the * audio). */ - private void startRecordAudioOp() { - mAppOpsManager.startProxyOp( + private void startRecordAudioOp(@Nullable String attributionTag) { + int status = mAppOpsManager.startProxyOp( Objects.requireNonNull(AppOpsManager.permissionToOp(RECORD_AUDIO)), mServiceInfo.applicationInfo.uid, mServiceInfo.packageName, - mAttributionTag, + attributionTag, mAttributionMessage); + // The above should already throw a SecurityException. This is just a fallback. + if (status != AppOpsManager.MODE_ALLOWED) { + throw new SecurityException(String.format( + "Failed to obtain RECORD_AUDIO permission (status: %d) for " + + "receiving service: %s", status, mServiceInfo.getComponentName())); + } + Slog.i(TAG, String.format( + "Starting audio streaming. Attributing to %s (%d) with tag '%s'", + mServiceInfo.packageName, mServiceInfo.applicationInfo.uid, attributionTag)); } /** Tracks that the RECORD_AUDIO operation finished. */ - private void finishRecordAudioOp() { + private void finishRecordAudioOp(@Nullable String attributionTag) { mAppOpsManager.finishProxyOp( Objects.requireNonNull(AppOpsManager.permissionToOp(RECORD_AUDIO)), mServiceInfo.applicationInfo.uid, mServiceInfo.packageName, - mAttributionTag); + attributionTag); } /** Establishes an audio stream from the DSP audio source. */ diff --git a/services/musicrecognition/java/com/android/server/musicrecognition/RemoteMusicRecognitionService.java b/services/musicrecognition/java/com/android/server/musicrecognition/RemoteMusicRecognitionService.java index 6c7d673ffe11..99b448211492 100644 --- a/services/musicrecognition/java/com/android/server/musicrecognition/RemoteMusicRecognitionService.java +++ b/services/musicrecognition/java/com/android/server/musicrecognition/RemoteMusicRecognitionService.java @@ -20,15 +20,20 @@ import android.annotation.NonNull; import android.content.ComponentName; import android.content.Context; import android.media.AudioFormat; +import android.media.musicrecognition.IMusicRecognitionAttributionTagCallback; import android.media.musicrecognition.IMusicRecognitionService; import android.media.musicrecognition.MusicRecognitionService; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.RemoteException; import android.text.format.DateUtils; import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService; import com.android.server.musicrecognition.MusicRecognitionManagerPerUserService.MusicRecognitionServiceCallback; +import java.util.concurrent.CompletableFuture; + + /** Remote connection to an instance of {@link MusicRecognitionService}. */ public class RemoteMusicRecognitionService extends AbstractMultiplePendingRequestsRemoteService<RemoteMusicRecognitionService, @@ -81,9 +86,26 @@ public class RemoteMusicRecognitionService extends * Sends the given descriptor to the app's {@link MusicRecognitionService} to read the * audio. */ - public void writeAudioToPipe(@NonNull ParcelFileDescriptor fd, + public void onAudioStreamStarted(@NonNull ParcelFileDescriptor fd, @NonNull AudioFormat audioFormat) { scheduleAsyncRequest( binder -> binder.onAudioStreamStarted(fd, audioFormat, mServerCallback)); } + + + /** + * Returns the name of the <attribution> tag defined in the remote service's manifest. + */ + public CompletableFuture<String> getAttributionTag() { + CompletableFuture<String> attributionTagFuture = new CompletableFuture<String>(); + scheduleAsyncRequest( + binder -> binder.getAttributionTag( + new IMusicRecognitionAttributionTagCallback.Stub() { + @Override + public void onAttributionTag(String tag) throws RemoteException { + attributionTagFuture.complete(tag); + } + })); + return attributionTagFuture; + } } diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java index e7d01219f6c1..eab3b770a94a 100644 --- a/services/people/java/com/android/server/people/PeopleService.java +++ b/services/people/java/com/android/server/people/PeopleService.java @@ -388,9 +388,11 @@ public class PeopleService extends SystemService { private Map<AppPredictionSessionId, SessionInfo> mSessions = new ArrayMap<>(); @Override - public void onCreatePredictionSession(AppPredictionContext context, + public void onCreatePredictionSession(AppPredictionContext appPredictionContext, AppPredictionSessionId sessionId) { - mSessions.put(sessionId, new SessionInfo(context, mDataManager, sessionId.getUserId())); + mSessions.put(sessionId, + new SessionInfo(appPredictionContext, mDataManager, sessionId.getUserId(), + getContext())); } @Override diff --git a/services/people/java/com/android/server/people/SessionInfo.java b/services/people/java/com/android/server/people/SessionInfo.java index 28612f1dd49b..d256d9c24540 100644 --- a/services/people/java/com/android/server/people/SessionInfo.java +++ b/services/people/java/com/android/server/people/SessionInfo.java @@ -20,6 +20,7 @@ import android.annotation.UserIdInt; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppTarget; import android.app.prediction.IPredictionCallback; +import android.content.Context; import android.content.pm.ParceledListSlice; import android.os.RemoteCallbackList; import android.os.RemoteException; @@ -40,9 +41,9 @@ class SessionInfo { new RemoteCallbackList<>(); SessionInfo(AppPredictionContext predictionContext, DataManager dataManager, - @UserIdInt int callingUserId) { + @UserIdInt int callingUserId, Context context) { mAppTargetPredictor = AppTargetPredictor.create(predictionContext, - this::updatePredictions, dataManager, callingUserId); + this::updatePredictions, dataManager, callingUserId, context); } void addCallback(IPredictionCallback callback) { diff --git a/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java b/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java index c89dadc3fbd6..e19108198bb7 100644 --- a/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java +++ b/services/people/java/com/android/server/people/prediction/AppTargetPredictor.java @@ -24,6 +24,7 @@ import android.app.prediction.AppPredictionContext; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; import android.app.prediction.AppTargetId; +import android.content.Context; import com.android.internal.annotations.VisibleForTesting; import com.android.server.people.data.DataManager; @@ -43,10 +44,10 @@ public class AppTargetPredictor { /** Creates a {@link AppTargetPredictor} instance based on the prediction context. */ public static AppTargetPredictor create(@NonNull AppPredictionContext predictionContext, @NonNull Consumer<List<AppTarget>> updatePredictionsMethod, - @NonNull DataManager dataManager, @UserIdInt int callingUserId) { + @NonNull DataManager dataManager, @UserIdInt int callingUserId, Context context) { if (UI_SURFACE_SHARE.equals(predictionContext.getUiSurface())) { - return new ShareTargetPredictor( - predictionContext, updatePredictionsMethod, dataManager, callingUserId); + return new ShareTargetPredictor(predictionContext, updatePredictionsMethod, dataManager, + callingUserId, context); } return new AppTargetPredictor( predictionContext, updatePredictionsMethod, dataManager, callingUserId); @@ -124,6 +125,11 @@ public class AppTargetPredictor { callback.accept(targets); } + /** To be overridden by the subclass to recycle resources. */ + @WorkerThread + void destroy() { + } + AppPredictionContext getPredictionContext() { return mPredictionContext; } diff --git a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java index 236ac8407faa..368b737d2133 100644 --- a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java +++ b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java @@ -16,6 +16,8 @@ package com.android.server.people.prediction; +import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI; + import static java.util.Collections.reverseOrder; import android.annotation.NonNull; @@ -23,17 +25,23 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.prediction.AppPredictionContext; +import android.app.prediction.AppPredictionManager; +import android.app.prediction.AppPredictor; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; import android.app.prediction.AppTargetId; +import android.content.Context; import android.content.IntentFilter; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager.ShareShortcutInfo; +import android.os.UserHandle; +import android.provider.DeviceConfig; import android.util.Log; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ChooserActivity; +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.server.people.data.ConversationInfo; import com.android.server.people.data.DataManager; import com.android.server.people.data.EventHistory; @@ -52,14 +60,27 @@ class ShareTargetPredictor extends AppTargetPredictor { private static final String TAG = "ShareTargetPredictor"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private static final String REMOTE_APP_PREDICTOR_KEY = "remote_app_predictor"; private final IntentFilter mIntentFilter; + private final AppPredictor mRemoteAppPredictor; ShareTargetPredictor(@NonNull AppPredictionContext predictionContext, @NonNull Consumer<List<AppTarget>> updatePredictionsMethod, - @NonNull DataManager dataManager, @UserIdInt int callingUserId) { + @NonNull DataManager dataManager, + @UserIdInt int callingUserId, @NonNull Context context) { super(predictionContext, updatePredictionsMethod, dataManager, callingUserId); mIntentFilter = predictionContext.getExtras().getParcelable( ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY); + if (DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.DARK_LAUNCH_REMOTE_PREDICTION_SERVICE_ENABLED, + false)) { + predictionContext.getExtras().putBoolean(REMOTE_APP_PREDICTOR_KEY, true); + mRemoteAppPredictor = context.createContextAsUser(UserHandle.of(callingUserId), 0) + .getSystemService(AppPredictionManager.class) + .createAppPredictionSession(predictionContext); + } else { + mRemoteAppPredictor = null; + } } /** Reports chosen history of direct/app share targets. */ @@ -72,6 +93,9 @@ class ShareTargetPredictor extends AppTargetPredictor { if (mIntentFilter != null) { getDataManager().reportShareTargetEvent(event, mIntentFilter); } + if (mRemoteAppPredictor != null) { + mRemoteAppPredictor.notifyAppTargetEvent(event); + } } /** Provides prediction on direct share targets */ @@ -129,6 +153,15 @@ class ShareTargetPredictor extends AppTargetPredictor { callback.accept(appTargetList); } + /** Recycles resources. */ + @WorkerThread + @Override + void destroy() { + if (mRemoteAppPredictor != null) { + mRemoteAppPredictor.destroy(); + } + } + private List<ShareTarget> getDirectShareTargets() { List<ShareTarget> shareTargets = new ArrayList<>(); List<ShareShortcutInfo> shareShortcuts = diff --git a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java index a19b3872949e..363c26b63bae 100644 --- a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java @@ -21,7 +21,6 @@ import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -53,9 +52,7 @@ import com.android.server.twilight.TwilightManager; import com.android.server.twilight.TwilightState; import org.junit.After; -import org.junit.AfterClass; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; @@ -76,25 +73,29 @@ public class ColorDisplayServiceTest { private int mUserId; private MockTwilightManager mTwilightManager; + private DisplayTransformManager mDisplayTransformManager; private ColorDisplayService mCds; private ColorDisplayService.BinderService mBinderService; private Resources mResourcesSpy; - @BeforeClass - public static void setDtm() { - final DisplayTransformManager dtm = Mockito.mock(DisplayTransformManager.class); - LocalServices.addService(DisplayTransformManager.class, dtm); - } + private static final int[] MINIMAL_COLOR_MODES = new int[] { + ColorDisplayManager.COLOR_MODE_NATURAL, + ColorDisplayManager.COLOR_MODE_BOOSTED, + }; @Before public void setUp() { mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); doReturn(mContext).when(mContext).getApplicationContext(); - mResourcesSpy = Mockito.spy(mContext.getResources()); - when(mContext.getResources()).thenReturn(mResourcesSpy); + final Resources res = Mockito.spy(mContext.getResources()); + doReturn(MINIMAL_COLOR_MODES).when(res).getIntArray(R.array.config_availableColorModes); + doReturn(true).when(res).getBoolean(R.bool.config_nightDisplayAvailable); + doReturn(true).when(res).getBoolean(R.bool.config_displayWhiteBalanceAvailable); + when(mContext.getResources()).thenReturn(res); + mResourcesSpy = res; mUserId = ActivityManager.getCurrentUser(); @@ -108,6 +109,10 @@ public class ColorDisplayServiceTest { mTwilightManager = new MockTwilightManager(); LocalServices.addService(TwilightManager.class, mTwilightManager); + mDisplayTransformManager = Mockito.mock(DisplayTransformManager.class); + doReturn(true).when(mDisplayTransformManager).needsLinearColorMatrix(); + LocalServices.addService(DisplayTransformManager.class, mDisplayTransformManager); + mCds = new ColorDisplayService(mContext); mBinderService = mCds.new BinderService(); LocalServices.addService(ColorDisplayService.ColorDisplayServiceInternal.class, @@ -116,12 +121,18 @@ public class ColorDisplayServiceTest { @After public void tearDown() { - LocalServices.removeServiceForTest(TwilightManager.class); - + /* + * Wait for internal {@link Handler} to finish processing pending messages, so that test + * code can safelyremove {@link DisplayTransformManager} mock from {@link LocalServices}. + */ + mCds.mHandler.runWithScissors(() -> { /* nop */ }, /* timeout */ 1000); mCds = null; + LocalServices.removeServiceForTest(TwilightManager.class); mTwilightManager = null; + LocalServices.removeServiceForTest(DisplayTransformManager.class); + mUserId = UserHandle.USER_NULL; mContext = null; @@ -130,11 +141,6 @@ public class ColorDisplayServiceTest { LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class); } - @AfterClass - public static void removeDtm() { - LocalServices.removeServiceForTest(DisplayTransformManager.class); - } - @Test public void customSchedule_whenStartedAfterNight_ifOffAfterNight_turnsOff() { setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */); @@ -1064,24 +1070,18 @@ public class ColorDisplayServiceTest { @Test public void compositionColorSpaces_noResources() { - final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class); - reset(dtm); - when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes)) .thenReturn(new int[] {}); when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces)) .thenReturn(new int[] {}); setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL); startService(); - verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), - eq(Display.COLOR_MODE_INVALID)); + verify(mDisplayTransformManager).setColorMode( + eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), eq(Display.COLOR_MODE_INVALID)); } @Test public void compositionColorSpaces_invalidResources() { - final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class); - reset(dtm); - when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes)) .thenReturn(new int[] { ColorDisplayManager.COLOR_MODE_NATURAL, @@ -1094,15 +1094,12 @@ public class ColorDisplayServiceTest { }); setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL); startService(); - verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), - eq(Display.COLOR_MODE_INVALID)); + verify(mDisplayTransformManager).setColorMode( + eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), eq(Display.COLOR_MODE_INVALID)); } @Test public void compositionColorSpaces_validResources_validColorMode() { - final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class); - reset(dtm); - when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes)) .thenReturn(new int[] { ColorDisplayManager.COLOR_MODE_NATURAL @@ -1113,15 +1110,12 @@ public class ColorDisplayServiceTest { }); setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL); startService(); - verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), - eq(Display.COLOR_MODE_SRGB)); + verify(mDisplayTransformManager).setColorMode( + eq(ColorDisplayManager.COLOR_MODE_NATURAL), any(), eq(Display.COLOR_MODE_SRGB)); } @Test public void compositionColorSpaces_validResources_invalidColorMode() { - final DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class); - reset(dtm); - when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes)) .thenReturn(new int[] { ColorDisplayManager.COLOR_MODE_NATURAL @@ -1132,8 +1126,8 @@ public class ColorDisplayServiceTest { }); setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED); startService(); - verify(dtm).setColorMode(eq(ColorDisplayManager.COLOR_MODE_BOOSTED), any(), - eq(Display.COLOR_MODE_INVALID)); + verify(mDisplayTransformManager).setColorMode( + eq(ColorDisplayManager.COLOR_MODE_BOOSTED), any(), eq(Display.COLOR_MODE_INVALID)); } /** diff --git a/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java new file mode 100644 index 000000000000..0ed6d7bec010 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.hdmi; + +import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM; +import static com.android.server.hdmi.Constants.ADDR_BROADCAST; +import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1; +import static com.android.server.hdmi.Constants.ADDR_TUNER_1; +import static com.android.server.hdmi.Constants.ADDR_TV; +import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED; +import static com.android.server.hdmi.Constants.MESSAGE_ACTIVE_SOURCE; +import static com.android.server.hdmi.Constants.MESSAGE_ROUTING_INFORMATION; +import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC; +import static com.android.server.hdmi.RoutingControlAction.STATE_WAIT_FOR_ROUTING_INFORMATION; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.hardware.hdmi.HdmiDeviceInfo; +import android.hardware.hdmi.HdmiPortInfo; +import android.hardware.hdmi.IHdmiControlCallback; +import android.os.Handler; +import android.os.IPowerManager; +import android.os.IThermalService; +import android.os.Looper; +import android.os.PowerManager; +import android.os.test.TestLooper; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; + +import com.android.server.hdmi.HdmiCecFeatureAction.ActionTimer; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +@SmallTest +@RunWith(JUnit4.class) +public class RoutingControlActionTest { + /* + * Example connection diagram used in tests. Double-lined paths indicate the currently active + * routes. + * + * + * +-----------+ + * | TV | + * | 0.0.0.0 | + * +---+-----+-+ + * | | + * <----------+ 1) AVR -> Switch + * +----------+ | | +-----------+ + * | AVR +---------+ +--+ Switch | + * | 1.0.0.0 | | 2.0.0.0 | + * +--+---++--+ +--++-----+-+ <-------+ 2) Recorder -> Blu-ray + * | || || | + * | || || +--------+ + * +-----------+ | || +----------+ +----++----+ | + * | XBox +--+ ++--+ Tuner | | Blueray | +-----+----+ + * | 1.1.0.0 | | 1.2.0.0 | | 2.1.0.0 | | Recorder | + * +-----------+ +----++----+ +----------+ | 2.2.0.0 | + * || +----------+ + * || + * +----++----+ + * | Player | + * | 1.2.1.0 | + * +----------+ + * + */ + + private static final int PHYSICAL_ADDRESS_TV = 0x0000; + private static final int PHYSICAL_ADDRESS_AVR = 0x1000; + private static final int PHYSICAL_ADDRESS_SWITCH = 0x2000; + private static final int PHYSICAL_ADDRESS_TUNER = 0x1200; + private static final int PHYSICAL_ADDRESS_PLAYER = 0x1210; + private static final int PHYSICAL_ADDRESS_BLUERAY = 0x2100; + private static final int PHYSICAL_ADDRESS_RECORDER = 0x2200; + private static final int PORT_1 = 1; + private static final int PORT_2 = 2; + private static final int VENDOR_ID_AVR = 0x11233; + + private static final byte[] TUNER_PARAM = + new byte[] {(PHYSICAL_ADDRESS_TUNER >> 8) & 0xFF, PHYSICAL_ADDRESS_TUNER & 0xFF}; + private static final byte[] PLAYER_PARAM = + new byte[] {(PHYSICAL_ADDRESS_PLAYER >> 8) & 0xFF, PHYSICAL_ADDRESS_PLAYER & 0xFF}; + + private static final HdmiDeviceInfo DEVICE_INFO_AVR = + new HdmiDeviceInfo(ADDR_AUDIO_SYSTEM, PHYSICAL_ADDRESS_AVR, PORT_1, + HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM, VENDOR_ID_AVR, "Audio"); + private static final HdmiDeviceInfo DEVICE_INFO_PLAYER = + new HdmiDeviceInfo(ADDR_PLAYBACK_1, PHYSICAL_ADDRESS_PLAYER, PORT_1, + HdmiDeviceInfo.DEVICE_PLAYBACK, VENDOR_ID_AVR, "Player"); + private static final HdmiCecMessage ROUTING_INFORMATION_TUNER = new HdmiCecMessage( + ADDR_UNREGISTERED, ADDR_BROADCAST, MESSAGE_ROUTING_INFORMATION, TUNER_PARAM); + private static final HdmiCecMessage ROUTING_INFORMATION_PLAYER = new HdmiCecMessage( + ADDR_UNREGISTERED, ADDR_BROADCAST, MESSAGE_ROUTING_INFORMATION, PLAYER_PARAM); + private static final HdmiCecMessage ACTIVE_SOURCE_TUNER = new HdmiCecMessage( + ADDR_TUNER_1, ADDR_BROADCAST, MESSAGE_ACTIVE_SOURCE, TUNER_PARAM); + private static final HdmiCecMessage ACTIVE_SOURCE_PLAYER = new HdmiCecMessage( + ADDR_PLAYBACK_1, ADDR_BROADCAST, MESSAGE_ACTIVE_SOURCE, PLAYER_PARAM); + + private HdmiControlService mHdmiControlService; + private HdmiCecController mHdmiCecController; + private HdmiCecLocalDeviceTv mHdmiCecLocalDeviceTv; + private FakeNativeWrapper mNativeWrapper; + private Looper mMyLooper; + private TestLooper mTestLooper = new TestLooper(); + private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>(); + + @Mock + private IPowerManager mIPowerManagerMock; + @Mock + private IThermalService mIThermalServiceMock; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + Context context = InstrumentationRegistry.getTargetContext(); + mMyLooper = mTestLooper.getLooper(); + PowerManager powerManager = new PowerManager(context, mIPowerManagerMock, + mIThermalServiceMock, new Handler(mMyLooper)); + + HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context); + + mHdmiControlService = + new HdmiControlService(InstrumentationRegistry.getTargetContext()) { + @Override + boolean isControlEnabled() { + return true; + } + + @Override + void wakeUp() { + } + + @Override + protected void writeStringSystemProperty(String key, String value) { + // do nothing + } + + @Override + boolean isPowerStandbyOrTransient() { + return false; + } + + @Override + protected PowerManager getPowerManager() { + return powerManager; + } + + @Override + protected HdmiCecConfig getHdmiCecConfig() { + return hdmiCecConfig; + } + }; + + mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService); + mHdmiCecLocalDeviceTv.init(); + mHdmiControlService.setIoLooper(mMyLooper); + mNativeWrapper = new FakeNativeWrapper(); + mHdmiCecController = HdmiCecController.createWithNativeWrapper( + mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); + mHdmiControlService.setCecController(mHdmiCecController); + mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService)); + mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService)); + mLocalDevices.add(mHdmiCecLocalDeviceTv); + HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1]; + hdmiPortInfos[0] = + new HdmiPortInfo(1, HdmiPortInfo.PORT_INPUT, PHYSICAL_ADDRESS_AVR, + true, false, false); + mNativeWrapper.setPortInfo(hdmiPortInfos); + mHdmiControlService.initService(); + mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); + mNativeWrapper.setPhysicalAddress(0x0000); + mTestLooper.dispatchAll(); + mNativeWrapper.clearResultMessages(); + mHdmiControlService.getHdmiCecNetwork().addCecDevice(DEVICE_INFO_AVR); + } + + private static class TestActionTimer implements ActionTimer { + private int mState; + + @Override + public void sendTimerMessage(int state, long delayMillis) { + mState = state; + } + + @Override + public void clearTimerMessage() { + } + + private int getState() { + return mState; + } + } + + private static class TestInputSelectCallback extends IHdmiControlCallback.Stub { + private final List<Integer> mCallbackResult = new ArrayList<Integer>(); + + @Override + public void onComplete(int result) { + mCallbackResult.add(result); + } + + private int getResult() { + assert (mCallbackResult.size() == 1); + return mCallbackResult.get(0); + } + } + + private static RoutingControlAction createRoutingControlAction(HdmiCecLocalDeviceTv localDevice, + TestInputSelectCallback callback) { + return new RoutingControlAction(localDevice, PHYSICAL_ADDRESS_AVR, callback); + } + + // Routing control succeeds against the device connected directly to the port. Action + // won't get any <Routing Information> in this case. It times out on <Routing Information>, + // regards the directly connected one as the new routing path to switch to. + @Test + public void testRoutingControl_succeedForDirectlyConnectedDevice() { + TestInputSelectCallback callback = new TestInputSelectCallback(); + TestActionTimer actionTimer = new TestActionTimer(); + mHdmiControlService.getHdmiCecNetwork().addCecDevice(DEVICE_INFO_AVR); + + RoutingControlAction action = createRoutingControlAction(mHdmiCecLocalDeviceTv, callback); + action.setActionTimer(actionTimer); + action.start(); + assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_ROUTING_INFORMATION); + + action.handleTimerEvent(actionTimer.getState()); + mTestLooper.dispatchAll(); + HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath( + ADDR_TV, PHYSICAL_ADDRESS_AVR); + assertThat(mNativeWrapper.getResultMessages()).contains(setStreamPath); + } + + // Succeeds by receiving a couple of <Routing Information> commands, followed by + // <Set Stream Path> going out in the end. + @Test + public void testRoutingControl_succeedForDeviceBehindSwitch() { + TestInputSelectCallback callback = new TestInputSelectCallback(); + TestActionTimer actionTimer = new TestActionTimer(); + mHdmiControlService.getHdmiCecNetwork().addCecDevice(DEVICE_INFO_PLAYER); + RoutingControlAction action = createRoutingControlAction(mHdmiCecLocalDeviceTv, callback); + action.setActionTimer(actionTimer); + action.start(); + + assertThat(actionTimer.getState()).isEqualTo(STATE_WAIT_FOR_ROUTING_INFORMATION); + + action.processCommand(ROUTING_INFORMATION_TUNER); + action.processCommand(ROUTING_INFORMATION_PLAYER); + + action.handleTimerEvent(actionTimer.getState()); + mTestLooper.dispatchAll(); + HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath( + ADDR_TV, PHYSICAL_ADDRESS_PLAYER); + assertThat(mNativeWrapper.getResultMessages()).contains(setStreamPath); + } +} diff --git a/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java b/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java index ecff409ccaf1..506624064265 100644 --- a/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java @@ -47,12 +47,14 @@ import android.os.Binder; import android.os.Bundle; import android.os.RemoteException; import android.os.test.TestLooper; +import android.provider.DeviceConfig; import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; import androidx.test.InstrumentationRegistry; +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.server.LocalServices; import org.junit.After; @@ -126,6 +128,10 @@ public final class PeopleServiceTest { .setPredictedTargetCount(APP_PREDICTION_TARGET_COUNT) .setExtras(new Bundle()) .build(); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.DARK_LAUNCH_REMOTE_PREDICTION_SERVICE_ENABLED, + Boolean.toString(false), + true /* makeDefault*/); } @After diff --git a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java index b09a3c374e86..fac5c1f94e56 100644 --- a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java +++ b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java @@ -22,13 +22,17 @@ import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anySet; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.prediction.AppPredictionContext; +import android.app.prediction.AppPredictionManager; import android.app.prediction.AppTarget; +import android.app.prediction.AppTargetEvent; import android.app.prediction.AppTargetId; import android.content.ComponentName; import android.content.Context; @@ -38,9 +42,11 @@ import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager.ShareShortcutInfo; import android.os.Bundle; import android.os.UserHandle; +import android.provider.DeviceConfig; import android.util.Range; import com.android.internal.app.ChooserActivity; +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.server.people.data.ConversationInfo; import com.android.server.people.data.DataManager; import com.android.server.people.data.EventHistory; @@ -71,6 +77,14 @@ public final class ShareTargetPredictorTest { private static final String PACKAGE_3 = "pkg3"; private static final String CLASS_1 = "cls1"; private static final String CLASS_2 = "cls2"; + private static final AppTargetEvent APP_TARGET_EVENT = + new AppTargetEvent.Builder( + new AppTarget.Builder( + new AppTargetId("cls1#pkg1"), PACKAGE_1, UserHandle.of(USER_ID)).build(), + AppTargetEvent.ACTION_LAUNCH) + .setLaunchLocation(ChooserActivity.LAUNCH_LOCATION_DIRECT_SHARE) + .build(); + private static final IntentFilter INTENT_FILTER = IntentFilter.create("SEND", "text/plain"); @Mock private Context mContext; @Mock private DataManager mDataManager; @@ -102,17 +116,33 @@ public final class ShareTargetPredictorTest { when(mDataManager.getShareShortcuts(any(), anyInt())).thenReturn(mShareShortcuts); when(mDataManager.getPackage(PACKAGE_1, USER_ID)).thenReturn(mPackageData1); when(mDataManager.getPackage(PACKAGE_2, USER_ID)).thenReturn(mPackageData2); + when(mContext.createContextAsUser(any(), any())).thenReturn(mContext); + when(mContext.getSystemServiceName(AppPredictionManager.class)).thenReturn( + Context.APP_PREDICTION_SERVICE); + when(mContext.getSystemService(AppPredictionManager.class)) + .thenReturn(new AppPredictionManager(mContext)); Bundle bundle = new Bundle(); - bundle.putObject(ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY, - IntentFilter.create("SEND", "text/plain")); + bundle.putObject(ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY, INTENT_FILTER); AppPredictionContext predictionContext = new AppPredictionContext.Builder(mContext) .setUiSurface(UI_SURFACE_SHARE) .setPredictedTargetCount(NUM_PREDICTED_TARGETS) .setExtras(bundle) .build(); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.DARK_LAUNCH_REMOTE_PREDICTION_SERVICE_ENABLED, + Boolean.toString(true), + true /* makeDefault*/); mPredictor = new ShareTargetPredictor( - predictionContext, mUpdatePredictionsMethod, mDataManager, USER_ID); + predictionContext, mUpdatePredictionsMethod, mDataManager, USER_ID, mContext); + } + + @Test + public void testReportAppTargetEvent() { + mPredictor.reportAppTargetEvent(APP_TARGET_EVENT); + + verify(mDataManager, times(1)) + .reportShareTargetEvent(eq(APP_TARGET_EVENT), eq(INTENT_FILTER)); } @Test @@ -240,7 +270,7 @@ public final class ShareTargetPredictorTest { .setExtras(new Bundle()) .build(); mPredictor = new ShareTargetPredictor( - predictionContext, mUpdatePredictionsMethod, mDataManager, USER_ID); + predictionContext, mUpdatePredictionsMethod, mDataManager, USER_ID, mContext); mPredictor.predictTargets(); @@ -349,7 +379,7 @@ public final class ShareTargetPredictorTest { .setExtras(new Bundle()) .build(); mPredictor = new ShareTargetPredictor( - predictionContext, mUpdatePredictionsMethod, mDataManager, USER_ID); + predictionContext, mUpdatePredictionsMethod, mDataManager, USER_ID, mContext); AppTarget appTarget1 = new AppTarget.Builder( new AppTargetId("cls1#pkg1"), PACKAGE_1, UserHandle.of(USER_ID)) .build(); diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java new file mode 100644 index 000000000000..3ab34484ce25 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java @@ -0,0 +1,295 @@ +/* + * 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.dex; + +import static org.mockito.Mockito.inOrder; + +import com.android.internal.art.ArtStatsLog; +import com.android.server.pm.dex.ArtStatsLogUtils.ArtStatsLogger; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.InOrder; +import org.mockito.MockitoAnnotations; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * Unit tests for {@link com.android.server.pm.dex.ArtStatsLogUtils}. + * + * Run with "atest ArtStatsLogUtilsTest". + */ +@RunWith(JUnit4.class) +public final class ArtStatsLogUtilsTest { + private static final String TAG = ArtStatsLogUtilsTest.class.getSimpleName(); + private static final String COMPILER_FILTER = "space-profile"; + private static final String PROFILE_DEX_METADATA = "primary.prof"; + private static final String VDEX_DEX_METADATA = "primary.vdex"; + private static final byte[] DEX_CONTENT = "dexData".getBytes(); + private static final int COMPILATION_REASON = 1; + private static final int RESULT_CODE = 222; + private static final int UID = 111; + private static final long COMPILE_TIME = 333L; + private static final long SESSION_ID = 444L; + + @Mock + ArtStatsLogger mockLogger; + + private static Path TEST_DIR; + private static Path DEX; + private static Path NON_DEX; + + @BeforeClass + public static void setUpAll() throws IOException { + TEST_DIR = Files.createTempDirectory(null); + DEX = Files.createFile(TEST_DIR.resolve("classes.dex")); + NON_DEX = Files.createFile(TEST_DIR.resolve("test.dex")); + Files.write(DEX, DEX_CONTENT); + Files.write(NON_DEX, "empty".getBytes()); + } + + @AfterClass + public static void tearnDownAll() { + deleteSliently(DEX); + deleteSliently(NON_DEX); + deleteSliently(TEST_DIR); + } + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testProfileAndVdexDexMetadata() throws IOException { + // Setup + Path dexMetadataPath = null; + Path apk = null; + try { + dexMetadataPath = createDexMetadata(PROFILE_DEX_METADATA, VDEX_DEX_METADATA); + apk = zipFiles(".apk", DEX, NON_DEX, dexMetadataPath); + + // Act + ArtStatsLogUtils.writeStatsLog( + mockLogger, + SESSION_ID, + apk.toString(), + COMPILER_FILTER, + UID, + COMPILE_TIME, + dexMetadataPath.toString(), + COMPILATION_REASON, + RESULT_CODE); + + // Assert + verifyWrites(ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__PROFILE_AND_VDEX); + } finally { + deleteSliently(dexMetadataPath); + deleteSliently(apk); + } + } + + @Test + public void testProfileOnlyDexMetadata() throws IOException { + // Setup + Path dexMetadataPath = null; + Path apk = null; + try { + dexMetadataPath = createDexMetadata(PROFILE_DEX_METADATA); + apk = zipFiles(".apk", DEX, NON_DEX, dexMetadataPath); + + // Act + ArtStatsLogUtils.writeStatsLog( + mockLogger, + SESSION_ID, + apk.toString(), + COMPILER_FILTER, + UID, + COMPILE_TIME, + dexMetadataPath.toString(), + COMPILATION_REASON, + RESULT_CODE); + + // Assert + verifyWrites(ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__PROFILE); + } finally { + deleteSliently(dexMetadataPath); + deleteSliently(apk); + } + } + + @Test + public void testVdexOnlyDexMetadata() throws IOException { + // Setup + Path dexMetadataPath = null; + Path apk = null; + try { + dexMetadataPath = createDexMetadata(VDEX_DEX_METADATA); + apk = zipFiles(".apk", DEX, NON_DEX, dexMetadataPath); + + // Act + ArtStatsLogUtils.writeStatsLog( + mockLogger, + SESSION_ID, + apk.toString(), + COMPILER_FILTER, + UID, + COMPILE_TIME, + dexMetadataPath.toString(), + COMPILATION_REASON, + RESULT_CODE); + + // Assert + verifyWrites(ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__VDEX); + } finally { + deleteSliently(dexMetadataPath); + deleteSliently(apk); + } + } + + @Test + public void testNoneDexMetadata() throws IOException { + // Setup + Path apk = null; + try { + apk = zipFiles(".apk", DEX, NON_DEX); + + // Act + ArtStatsLogUtils.writeStatsLog( + mockLogger, + SESSION_ID, + apk.toString(), + COMPILER_FILTER, + UID, + COMPILE_TIME, + /*dexMetadataPath=*/ null, + COMPILATION_REASON, + RESULT_CODE); + + // Assert + verifyWrites(ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__NONE_DEX_METADATA); + } finally { + deleteSliently(apk); + } + } + + @Test + public void testUnKnownDexMetadata() throws IOException { + // Setup + Path dexMetadataPath = null; + Path apk = null; + try { + dexMetadataPath = createDexMetadata("unknown"); + apk = zipFiles(".apk", DEX, NON_DEX, dexMetadataPath); + + // Act + ArtStatsLogUtils.writeStatsLog( + mockLogger, + SESSION_ID, + apk.toString(), + COMPILER_FILTER, + UID, + COMPILE_TIME, + dexMetadataPath.toString(), + COMPILATION_REASON, + RESULT_CODE); + + // Assert + verifyWrites(ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__UNKNOWN_DEX_METADATA); + } finally { + deleteSliently(dexMetadataPath); + deleteSliently(apk); + } + } + + private void verifyWrites(int dexMetadataType) { + InOrder inorder = inOrder(mockLogger); + inorder.verify(mockLogger).write( + SESSION_ID, UID, + COMPILATION_REASON, + COMPILER_FILTER, + ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_RESULT_CODE, + RESULT_CODE, + dexMetadataType); + inorder.verify(mockLogger).write( + SESSION_ID, + UID, + COMPILATION_REASON, + COMPILER_FILTER, + ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES, + DEX_CONTENT.length, + dexMetadataType); + inorder.verify(mockLogger).write( + SESSION_ID, + UID, + COMPILATION_REASON, + COMPILER_FILTER, + ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME, + COMPILE_TIME, + dexMetadataType); + } + + private Path zipFiles(String suffix, Path... files) throws IOException { + Path zipFile = Files.createTempFile(null, suffix); + try (final OutputStream os = Files.newOutputStream(zipFile)) { + try (final ZipOutputStream zos = new ZipOutputStream(os)) { + for (Path file : files) { + ZipEntry zipEntry = new ZipEntry(file.getFileName().toString()); + zos.putNextEntry(zipEntry); + zos.write(Files.readAllBytes(file)); + zos.closeEntry(); + } + } + } + return zipFile; + } + + private Path createDexMetadata(String... entryNames) throws IOException { + Path zipFile = Files.createTempFile(null, ".dm"); + try (final OutputStream os = Files.newOutputStream(zipFile)) { + try (final ZipOutputStream zos = new ZipOutputStream(os)) { + for (String entryName : entryNames) { + ZipEntry zipEntry = new ZipEntry(entryName); + zos.putNextEntry(zipEntry); + zos.write(entryName.getBytes()); + zos.closeEntry(); + } + } + } + return zipFile; + } + + private static void deleteSliently(Path file) { + if (file != null) { + try { + Files.deleteIfExists(file); + } catch (IOException e) { + // ignore + } + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java new file mode 100644 index 000000000000..5cd0adb6b483 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java @@ -0,0 +1,1113 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.soundtrigger_middleware; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.atMost; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +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.media.soundtrigger_middleware.Status; +import android.os.HwParcel; +import android.os.IHwBinder; +import android.os.IHwInterface; +import android.os.RemoteException; +import android.system.OsConstants; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.mockito.ArgumentCaptor; + +import java.util.LinkedList; +import java.util.List; + +@RunWith(Parameterized.class) +public class SoundHw2CompatTest { + @Parameterized.Parameter(0) + public String mVersion; + + @Parameterized.Parameter(1) + public boolean mSupportConcurrentCapture; + + private final Runnable mRebootRunnable = mock(Runnable.class); + private ISoundTriggerHw2 mCanonical; + private CaptureStateNotifier mCaptureStateNotifier; + private android.hardware.soundtrigger.V2_0.ISoundTriggerHw mHalDriver; + + // We run the test once for every version of the underlying driver. + @Parameterized.Parameters(name = "{0}, concurrent={1}") + public static Iterable<Object[]> data() { + List<Object[]> result = new LinkedList<>(); + + for (String version : new String[]{ + "V2_0", + "V2_1", + "V2_2", + "V2_3", + "V2_4", + }) { + for (boolean concurrentCapture : new boolean[]{false, true}) { + result.add(new Object[]{version, concurrentCapture}); + } + } + + return result; + } + + @Before + public void setUp() throws Exception { + mHalDriver = (android.hardware.soundtrigger.V2_0.ISoundTriggerHw) mock(Class.forName( + String.format("android.hardware.soundtrigger.%s.ISoundTriggerHw", mVersion))); + + clearInvocations(mRebootRunnable); + + // This binder is associated with the mock, so it can be cast to either version of the + // HAL interface. + final IHwBinder binder = new IHwBinder() { + @Override + public void transact(int code, HwParcel request, HwParcel reply, int flags) + throws RemoteException { + // This is a little hacky, but a very easy way to gracefully reject a request for + // an unsupported interface (after queryLocalInterface() returns null, the client + // will attempt a remote transaction to obtain the interface. RemoteException will + // cause it to give up). + throw new RemoteException(); + } + + @Override + public IHwInterface queryLocalInterface(String descriptor) { + if (descriptor.equals("android.hardware.soundtrigger@2.0::ISoundTriggerHw") + || descriptor.equals("android.hardware.soundtrigger@2.1::ISoundTriggerHw") + && mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw + || descriptor.equals("android.hardware.soundtrigger@2.2::ISoundTriggerHw") + && mHalDriver instanceof android.hardware.soundtrigger.V2_2.ISoundTriggerHw + || descriptor.equals("android.hardware.soundtrigger@2.3::ISoundTriggerHw") + && mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw + || descriptor.equals("android.hardware.soundtrigger@2.4::ISoundTriggerHw") + && mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) { + return mHalDriver; + } + return null; + } + + @Override + public boolean linkToDeath(DeathRecipient recipient, long cookie) { + try { + return mHalDriver.linkToDeath(recipient, cookie); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + @Override + public boolean unlinkToDeath(DeathRecipient recipient) { + try { + return mHalDriver.unlinkToDeath(recipient); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + }; + when(mHalDriver.asBinder()).thenReturn(binder); + + android.hardware.soundtrigger.V2_3.Properties halProperties = + TestUtil.createDefaultProperties_2_3(mSupportConcurrentCapture); + doAnswer(invocation -> { + ((android.hardware.soundtrigger.V2_0.ISoundTriggerHw.getPropertiesCallback) + invocation.getArgument( + 0)).onValues(0, + halProperties.base); + return null; + }).when(mHalDriver).getProperties(any()); + + if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) { + android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver = + (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; + doAnswer(invocation -> { + ((android.hardware.soundtrigger.V2_3.ISoundTriggerHw.getProperties_2_3Callback) + invocation.getArgument( + 0)).onValues(0, + halProperties); + return null; + }).when(driver).getProperties_2_3(any()); + } + + mCaptureStateNotifier = spy(new CaptureStateNotifier()); + + mCanonical = SoundTriggerHw2Compat.create(mHalDriver, mRebootRunnable, + mCaptureStateNotifier); + + // During initialization any method can be called, but after we're starting to enforce that + // no additional methods are called. + clearInvocations(mHalDriver); + } + + @After + public void tearDown() { + mCanonical.detach(); + verifyNoMoreInteractions(mHalDriver); + verifyNoMoreInteractions(mRebootRunnable); + mCaptureStateNotifier.verifyNoMoreListeners(); + } + + @Test + public void testSetUpAndTearDown() { + } + + @Test + public void testReboot() { + mCanonical.reboot(); + verify(mRebootRunnable).run(); + } + + @Test + public void testGetProperties() throws Exception { + android.hardware.soundtrigger.V2_3.Properties halProperties = + TestUtil.createDefaultProperties_2_3(mSupportConcurrentCapture); + android.hardware.soundtrigger.V2_3.Properties properties = mCanonical.getProperties(); + + if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) { + android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver = + (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; + // It is OK for the SUT to cache the properties, so the underlying method doesn't + // need to be called every single time. + verify(driver, atMost(1)).getProperties_2_3(any()); + assertEquals(halProperties, properties); + } else { + // It is OK for the SUT to cache the properties, so the underlying method doesn't + // need to be called every single time. + verify(mHalDriver, atMost(1)).getProperties(any()); + assertEquals(halProperties.base, properties.base); + assertEquals(0, properties.audioCapabilities); + assertEquals("", properties.supportedModelArch); + } + } + + private int loadGenericModel_2_0(ISoundTriggerHw2.ModelCallback canonicalCallback) + throws Exception { + final int handle = 29; + ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel> + modelCaptor = + ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel.class); + ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback> + callbackCaptor = + ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.class); + + doAnswer(invocation -> { + android.hardware.soundtrigger.V2_0.ISoundTriggerHw.loadSoundModelCallback + resultCallback = invocation.getArgument(3); + + // This is the return of this method. + resultCallback.onValues(0, handle); + return null; + }).when(mHalDriver).loadSoundModel(any(), any(), anyInt(), any()); + + assertEquals(handle, mCanonical.loadSoundModel(TestUtil.createGenericSoundModel_2_1(), + canonicalCallback)); + + verify(mHalDriver).loadSoundModel(modelCaptor.capture(), callbackCaptor.capture(), anyInt(), + any()); + + TestUtil.validateGenericSoundModel_2_0(modelCaptor.getValue()); + validateCallback_2_0(callbackCaptor.getValue(), canonicalCallback); + return handle; + } + + private int loadGenericModel_2_1(ISoundTriggerHw2.ModelCallback canonicalCallback) + throws Exception { + final android.hardware.soundtrigger.V2_1.ISoundTriggerHw driver_2_1 = + (android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver; + + final int handle = 29; + ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel> + modelCaptor = + ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel.class); + ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> + callbackCaptor = + ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class); + + doAnswer(invocation -> { + android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadSoundModel_2_1Callback + resultCallback = invocation.getArgument(3); + + // This is the return of this method. + resultCallback.onValues(0, handle); + return null; + }).when(driver_2_1).loadSoundModel_2_1(any(), any(), anyInt(), any()); + + assertEquals(handle, mCanonical.loadSoundModel(TestUtil.createGenericSoundModel_2_1(), + canonicalCallback)); + + verify(driver_2_1).loadSoundModel_2_1(modelCaptor.capture(), callbackCaptor.capture(), + anyInt(), + any()); + + TestUtil.validateGenericSoundModel_2_1(modelCaptor.getValue()); + validateCallback_2_1(callbackCaptor.getValue(), canonicalCallback); + return handle; + } + + private int loadGenericModel_2_4(ISoundTriggerHw2.ModelCallback canonicalCallback) + throws Exception { + final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 = + (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver; + + final int handle = 29; + ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel> + modelCaptor = + ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel.class); + ArgumentCaptor<android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback> + callbackCaptor = + ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback.class); + + doAnswer(invocation -> { + android.hardware.soundtrigger.V2_4.ISoundTriggerHw.loadSoundModel_2_4Callback + resultCallback = invocation.getArgument(2); + + // This is the return of this method. + resultCallback.onValues(0, handle); + return null; + }).when(driver_2_4).loadSoundModel_2_4(any(), any(), any()); + + assertEquals(handle, mCanonical.loadSoundModel(TestUtil.createGenericSoundModel_2_1(), + canonicalCallback)); + + verify(driver_2_4).loadSoundModel_2_4(modelCaptor.capture(), callbackCaptor.capture(), + any()); + + TestUtil.validateGenericSoundModel_2_1(modelCaptor.getValue()); + validateCallback_2_4(callbackCaptor.getValue(), canonicalCallback); + return handle; + } + + private int loadGenericModel(ISoundTriggerHw2.ModelCallback canonicalCallback) + throws Exception { + if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) { + return loadGenericModel_2_4(canonicalCallback); + } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) { + return loadGenericModel_2_1(canonicalCallback); + } else { + return loadGenericModel_2_0(canonicalCallback); + } + } + + @Test + public void testLoadGenericModel() throws Exception { + ISoundTriggerHw2.ModelCallback canonicalCallback = mock( + ISoundTriggerHw2.ModelCallback.class); + loadGenericModel(canonicalCallback); + } + + @Test + public void testMaxModels() throws Exception { + assumeFalse(mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw); + + // Register global callback. + ISoundTriggerHw2.GlobalCallback globalCallback = mock( + ISoundTriggerHw2.GlobalCallback.class); + mCanonical.registerCallback(globalCallback); + + ISoundTriggerHw2.ModelCallback canonicalCallback = mock( + ISoundTriggerHw2.ModelCallback.class); + final int maxModels = TestUtil.createDefaultProperties(false).maxSoundModels; + int[] modelHandles = new int[maxModels]; + + // Load as many models as we're allowed. + for (int i = 0; i < maxModels; ++i) { + modelHandles[i] = loadGenericModel(canonicalCallback); + verifyNoMoreInteractions(mHalDriver); + clearInvocations(mHalDriver); + } + + // Now try to load an additional one and expect failure without invoking the underlying + // driver. + try { + mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel_2_1(), + canonicalCallback); + fail("Expected an exception"); + } catch (RecoverableException e) { + assertEquals(Status.RESOURCE_CONTENTION, e.errorCode); + } + + // Unload a single model and expect a onResourcesAvailable(). + mCanonical.unloadSoundModel(modelHandles[0]); + verify(mHalDriver).unloadSoundModel(modelHandles[0]); + + mCanonical.flushCallbacks(); + verify(globalCallback).onResourcesAvailable(); + } + + private void testLoadGenericModelBusy_2_4() throws Exception { + final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 = + (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver; + + doAnswer(invocation -> { + android.hardware.soundtrigger.V2_4.ISoundTriggerHw.loadSoundModel_2_4Callback + resultCallback = invocation.getArgument(2); + + // This is the return of this method. + resultCallback.onValues(-OsConstants.EBUSY, 0); + return null; + }).when(driver_2_4).loadSoundModel_2_4(any(), any(), any()); + + ISoundTriggerHw2.ModelCallback canonicalCallback = mock( + ISoundTriggerHw2.ModelCallback.class); + try { + mCanonical.loadSoundModel(TestUtil.createGenericSoundModel_2_1(), + canonicalCallback); + fail("Expected an exception"); + } catch (RecoverableException e) { + assertEquals(Status.RESOURCE_CONTENTION, e.errorCode); + } + verify(driver_2_4).loadSoundModel_2_4(any(), any(), any()); + } + + @Test + public void testLoadGenericModelBusy() throws Exception { + if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) { + testLoadGenericModelBusy_2_4(); + } + } + + private int loadPhraseModel_2_0(ISoundTriggerHw2.ModelCallback canonicalCallback) + throws Exception { + final int handle = 29; + ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel> + modelCaptor = + ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel.class); + ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback> + callbackCaptor = + ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.class); + + doAnswer(invocation -> { + android.hardware.soundtrigger.V2_0.ISoundTriggerHw.loadPhraseSoundModelCallback + resultCallback = invocation.getArgument(3); + + // This is the return of this method. + resultCallback.onValues(0, handle); + return null; + }).when(mHalDriver).loadPhraseSoundModel(any(), any(), anyInt(), any()); + + assertEquals(handle, mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel_2_1(), + canonicalCallback)); + + verify(mHalDriver).loadPhraseSoundModel(modelCaptor.capture(), callbackCaptor.capture(), + anyInt(), + any()); + + TestUtil.validatePhraseSoundModel_2_0(modelCaptor.getValue()); + validateCallback_2_0(callbackCaptor.getValue(), canonicalCallback); + return handle; + } + + private int loadPhraseModel_2_1(ISoundTriggerHw2.ModelCallback canonicalCallback) + throws Exception { + final android.hardware.soundtrigger.V2_1.ISoundTriggerHw driver_2_1 = + (android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver; + + final int handle = 29; + ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel> + modelCaptor = + ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel.class); + ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> + callbackCaptor = + ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class); + + doAnswer(invocation -> { + android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadPhraseSoundModel_2_1Callback + resultCallback = invocation.getArgument(3); + + // This is the return of this method. + resultCallback.onValues(0, handle); + return null; + }).when(driver_2_1).loadPhraseSoundModel_2_1(any(), any(), anyInt(), any()); + + assertEquals(handle, mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel_2_1(), + canonicalCallback)); + + verify(driver_2_1).loadPhraseSoundModel_2_1(modelCaptor.capture(), callbackCaptor.capture(), + anyInt(), + any()); + + TestUtil.validatePhraseSoundModel_2_1(modelCaptor.getValue()); + validateCallback_2_1(callbackCaptor.getValue(), canonicalCallback); + return handle; + } + + private int loadPhraseModel_2_4(ISoundTriggerHw2.ModelCallback canonicalCallback) + throws Exception { + final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 = + (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver; + + final int handle = 29; + ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel> + modelCaptor = + ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel.class); + ArgumentCaptor<android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback> + callbackCaptor = + ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback.class); + + doAnswer(invocation -> { + android.hardware.soundtrigger.V2_4.ISoundTriggerHw.loadPhraseSoundModel_2_4Callback + resultCallback = invocation.getArgument(2); + + // This is the return of this method. + resultCallback.onValues(0, handle); + return null; + }).when(driver_2_4).loadPhraseSoundModel_2_4(any(), any(), any()); + + assertEquals(handle, mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel_2_1(), + canonicalCallback)); + + verify(driver_2_4).loadPhraseSoundModel_2_4(modelCaptor.capture(), callbackCaptor.capture(), + any()); + + TestUtil.validatePhraseSoundModel_2_1(modelCaptor.getValue()); + validateCallback_2_4(callbackCaptor.getValue(), canonicalCallback); + return handle; + } + + public int loadPhraseModel(ISoundTriggerHw2.ModelCallback canonicalCallback) throws Exception { + if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) { + return loadPhraseModel_2_4(canonicalCallback); + } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) { + return loadPhraseModel_2_1(canonicalCallback); + } else { + return loadPhraseModel_2_0(canonicalCallback); + } + } + + @Test + public void testLoadPhraseModel() throws Exception { + ISoundTriggerHw2.ModelCallback canonicalCallback = mock( + ISoundTriggerHw2.ModelCallback.class); + loadPhraseModel(canonicalCallback); + } + + private void testLoadPhraseModelBusy_2_4() throws Exception { + final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 = + (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver; + + doAnswer(invocation -> { + android.hardware.soundtrigger.V2_4.ISoundTriggerHw.loadPhraseSoundModel_2_4Callback + resultCallback = invocation.getArgument(2); + + // This is the return of this method. + resultCallback.onValues(-OsConstants.EBUSY, 0); + return null; + }).when(driver_2_4).loadPhraseSoundModel_2_4(any(), any(), any()); + + ISoundTriggerHw2.ModelCallback canonicalCallback = mock( + ISoundTriggerHw2.ModelCallback.class); + try { + mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel_2_1(), + canonicalCallback); + fail("Expected an exception"); + } catch (RecoverableException e) { + assertEquals(Status.RESOURCE_CONTENTION, e.errorCode); + } + verify(driver_2_4).loadPhraseSoundModel_2_4(any(), any(), any()); + } + + @Test + public void testLoadPhraseModelBusy() throws Exception { + if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) { + testLoadPhraseModelBusy_2_4(); + } + } + + @Test + public void testUnloadModel() throws Exception { + mCanonical.unloadSoundModel(14); + verify(mHalDriver).unloadSoundModel(14); + } + + private void startRecognition_2_0(int handle, ISoundTriggerHw2.ModelCallback canonicalCallback) + throws Exception { + ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.RecognitionConfig> + configCaptor = ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_0.ISoundTriggerHw.RecognitionConfig.class); + ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback> + callbackCaptor = + ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.class); + + when(mHalDriver.startRecognition(eq(handle), any(), any(), anyInt())).thenReturn(0); + + android.hardware.soundtrigger.V2_3.RecognitionConfig config = + TestUtil.createRecognitionConfig_2_3(203, 204); + mCanonical.startRecognition(handle, config); + verify(mHalDriver).startRecognition(eq(handle), configCaptor.capture(), + callbackCaptor.capture(), anyInt()); + + TestUtil.validateRecognitionConfig_2_0(configCaptor.getValue(), 203, 204); + validateCallback_2_0(callbackCaptor.getValue(), canonicalCallback); + } + + private void startRecognition_2_1(int handle, ISoundTriggerHw2.ModelCallback canonicalCallback) + throws Exception { + final android.hardware.soundtrigger.V2_1.ISoundTriggerHw driver_2_1 = + (android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver; + + ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig> + configCaptor = ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig.class); + ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> + callbackCaptor = + ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class); + + when(driver_2_1.startRecognition_2_1(eq(handle), any(), any(), anyInt())).thenReturn(0); + + android.hardware.soundtrigger.V2_3.RecognitionConfig config = + TestUtil.createRecognitionConfig_2_3(505, 506); + mCanonical.startRecognition(handle, config); + verify(driver_2_1).startRecognition_2_1(eq(handle), configCaptor.capture(), + callbackCaptor.capture(), + anyInt()); + + TestUtil.validateRecognitionConfig_2_1(configCaptor.getValue(), 505, 506); + validateCallback_2_1(callbackCaptor.getValue(), canonicalCallback); + } + + private void startRecognition_2_3(int handle) + throws Exception { + final android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver_2_3 = + (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; + ArgumentCaptor<android.hardware.soundtrigger.V2_3.RecognitionConfig> + configCaptor = ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_3.RecognitionConfig.class); + + when(driver_2_3.startRecognition_2_3(eq(handle), any())).thenReturn(0); + + android.hardware.soundtrigger.V2_3.RecognitionConfig config = + TestUtil.createRecognitionConfig_2_3(808, 909); + mCanonical.startRecognition(handle, config); + verify(driver_2_3).startRecognition_2_3(eq(handle), configCaptor.capture()); + TestUtil.validateRecognitionConfig_2_3(configCaptor.getValue(), 808, 909); + } + + private void startRecognition_2_4(int handle) + throws Exception { + final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 = + (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver; + ArgumentCaptor<android.hardware.soundtrigger.V2_3.RecognitionConfig> + configCaptor = ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_3.RecognitionConfig.class); + + when(driver_2_4.startRecognition_2_4(eq(handle), any())).thenReturn(0); + + android.hardware.soundtrigger.V2_3.RecognitionConfig config = + TestUtil.createRecognitionConfig_2_3(21, 22); + mCanonical.startRecognition(handle, config); + verify(driver_2_4).startRecognition_2_4(eq(handle), configCaptor.capture()); + TestUtil.validateRecognitionConfig_2_3(configCaptor.getValue(), 21, 22); + } + + private void startRecognition(int handle, ISoundTriggerHw2.ModelCallback canonicalCallback) + throws Exception { + if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) { + startRecognition_2_4(handle); + } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) { + startRecognition_2_3(handle); + } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) { + startRecognition_2_1(handle, canonicalCallback); + } else { + startRecognition_2_0(handle, canonicalCallback); + } + } + + @Test + public void testStartRecognition() throws Exception { + // First load. + ISoundTriggerHw2.ModelCallback canonicalCallback = mock( + ISoundTriggerHw2.ModelCallback.class); + final int handle = loadGenericModel(canonicalCallback); + + // Then start. + startRecognition(handle, canonicalCallback); + } + + private void testStartRecognitionBusy_2_4() throws Exception { + final android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 = + (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver; + + final int handle = 68; + when(driver_2_4.startRecognition_2_4(eq(handle), any())).thenReturn(-OsConstants.EBUSY); + + android.hardware.soundtrigger.V2_3.RecognitionConfig config = + TestUtil.createRecognitionConfig_2_3(34, 35); + try { + mCanonical.startRecognition(handle, config); + fail("Expected an exception"); + } catch (RecoverableException e) { + assertEquals(Status.RESOURCE_CONTENTION, e.errorCode); + } + verify(driver_2_4).startRecognition_2_4(eq(handle), any()); + } + + @Test + public void testStartRecognitionBusy() throws Exception { + if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) { + testStartRecognitionBusy_2_4(); + } + } + + @Test + public void testNoRegisterCaptureStateListener() { + assumeTrue(mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw + || mSupportConcurrentCapture); + verify(mCaptureStateNotifier, never()).registerListener(any()); + } + + @Test + public void testConcurrentCaptureAbort() throws Exception { + assumeFalse(mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw + || mSupportConcurrentCapture); + verify(mCaptureStateNotifier, atLeast(1)).registerListener(any()); + + // Register global callback. + ISoundTriggerHw2.GlobalCallback globalCallback = mock( + ISoundTriggerHw2.GlobalCallback.class); + mCanonical.registerCallback(globalCallback); + + // Load. + ISoundTriggerHw2.ModelCallback canonicalCallback = mock( + ISoundTriggerHw2.ModelCallback.class); + final int handle = loadGenericModel(canonicalCallback); + + // Then start. + startRecognition(handle, canonicalCallback); + + // Now activate external capture. + mCaptureStateNotifier.setState(true); + + // Expect hardware to have been stopped. + verify(mHalDriver).stopRecognition(handle); + + // Expect an abort event (async). + ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent> + eventCaptor = ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent.class); + mCanonical.flushCallbacks(); + verify(canonicalCallback).recognitionCallback(eventCaptor.capture()); + assertEquals( + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT, + eventCaptor.getValue().header.status); + assertEquals(handle, eventCaptor.getValue().header.model); + + // Deactivate external capture. + mCaptureStateNotifier.setState(false); + + // Expect a onResourcesAvailable(). + mCanonical.flushCallbacks(); + verify(globalCallback).onResourcesAvailable(); + } + + @Test + public void testConcurrentCaptureReject() throws Exception { + assumeFalse(mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw + || mSupportConcurrentCapture); + verify(mCaptureStateNotifier, atLeast(1)).registerListener(any()); + + // Register global callback. + ISoundTriggerHw2.GlobalCallback globalCallback = mock( + ISoundTriggerHw2.GlobalCallback.class); + mCanonical.registerCallback(globalCallback); + + // Load (this registers the callback). + ISoundTriggerHw2.ModelCallback canonicalCallback = mock( + ISoundTriggerHw2.ModelCallback.class); + final int handle = loadGenericModel(canonicalCallback); + + // Report external capture active. + mCaptureStateNotifier.setState(true); + + // Then start. + android.hardware.soundtrigger.V2_3.RecognitionConfig config = + TestUtil.createRecognitionConfig_2_3(203, 204); + try { + mCanonical.startRecognition(handle, config); + fail("Expected an exception"); + } catch (RecoverableException e) { + assertEquals(Status.RESOURCE_CONTENTION, e.errorCode); + } + + // Deactivate external capture. + mCaptureStateNotifier.setState(false); + + // Expect a onResourcesAvailable(). + mCanonical.flushCallbacks(); + verify(globalCallback).onResourcesAvailable(); + } + + @Test + public void testStopRecognition() throws Exception { + mCanonical.stopRecognition(17); + verify(mHalDriver).stopRecognition(17); + } + + @Test + public void testForceRecognition() throws Exception { + if (mHalDriver instanceof android.hardware.soundtrigger.V2_2.ISoundTriggerHw) { + android.hardware.soundtrigger.V2_2.ISoundTriggerHw driver_2_2 = + (android.hardware.soundtrigger.V2_2.ISoundTriggerHw) mHalDriver; + mCanonical.getModelState(14); + verify(driver_2_2).getModelState(14); + } else { + try { + mCanonical.getModelState(14); + fail("Expected an exception"); + } catch (RecoverableException e) { + assertEquals(Status.OPERATION_NOT_SUPPORTED, e.errorCode); + } + } + } + + @Test + public void testGetParameter() throws Exception { + assumeTrue(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw); + + android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver_2_3 = + (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; + + doAnswer(invocation -> { + android.hardware.soundtrigger.V2_3.ISoundTriggerHw.getParameterCallback + resultCallback = invocation.getArgument(2); + + // This is the return of this method. + resultCallback.onValues(0, 99); + return null; + }).when(driver_2_3).getParameter(eq(21), eq(47), any()); + + assertEquals(99, mCanonical.getModelParameter(21, 47)); + verify(driver_2_3).getParameter(eq(21), eq(47), any()); + } + + @Test + public void testSetParameter() throws Exception { + assumeTrue(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw); + + android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver_2_3 = + (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; + + mCanonical.setModelParameter(212, 247, 80); + verify(driver_2_3).setParameter(212, 247, 80); + } + + @Test + public void testQueryParameterSupported() throws Exception { + assumeTrue(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw); + + android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver_2_3 = + (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; + + doAnswer(invocation -> { + android.hardware.soundtrigger.V2_3.ISoundTriggerHw.queryParameterCallback + resultCallback = invocation.getArgument(2); + + // This is the return of this method. + android.hardware.soundtrigger.V2_3.ModelParameterRange range = + new android.hardware.soundtrigger.V2_3.ModelParameterRange(); + range.start = 34; + range.end = 45; + android.hardware.soundtrigger.V2_3.OptionalModelParameterRange optionalRange = + new android.hardware.soundtrigger.V2_3.OptionalModelParameterRange(); + optionalRange.range(range); + resultCallback.onValues(0, optionalRange); + return null; + }).when(driver_2_3).queryParameter(eq(11), eq(12), any()); + + android.hardware.soundtrigger.V2_3.ModelParameterRange range = mCanonical.queryParameter(11, + 12); + assertNotNull(range); + assertEquals(34, range.start); + assertEquals(45, range.end); + verify(driver_2_3).queryParameter(eq(11), eq(12), any()); + } + + @Test + public void testQueryParameterNotSupported() throws Exception { + if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) { + android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver_2_3 = + (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; + + doAnswer(invocation -> { + android.hardware.soundtrigger.V2_3.ISoundTriggerHw.queryParameterCallback + resultCallback = invocation.getArgument(2); + + // This is the return of this method. + android.hardware.soundtrigger.V2_3.OptionalModelParameterRange optionalRange = + new android.hardware.soundtrigger.V2_3.OptionalModelParameterRange(); + resultCallback.onValues(0, optionalRange); + return null; + }).when(driver_2_3).queryParameter(eq(11), eq(12), any()); + + android.hardware.soundtrigger.V2_3.ModelParameterRange range = + mCanonical.queryParameter(11, 12); + assertNull(range); + verify(driver_2_3).queryParameter(eq(11), eq(12), any()); + } else { + android.hardware.soundtrigger.V2_3.ModelParameterRange range = + mCanonical.queryParameter(11, 12); + assertNull(range); + } + } + + private void testGlobalCallback_2_0() { + ISoundTriggerHw2.GlobalCallback canonicalCallback = mock( + ISoundTriggerHw2.GlobalCallback.class); + mCanonical.registerCallback(canonicalCallback); + // We just care that it doesn't throw. + } + + private void testGlobalCallback_2_4() throws Exception { + android.hardware.soundtrigger.V2_4.ISoundTriggerHw driver_2_4 = + (android.hardware.soundtrigger.V2_4.ISoundTriggerHw) mHalDriver; + + ISoundTriggerHw2.GlobalCallback canonicalCallback = mock( + ISoundTriggerHw2.GlobalCallback.class); + mCanonical.registerCallback(canonicalCallback); + + ArgumentCaptor<android.hardware.soundtrigger.V2_4.ISoundTriggerHwGlobalCallback> + callbackCaptor = ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_4.ISoundTriggerHwGlobalCallback.class); + verify(driver_2_4).registerGlobalCallback(callbackCaptor.capture()); + validateGlobalCallback_2_4(callbackCaptor.getValue(), canonicalCallback); + } + + @Test + public void testGlobalCallback() throws Exception { + if (mHalDriver instanceof android.hardware.soundtrigger.V2_4.ISoundTriggerHw) { + testGlobalCallback_2_4(); + } else { + testGlobalCallback_2_0(); + } + } + + @Test + public void testLinkToDeath() throws Exception { + IHwBinder.DeathRecipient canonicalRecipient = mock(IHwBinder.DeathRecipient.class); + when(mHalDriver.linkToDeath(any(), anyLong())).thenReturn(true); + mCanonical.linkToDeath(canonicalRecipient, 19); + + ArgumentCaptor<IHwBinder.DeathRecipient> recipientCaptor = ArgumentCaptor.forClass( + IHwBinder.DeathRecipient.class); + ArgumentCaptor<Long> cookieCaptor = ArgumentCaptor.forClass(Long.class); + verify(mHalDriver).linkToDeath(recipientCaptor.capture(), cookieCaptor.capture()); + + recipientCaptor.getValue().serviceDied(cookieCaptor.getValue()); + mCanonical.flushCallbacks(); + verify(canonicalRecipient).serviceDied(19); + + mCanonical.unlinkToDeath(canonicalRecipient); + verify(mHalDriver).unlinkToDeath(recipientCaptor.getValue()); + } + + @Test + public void testInterfaceDescriptor() throws Exception { + when(mHalDriver.interfaceDescriptor()).thenReturn("ABCD"); + assertEquals("ABCD", mCanonical.interfaceDescriptor()); + verify(mHalDriver).interfaceDescriptor(); + } + + private void validateGlobalCallback_2_4( + android.hardware.soundtrigger.V2_4.ISoundTriggerHwGlobalCallback hwCallback, + ISoundTriggerHw2.GlobalCallback canonicalCallback) throws Exception { + hwCallback.onResourcesAvailable(); + mCanonical.flushCallbacks(); + verify(canonicalCallback).onResourcesAvailable(); + } + + private void validateCallback_2_0( + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback hwCallback, + ISoundTriggerHw2.ModelCallback canonicalCallback) throws Exception { + { + final int handle = 85; + final int status = + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT; + ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent> + eventCaptor = ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent.class); + + hwCallback.recognitionCallback(TestUtil.createRecognitionEvent_2_0(handle, status, 555), + 99); + mCanonical.flushCallbacks(); + verify(canonicalCallback).recognitionCallback(eventCaptor.capture()); + TestUtil.validateRecognitionEvent_2_1(eventCaptor.getValue(), handle, status, 555); + } + + { + final int handle = 92; + final int status = + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS; + ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent> + eventCaptor = ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent.class); + + hwCallback.phraseRecognitionCallback( + TestUtil.createPhraseRecognitionEvent_2_0(handle, status, 666), 99); + mCanonical.flushCallbacks(); + verify(canonicalCallback).phraseRecognitionCallback(eventCaptor.capture()); + TestUtil.validatePhraseRecognitionEvent_2_1(eventCaptor.getValue(), handle, status, + 666); + } + verifyNoMoreInteractions(canonicalCallback); + clearInvocations(canonicalCallback); + } + + private void validateCallback_2_1( + android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback hwCallback, + ISoundTriggerHw2.ModelCallback canonicalCallback) throws Exception { + { + final int handle = 85; + final int status = + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT; + ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent> + eventCaptor = ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent.class); + + hwCallback.recognitionCallback_2_1( + TestUtil.createRecognitionEvent_2_1(handle, status, 777), + 99); + mCanonical.flushCallbacks(); + verify(canonicalCallback).recognitionCallback(eventCaptor.capture()); + TestUtil.validateRecognitionEvent_2_1(eventCaptor.getValue(), handle, status, 777); + } + + { + final int handle = 92; + final int status = + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS; + ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent> + eventCaptor = ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent.class); + + hwCallback.phraseRecognitionCallback_2_1( + TestUtil.createPhraseRecognitionEvent_2_1(handle, status, 888), 99); + mCanonical.flushCallbacks(); + verify(canonicalCallback).phraseRecognitionCallback(eventCaptor.capture()); + TestUtil.validatePhraseRecognitionEvent_2_1(eventCaptor.getValue(), handle, status, + 888); + } + verifyNoMoreInteractions(canonicalCallback); + clearInvocations(canonicalCallback); + } + + private void validateCallback_2_4( + android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback hwCallback, + ISoundTriggerHw2.ModelCallback canonicalCallback) throws Exception { + { + final int handle = 85; + final int status = + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT; + ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent> + eventCaptor = ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent.class); + + hwCallback.recognitionCallback_2_1( + TestUtil.createRecognitionEvent_2_1(handle, status, 444), + 99); + mCanonical.flushCallbacks(); + verify(canonicalCallback).recognitionCallback(eventCaptor.capture()); + TestUtil.validateRecognitionEvent_2_1(eventCaptor.getValue(), handle, status, 444); + } + + { + final int handle = 92; + final int status = + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS; + ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent> + eventCaptor = ArgumentCaptor.forClass( + android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent.class); + + hwCallback.phraseRecognitionCallback_2_1( + TestUtil.createPhraseRecognitionEvent_2_1(handle, status, 555), 99); + mCanonical.flushCallbacks(); + verify(canonicalCallback).phraseRecognitionCallback(eventCaptor.capture()); + TestUtil.validatePhraseRecognitionEvent_2_1(eventCaptor.getValue(), handle, status, + 555); + } + + { + final int handle = 23; + hwCallback.modelUnloaded(handle); + mCanonical.flushCallbacks(); + verify(canonicalCallback).modelUnloaded(handle); + } + verifyNoMoreInteractions(canonicalCallback); + clearInvocations(canonicalCallback); + } + + public class CaptureStateNotifier implements ICaptureStateNotifier { + private boolean mState = false; + private List<Listener> mListeners = new LinkedList<>(); + + @Override + public boolean registerListener(Listener listener) { + mListeners.add(listener); + return false; + } + + @Override + public void unregisterListener(Listener listener) { + mListeners.remove(listener); + } + + public void setState(boolean state) { + mState = state; + for (Listener listener : mListeners) { + listener.onCaptureStateChange(state); + } + } + + public void verifyNoMoreListeners() { + assertEquals(0, mListeners.size()); + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java index 509eb2563376..c8986d53e696 100644 --- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java +++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java @@ -16,88 +16,52 @@ package com.android.server.soundtrigger_middleware; -import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; 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.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.hardware.audio.common.V2_0.AudioConfig; -import android.hardware.audio.common.V2_0.Uuid; -import android.hardware.soundtrigger.V2_3.OptionalModelParameterRange; -import android.media.audio.common.AudioChannelMask; -import android.media.audio.common.AudioFormat; -import android.media.soundtrigger_middleware.AudioCapabilities; -import android.media.soundtrigger_middleware.ConfidenceLevel; +import android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback; import android.media.soundtrigger_middleware.ISoundTriggerCallback; import android.media.soundtrigger_middleware.ISoundTriggerModule; import android.media.soundtrigger_middleware.ModelParameter; import android.media.soundtrigger_middleware.ModelParameterRange; -import android.media.soundtrigger_middleware.Phrase; import android.media.soundtrigger_middleware.PhraseRecognitionEvent; -import android.media.soundtrigger_middleware.PhraseRecognitionExtra; import android.media.soundtrigger_middleware.PhraseSoundModel; import android.media.soundtrigger_middleware.RecognitionConfig; import android.media.soundtrigger_middleware.RecognitionEvent; -import android.media.soundtrigger_middleware.RecognitionMode; import android.media.soundtrigger_middleware.RecognitionStatus; import android.media.soundtrigger_middleware.SoundModel; -import android.media.soundtrigger_middleware.SoundModelType; import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; import android.media.soundtrigger_middleware.SoundTriggerModuleProperties; -import android.os.HidlMemoryUtil; -import android.os.HwParcel; -import android.os.IHwBinder; -import android.os.IHwInterface; -import android.os.ParcelFileDescriptor; +import android.media.soundtrigger_middleware.Status; import android.os.RemoteException; -import android.os.SharedMemory; -import android.system.ErrnoException; import android.util.Pair; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.runners.JUnit4; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.stubbing.Answer; -import java.io.FileDescriptor; -import java.nio.ByteBuffer; - -@RunWith(Parameterized.class) +@RunWith(JUnit4.class) public class SoundTriggerMiddlewareImplTest { - private static final String TAG = "SoundTriggerMiddlewareImplTest"; - - // We run the test once for every version of the underlying driver. - @Parameterized.Parameters - public static Object[] data() { - return new Object[]{ - mock(android.hardware.soundtrigger.V2_0.ISoundTriggerHw.class), - mock(android.hardware.soundtrigger.V2_1.ISoundTriggerHw.class), - mock(android.hardware.soundtrigger.V2_2.ISoundTriggerHw.class), - mock(android.hardware.soundtrigger.V2_3.ISoundTriggerHw.class), - }; - } - @Mock - @Parameterized.Parameter - public android.hardware.soundtrigger.V2_0.ISoundTriggerHw mHalDriver; + public ISoundTriggerHw2 mHalDriver = mock(ISoundTriggerHw2.class); @Mock - private SoundTriggerMiddlewareImpl.AudioSessionProvider mAudioSessionProvider = mock( + private final SoundTriggerMiddlewareImpl.AudioSessionProvider mAudioSessionProvider = mock( SoundTriggerMiddlewareImpl.AudioSessionProvider.class); private SoundTriggerMiddlewareImpl mService; @@ -106,522 +70,45 @@ public class SoundTriggerMiddlewareImplTest { return mock(ISoundTriggerCallback.Stub.class, Mockito.CALLS_REAL_METHODS); } - private static SoundModel createGenericSoundModel() { - return createSoundModel(SoundModelType.GENERIC); - } - - private static FileDescriptor byteArrayToFileDescriptor(byte[] data) { - try { - SharedMemory shmem = SharedMemory.create("", data.length); - ByteBuffer buffer = shmem.mapReadWrite(); - buffer.put(data); - return shmem.getFileDescriptor(); - } catch (ErrnoException e) { - throw new RuntimeException(e); - } - } - - private static SoundModel createSoundModel(int type) { - SoundModel model = new SoundModel(); - model.type = type; - model.uuid = "12345678-2345-3456-4567-abcdef987654"; - model.vendorUuid = "87654321-5432-6543-7654-456789fedcba"; - byte[] data = new byte[]{91, 92, 93, 94, 95}; - model.data = new ParcelFileDescriptor(byteArrayToFileDescriptor(data)); - model.dataSize = data.length; - return model; - } - - private static PhraseSoundModel createPhraseSoundModel() { - PhraseSoundModel model = new PhraseSoundModel(); - model.common = createSoundModel(SoundModelType.KEYPHRASE); - model.phrases = new Phrase[1]; - model.phrases[0] = new Phrase(); - model.phrases[0].id = 123; - model.phrases[0].users = new int[]{5, 6, 7}; - model.phrases[0].locale = "locale"; - model.phrases[0].text = "text"; - model.phrases[0].recognitionModes = - RecognitionMode.USER_AUTHENTICATION | RecognitionMode.USER_IDENTIFICATION; - return model; - } - - private static android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Properties createDefaultProperties( - boolean supportConcurrentCapture) { - android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Properties properties = - new android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Properties(); - properties.implementor = "implementor"; - properties.description = "description"; - properties.version = 123; - properties.uuid = new Uuid(); - properties.uuid.timeLow = 1; - properties.uuid.timeMid = 2; - properties.uuid.versionAndTimeHigh = 3; - properties.uuid.variantAndClockSeqHigh = 4; - properties.uuid.node = new byte[]{5, 6, 7, 8, 9, 10}; - - properties.maxSoundModels = 456; - properties.maxKeyPhrases = 567; - properties.maxUsers = 678; - properties.recognitionModes = - android.hardware.soundtrigger.V2_0.RecognitionMode.VOICE_TRIGGER - | android.hardware.soundtrigger.V2_0.RecognitionMode.USER_IDENTIFICATION - | android.hardware.soundtrigger.V2_0.RecognitionMode.USER_AUTHENTICATION - | android.hardware.soundtrigger.V2_0.RecognitionMode.GENERIC_TRIGGER; - properties.captureTransition = true; - properties.maxBufferMs = 321; - properties.concurrentCapture = supportConcurrentCapture; - properties.triggerInEvent = true; - properties.powerConsumptionMw = 432; - return properties; - } - - private static android.hardware.soundtrigger.V2_3.Properties createDefaultProperties_2_3( - boolean supportConcurrentCapture) { - android.hardware.soundtrigger.V2_3.Properties properties = - new android.hardware.soundtrigger.V2_3.Properties(); - properties.base = createDefaultProperties(supportConcurrentCapture); - properties.supportedModelArch = "supportedModelArch"; - properties.audioCapabilities = - android.hardware.soundtrigger.V2_3.AudioCapabilities.ECHO_CANCELLATION - | android.hardware.soundtrigger.V2_3.AudioCapabilities.NOISE_SUPPRESSION; - return properties; - } - - private void validateDefaultProperties(SoundTriggerModuleProperties properties, - boolean supportConcurrentCapture) { - assertEquals("implementor", properties.implementor); - assertEquals("description", properties.description); - assertEquals(123, properties.version); - assertEquals("00000001-0002-0003-0004-05060708090a", properties.uuid); - assertEquals(456, properties.maxSoundModels); - assertEquals(567, properties.maxKeyPhrases); - assertEquals(678, properties.maxUsers); - assertEquals(RecognitionMode.GENERIC_TRIGGER - | RecognitionMode.USER_AUTHENTICATION - | RecognitionMode.USER_IDENTIFICATION - | RecognitionMode.VOICE_TRIGGER, properties.recognitionModes); - assertTrue(properties.captureTransition); - assertEquals(321, properties.maxBufferMs); - assertEquals(supportConcurrentCapture, properties.concurrentCapture); - assertTrue(properties.triggerInEvent); - assertEquals(432, properties.powerConsumptionMw); - - if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) { - assertEquals("supportedModelArch", properties.supportedModelArch); - assertEquals(AudioCapabilities.ECHO_CANCELLATION | AudioCapabilities.NOISE_SUPPRESSION, - properties.audioCapabilities); - } else { - assertEquals("", properties.supportedModelArch); - assertEquals(0, properties.audioCapabilities); - } - } - - private void verifyNotGetProperties() throws RemoteException { - if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) { - verify((android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver, - never()).getProperties(any()); - } - } - - private static android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent createRecognitionEvent_2_0( - int hwHandle, - int status) { - android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent halEvent = - new android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent(); - halEvent.status = status; - halEvent.type = SoundModelType.GENERIC; - halEvent.model = hwHandle; - halEvent.captureAvailable = true; - // This field is ignored. - halEvent.captureSession = 123; - halEvent.captureDelayMs = 234; - halEvent.capturePreambleMs = 345; - halEvent.triggerInData = true; - halEvent.audioConfig = new AudioConfig(); - halEvent.audioConfig.sampleRateHz = 456; - halEvent.audioConfig.channelMask = AudioChannelMask.IN_LEFT; - halEvent.audioConfig.format = AudioFormat.MP3; - // hwEvent.audioConfig.offloadInfo is irrelevant. - halEvent.data.add((byte) 31); - halEvent.data.add((byte) 32); - halEvent.data.add((byte) 33); - return halEvent; - } - - private static android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent createRecognitionEvent_2_1( - int hwHandle, - int status) { - android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent halEvent = - new android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent(); - halEvent.header = createRecognitionEvent_2_0(hwHandle, status); - halEvent.header.data.clear(); - halEvent.data = HidlMemoryUtil.byteArrayToHidlMemory(new byte[]{31, 32, 33}); - return halEvent; - } - - private static void validateRecognitionEvent(RecognitionEvent event, int status) { - assertEquals(status, event.status); - assertEquals(SoundModelType.GENERIC, event.type); - assertTrue(event.captureAvailable); - assertEquals(101, event.captureSession); - assertEquals(234, event.captureDelayMs); - assertEquals(345, event.capturePreambleMs); - assertTrue(event.triggerInData); - assertEquals(456, event.audioConfig.sampleRateHz); - assertEquals(AudioChannelMask.IN_LEFT, event.audioConfig.channelMask); - assertEquals(AudioFormat.MP3, event.audioConfig.format); - } - - private static android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent createPhraseRecognitionEvent_2_0( - int hwHandle, int status) { - android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent halEvent = - new android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent(); - halEvent.common = createRecognitionEvent_2_0(hwHandle, status); - - android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halExtra = - new android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra(); - halExtra.id = 123; - halExtra.confidenceLevel = 52; - halExtra.recognitionModes = android.hardware.soundtrigger.V2_0.RecognitionMode.VOICE_TRIGGER - | android.hardware.soundtrigger.V2_0.RecognitionMode.GENERIC_TRIGGER; - android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel = - new android.hardware.soundtrigger.V2_0.ConfidenceLevel(); - halLevel.userId = 31; - halLevel.levelPercent = 43; - halExtra.levels.add(halLevel); - halEvent.phraseExtras.add(halExtra); - return halEvent; - } - - private static android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent createPhraseRecognitionEvent_2_1( - int hwHandle, int status) { - android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent halEvent = - new android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent(); - halEvent.common = createRecognitionEvent_2_1(hwHandle, status); - - android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halExtra = - new android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra(); - halExtra.id = 123; - halExtra.confidenceLevel = 52; - halExtra.recognitionModes = android.hardware.soundtrigger.V2_0.RecognitionMode.VOICE_TRIGGER - | android.hardware.soundtrigger.V2_0.RecognitionMode.GENERIC_TRIGGER; - android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel = - new android.hardware.soundtrigger.V2_0.ConfidenceLevel(); - halLevel.userId = 31; - halLevel.levelPercent = 43; - halExtra.levels.add(halLevel); - halEvent.phraseExtras.add(halExtra); - return halEvent; - } - - private static void validatePhraseRecognitionEvent(PhraseRecognitionEvent event, int status) { - validateRecognitionEvent(event.common, status); - - assertEquals(1, event.phraseExtras.length); - assertEquals(123, event.phraseExtras[0].id); - assertEquals(52, event.phraseExtras[0].confidenceLevel); - assertEquals(RecognitionMode.VOICE_TRIGGER | RecognitionMode.GENERIC_TRIGGER, - event.phraseExtras[0].recognitionModes); - assertEquals(1, event.phraseExtras[0].levels.length); - assertEquals(31, event.phraseExtras[0].levels[0].userId); - assertEquals(43, event.phraseExtras[0].levels[0].levelPercent); - } - - private void initService(boolean supportConcurrentCapture) throws RemoteException { - doAnswer(invocation -> { - android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Properties properties = - createDefaultProperties( - supportConcurrentCapture); - ((android.hardware.soundtrigger.V2_0.ISoundTriggerHw.getPropertiesCallback) invocation.getArgument( - 0)).onValues(0, - properties); - return null; - }).when(mHalDriver).getProperties(any()); - - if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) { - android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver = - (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; - doAnswer(invocation -> { - android.hardware.soundtrigger.V2_3.Properties properties = - createDefaultProperties_2_3( - supportConcurrentCapture); - ((android.hardware.soundtrigger.V2_3.ISoundTriggerHw.getProperties_2_3Callback) - invocation.getArgument( - 0)).onValues(0, - properties); - return null; - }).when(driver).getProperties_2_3(any()); - } - - mService = new SoundTriggerMiddlewareImpl(() -> { - return mHalDriver; - }, mAudioSessionProvider); - } - - private Pair<Integer, SoundTriggerHwCallback> loadGenericModel_2_0(ISoundTriggerModule module, - int hwHandle) throws RemoteException { - SoundModel model = createGenericSoundModel(); - ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel> modelCaptor = - ArgumentCaptor.forClass( - android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel.class); - ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback> callbackCaptor = - ArgumentCaptor.forClass( - android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.class); - ArgumentCaptor<Integer> cookieCaptor = ArgumentCaptor.forClass(Integer.class); - - doAnswer(invocation -> { - android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback callback = - invocation.getArgument(1); - int callbackCookie = invocation.getArgument(2); - android.hardware.soundtrigger.V2_0.ISoundTriggerHw.loadSoundModelCallback - resultCallback = invocation.getArgument(3); - - // This is the return of this method. - resultCallback.onValues(0, hwHandle); - - // This is the async mCallback that comes after. - android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.ModelEvent modelEvent = - new android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.ModelEvent(); - modelEvent.status = - android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.SoundModelStatus.UPDATED; - modelEvent.model = hwHandle; - callback.soundModelCallback(modelEvent, callbackCookie); - return null; - }).when(mHalDriver).loadSoundModel(modelCaptor.capture(), callbackCaptor.capture(), - cookieCaptor.capture(), any()); - - when(mAudioSessionProvider.acquireSession()).thenReturn( - new SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession(101, 102, 103)); - - int handle = module.loadModel(model); - verify(mHalDriver).loadSoundModel(any(), any(), anyInt(), any()); - verify(mAudioSessionProvider).acquireSession(); - - android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel hidlModel = - modelCaptor.getValue(); - assertEquals(android.hardware.soundtrigger.V2_0.SoundModelType.GENERIC, - hidlModel.type); - assertEquals(model.uuid, ConversionUtil.hidl2aidlUuid(hidlModel.uuid)); - assertEquals(model.vendorUuid, ConversionUtil.hidl2aidlUuid(hidlModel.vendorUuid)); - assertArrayEquals(new Byte[]{91, 92, 93, 94, 95}, hidlModel.data.toArray()); - - return new Pair<>(handle, - new SoundTriggerHwCallback(callbackCaptor.getValue(), cookieCaptor.getValue())); - } - - private Pair<Integer, SoundTriggerHwCallback> loadGenericModel_2_1(ISoundTriggerModule module, + private Pair<Integer, SoundTriggerHwCallback> loadGenericModel(ISoundTriggerModule module, int hwHandle) throws RemoteException { - android.hardware.soundtrigger.V2_1.ISoundTriggerHw driver = - (android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver; - SoundModel model = createGenericSoundModel(); + SoundModel model = TestUtil.createGenericSoundModel(); ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel> modelCaptor = ArgumentCaptor.forClass( android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel.class); - ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> callbackCaptor = - ArgumentCaptor.forClass( - android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class); - ArgumentCaptor<Integer> cookieCaptor = ArgumentCaptor.forClass(Integer.class); - - doAnswer(invocation -> { - android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback callback = - invocation.getArgument(1); - int callbackCookie = invocation.getArgument(2); - android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadSoundModel_2_1Callback - resultCallback = invocation.getArgument(3); - - // This is the return of this method. - resultCallback.onValues(0, hwHandle); - - // This is the async mCallback that comes after. - android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.ModelEvent modelEvent = - new android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.ModelEvent(); - modelEvent.header.status = - android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.SoundModelStatus.UPDATED; - modelEvent.header.model = hwHandle; - callback.soundModelCallback_2_1(modelEvent, callbackCookie); - return null; - }).when(driver).loadSoundModel_2_1(modelCaptor.capture(), callbackCaptor.capture(), - cookieCaptor.capture(), any()); + ArgumentCaptor<ISoundTriggerHw2.ModelCallback> callbackCaptor = + ArgumentCaptor.forClass(ISoundTriggerHw2.ModelCallback.class); + when(mHalDriver.loadSoundModel(any(), any())).thenReturn( + hwHandle); when(mAudioSessionProvider.acquireSession()).thenReturn( new SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession(101, 102, 103)); int handle = module.loadModel(model); - verify(driver).loadSoundModel_2_1(any(), any(), anyInt(), any()); - verify(mAudioSessionProvider).acquireSession(); - - android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel hidlModel = - modelCaptor.getValue(); - assertEquals(android.hardware.soundtrigger.V2_0.SoundModelType.GENERIC, - hidlModel.header.type); - assertEquals(model.uuid, ConversionUtil.hidl2aidlUuid(hidlModel.header.uuid)); - assertEquals(model.vendorUuid, ConversionUtil.hidl2aidlUuid(hidlModel.header.vendorUuid)); - assertArrayEquals(new byte[]{91, 92, 93, 94, 95}, - HidlMemoryUtil.hidlMemoryToByteArray(hidlModel.data)); - - return new Pair<>(handle, - new SoundTriggerHwCallback(callbackCaptor.getValue(), cookieCaptor.getValue())); - } - - private Pair<Integer, SoundTriggerHwCallback> loadGenericModel(ISoundTriggerModule module, - int hwHandle) throws RemoteException { - if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) { - return loadGenericModel_2_1(module, hwHandle); - } else { - return loadGenericModel_2_0(module, hwHandle); - } - } - - private Pair<Integer, SoundTriggerHwCallback> loadPhraseModel_2_0(ISoundTriggerModule module, - int hwHandle) throws RemoteException { - PhraseSoundModel model = createPhraseSoundModel(); - ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel> - modelCaptor = ArgumentCaptor.forClass( - android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel.class); - ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback> callbackCaptor = - ArgumentCaptor.forClass( - android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.class); - ArgumentCaptor<Integer> cookieCaptor = ArgumentCaptor.forClass(Integer.class); - - doAnswer(invocation -> { - android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback callback = - invocation.getArgument( - 1); - int callbackCookie = invocation.getArgument(2); - android.hardware.soundtrigger.V2_0.ISoundTriggerHw.loadPhraseSoundModelCallback - resultCallback = - invocation.getArgument( - 3); - - // This is the return of this method. - resultCallback.onValues(0, hwHandle); - - // This is the async mCallback that comes after. - android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.ModelEvent modelEvent = - new android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.ModelEvent(); - modelEvent.status = - android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.SoundModelStatus.UPDATED; - modelEvent.model = hwHandle; - callback.soundModelCallback(modelEvent, callbackCookie); - return null; - }).when(mHalDriver).loadPhraseSoundModel(modelCaptor.capture(), callbackCaptor.capture(), - cookieCaptor.capture(), any()); - - when(mAudioSessionProvider.acquireSession()).thenReturn( - new SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession(101, 102, 103)); - - int handle = module.loadPhraseModel(model); - verify(mHalDriver).loadPhraseSoundModel(any(), any(), anyInt(), any()); + verify(mHalDriver).loadSoundModel(modelCaptor.capture(), callbackCaptor.capture()); verify(mAudioSessionProvider).acquireSession(); - - android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel hidlModel = - modelCaptor.getValue(); - - // Validate common part. - assertEquals(android.hardware.soundtrigger.V2_0.SoundModelType.KEYPHRASE, - hidlModel.common.type); - assertEquals(model.common.uuid, ConversionUtil.hidl2aidlUuid(hidlModel.common.uuid)); - assertEquals(model.common.vendorUuid, - ConversionUtil.hidl2aidlUuid(hidlModel.common.vendorUuid)); - assertArrayEquals(new Byte[]{91, 92, 93, 94, 95}, hidlModel.common.data.toArray()); - - // Validate phrase part. - assertEquals(1, hidlModel.phrases.size()); - android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Phrase hidlPhrase = - hidlModel.phrases.get(0); - assertEquals(123, hidlPhrase.id); - assertArrayEquals(new Integer[]{5, 6, 7}, hidlPhrase.users.toArray()); - assertEquals("locale", hidlPhrase.locale); - assertEquals("text", hidlPhrase.text); - assertEquals(android.hardware.soundtrigger.V2_0.RecognitionMode.USER_AUTHENTICATION - | android.hardware.soundtrigger.V2_0.RecognitionMode.USER_IDENTIFICATION, - hidlPhrase.recognitionModes); - - return new Pair<>(handle, - new SoundTriggerHwCallback(callbackCaptor.getValue(), cookieCaptor.getValue())); + TestUtil.validateGenericSoundModel_2_1(modelCaptor.getValue()); + return new Pair<>(handle, new SoundTriggerHwCallback(callbackCaptor.getValue())); } - private Pair<Integer, SoundTriggerHwCallback> loadPhraseModel_2_1(ISoundTriggerModule module, - int hwHandle) throws RemoteException { - android.hardware.soundtrigger.V2_1.ISoundTriggerHw driver = - (android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver; - - PhraseSoundModel model = createPhraseSoundModel(); + private Pair<Integer, SoundTriggerHwCallback> loadPhraseModel( + ISoundTriggerModule module, int hwHandle) throws RemoteException { + PhraseSoundModel model = TestUtil.createPhraseSoundModel(); ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel> modelCaptor = ArgumentCaptor.forClass( android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel.class); - ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> callbackCaptor = - ArgumentCaptor.forClass( - android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class); - ArgumentCaptor<Integer> cookieCaptor = ArgumentCaptor.forClass(Integer.class); - - doAnswer(invocation -> { - android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback callback = - invocation.getArgument( - 1); - int callbackCookie = invocation.getArgument(2); - android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadPhraseSoundModel_2_1Callback - resultCallback = - invocation.getArgument( - 3); - - // This is the return of this method. - resultCallback.onValues(0, hwHandle); - - // This is the async mCallback that comes after. - android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.ModelEvent modelEvent = - new android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.ModelEvent(); - modelEvent.header.status = - android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.SoundModelStatus.UPDATED; - modelEvent.header.model = hwHandle; - callback.soundModelCallback_2_1(modelEvent, callbackCookie); - return null; - }).when(driver).loadPhraseSoundModel_2_1(modelCaptor.capture(), callbackCaptor.capture(), - cookieCaptor.capture(), any()); + ArgumentCaptor<ISoundTriggerHw2.ModelCallback> callbackCaptor = + ArgumentCaptor.forClass(ISoundTriggerHw2.ModelCallback.class); + when(mHalDriver.loadPhraseSoundModel(any(), any())).thenReturn(hwHandle); when(mAudioSessionProvider.acquireSession()).thenReturn( new SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession(101, 102, 103)); int handle = module.loadPhraseModel(model); - verify(driver).loadPhraseSoundModel_2_1(any(), any(), anyInt(), any()); + verify(mHalDriver).loadPhraseSoundModel(modelCaptor.capture(), callbackCaptor.capture()); verify(mAudioSessionProvider).acquireSession(); - - android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel hidlModel = - modelCaptor.getValue(); - - // Validate common part. - assertEquals(android.hardware.soundtrigger.V2_0.SoundModelType.KEYPHRASE, - hidlModel.common.header.type); - assertEquals(model.common.uuid, ConversionUtil.hidl2aidlUuid(hidlModel.common.header.uuid)); - assertEquals(model.common.vendorUuid, - ConversionUtil.hidl2aidlUuid(hidlModel.common.header.vendorUuid)); - assertArrayEquals(new byte[]{91, 92, 93, 94, 95}, - HidlMemoryUtil.hidlMemoryToByteArray(hidlModel.common.data)); - - // Validate phrase part. - assertEquals(1, hidlModel.phrases.size()); - android.hardware.soundtrigger.V2_1.ISoundTriggerHw.Phrase hidlPhrase = - hidlModel.phrases.get(0); - assertEquals(123, hidlPhrase.id); - assertArrayEquals(new Integer[]{5, 6, 7}, hidlPhrase.users.toArray()); - assertEquals("locale", hidlPhrase.locale); - assertEquals("text", hidlPhrase.text); - assertEquals(android.hardware.soundtrigger.V2_0.RecognitionMode.USER_AUTHENTICATION - | android.hardware.soundtrigger.V2_0.RecognitionMode.USER_IDENTIFICATION, - hidlPhrase.recognitionModes); - - return new Pair<>(handle, - new SoundTriggerHwCallback(callbackCaptor.getValue(), cookieCaptor.getValue())); - } - - private Pair<Integer, SoundTriggerHwCallback> loadPhraseModel( - ISoundTriggerModule module, int hwHandle) throws RemoteException { - if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) { - return loadPhraseModel_2_1(module, hwHandle); - } else { - return loadPhraseModel_2_0(module, hwHandle); - } + TestUtil.validatePhraseSoundModel_2_1(modelCaptor.getValue()); + return new Pair<>(handle, new SoundTriggerHwCallback(callbackCaptor.getValue())); } private void unloadModel(ISoundTriggerModule module, int handle, int hwHandle) @@ -631,204 +118,37 @@ public class SoundTriggerMiddlewareImplTest { verify(mAudioSessionProvider).releaseSession(101); } - private void startRecognition_2_0(ISoundTriggerModule module, int handle, - int hwHandle) throws RemoteException { - ArgumentCaptor<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.RecognitionConfig> - configCaptor = ArgumentCaptor.forClass( - android.hardware.soundtrigger.V2_0.ISoundTriggerHw.RecognitionConfig.class); - - when(mHalDriver.startRecognition(eq(hwHandle), configCaptor.capture(), any(), anyInt())) - .thenReturn(0); - - RecognitionConfig config = createRecognitionConfig(); - - module.startRecognition(handle, config); - verify(mHalDriver).startRecognition(eq(hwHandle), any(), any(), anyInt()); - - android.hardware.soundtrigger.V2_0.ISoundTriggerHw.RecognitionConfig halConfig = - configCaptor.getValue(); - assertTrue(halConfig.captureRequested); - assertEquals(102, halConfig.captureHandle); - assertEquals(103, halConfig.captureDevice); - assertEquals(1, halConfig.phrases.size()); - android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halPhraseExtra = - halConfig.phrases.get(0); - assertEquals(123, halPhraseExtra.id); - assertEquals(4, halPhraseExtra.confidenceLevel); - assertEquals(5, halPhraseExtra.recognitionModes); - assertEquals(1, halPhraseExtra.levels.size()); - android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel = halPhraseExtra.levels.get(0); - assertEquals(234, halLevel.userId); - assertEquals(34, halLevel.levelPercent); - assertArrayEquals(new Byte[]{5, 4, 3, 2, 1}, halConfig.data.toArray()); - } - - private void startRecognition_2_1(ISoundTriggerModule module, int handle, - int hwHandle) throws RemoteException { - android.hardware.soundtrigger.V2_1.ISoundTriggerHw driver = - (android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver; - - ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig> - configCaptor = ArgumentCaptor.forClass( - android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig.class); - - when(driver.startRecognition_2_1(eq(hwHandle), configCaptor.capture(), any(), anyInt())) - .thenReturn(0); - - RecognitionConfig config = createRecognitionConfig(); - - module.startRecognition(handle, config); - verify(driver).startRecognition_2_1(eq(hwHandle), any(), any(), anyInt()); - - android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig halConfig = - configCaptor.getValue(); - assertTrue(halConfig.header.captureRequested); - assertEquals(102, halConfig.header.captureHandle); - assertEquals(103, halConfig.header.captureDevice); - assertEquals(1, halConfig.header.phrases.size()); - android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halPhraseExtra = - halConfig.header.phrases.get(0); - assertEquals(123, halPhraseExtra.id); - assertEquals(4, halPhraseExtra.confidenceLevel); - assertEquals(5, halPhraseExtra.recognitionModes); - assertEquals(1, halPhraseExtra.levels.size()); - android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel = halPhraseExtra.levels.get(0); - assertEquals(234, halLevel.userId); - assertEquals(34, halLevel.levelPercent); - assertArrayEquals(new byte[]{5, 4, 3, 2, 1}, - HidlMemoryUtil.hidlMemoryToByteArray(halConfig.data)); - } - - private void startRecognition_2_3(ISoundTriggerModule module, int handle, + private void startRecognition(ISoundTriggerModule module, int handle, int hwHandle) throws RemoteException { - android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver = - (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; - ArgumentCaptor<android.hardware.soundtrigger.V2_3.RecognitionConfig> configCaptor = ArgumentCaptor.forClass( android.hardware.soundtrigger.V2_3.RecognitionConfig.class); - when(driver.startRecognition_2_3(eq(hwHandle), configCaptor.capture())).thenReturn(0); - - RecognitionConfig config = createRecognitionConfig(); + RecognitionConfig config = TestUtil.createRecognitionConfig(); module.startRecognition(handle, config); - verify(driver).startRecognition_2_3(eq(hwHandle), any()); - - android.hardware.soundtrigger.V2_3.RecognitionConfig halConfigExtended = - configCaptor.getValue(); - android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig halConfig_2_1 = - halConfigExtended.base; - - assertTrue(halConfig_2_1.header.captureRequested); - assertEquals(102, halConfig_2_1.header.captureHandle); - assertEquals(103, halConfig_2_1.header.captureDevice); - assertEquals(1, halConfig_2_1.header.phrases.size()); - android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halPhraseExtra = - halConfig_2_1.header.phrases.get(0); - assertEquals(123, halPhraseExtra.id); - assertEquals(4, halPhraseExtra.confidenceLevel); - assertEquals(5, halPhraseExtra.recognitionModes); - assertEquals(1, halPhraseExtra.levels.size()); - android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel = halPhraseExtra.levels.get(0); - assertEquals(234, halLevel.userId); - assertEquals(34, halLevel.levelPercent); - assertArrayEquals(new byte[]{5, 4, 3, 2, 1}, - HidlMemoryUtil.hidlMemoryToByteArray(halConfig_2_1.data)); - assertEquals(AudioCapabilities.ECHO_CANCELLATION - | AudioCapabilities.NOISE_SUPPRESSION, halConfigExtended.audioCapabilities); - } - - private void startRecognition(ISoundTriggerModule module, int handle, - int hwHandle) throws RemoteException { - if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) { - startRecognition_2_3(module, handle, hwHandle); - } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) { - startRecognition_2_1(module, handle, hwHandle); - } else { - startRecognition_2_0(module, handle, hwHandle); - } - } - - private RecognitionConfig createRecognitionConfig() { - RecognitionConfig config = new RecognitionConfig(); - config.captureRequested = true; - config.phraseRecognitionExtras = new PhraseRecognitionExtra[]{new PhraseRecognitionExtra()}; - config.phraseRecognitionExtras[0].id = 123; - config.phraseRecognitionExtras[0].confidenceLevel = 4; - config.phraseRecognitionExtras[0].recognitionModes = 5; - config.phraseRecognitionExtras[0].levels = new ConfidenceLevel[]{new ConfidenceLevel()}; - config.phraseRecognitionExtras[0].levels[0].userId = 234; - config.phraseRecognitionExtras[0].levels[0].levelPercent = 34; - config.data = new byte[]{5, 4, 3, 2, 1}; - config.audioCapabilities = AudioCapabilities.ECHO_CANCELLATION - | AudioCapabilities.NOISE_SUPPRESSION; - return config; + verify(mHalDriver).startRecognition(eq(hwHandle), configCaptor.capture()); + TestUtil.validateRecognitionConfig_2_3(configCaptor.getValue(), 102, 103); } private void stopRecognition(ISoundTriggerModule module, int handle, int hwHandle) throws RemoteException { - when(mHalDriver.stopRecognition(hwHandle)).thenReturn(0); module.stopRecognition(handle); verify(mHalDriver).stopRecognition(hwHandle); } - private void verifyNotStartRecognition() throws RemoteException { - verify(mHalDriver, never()).startRecognition(anyInt(), any(), any(), anyInt()); - if (mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw) { - verify((android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver, - never()).startRecognition_2_1(anyInt(), any(), any(), anyInt()); - } else if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) { - verify((android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver, - never()).startRecognition_2_3(anyInt(), any()); - } - } - - @Before public void setUp() throws Exception { clearInvocations(mHalDriver); clearInvocations(mAudioSessionProvider); + when(mHalDriver.getProperties()).thenReturn( + TestUtil.createDefaultProperties_2_3(false)); + mService = new SoundTriggerMiddlewareImpl(() -> mHalDriver, mAudioSessionProvider); + } - // This binder is associated with the mock, so it can be cast to either version of the - // HAL interface. - final IHwBinder binder = new IHwBinder() { - @Override - public void transact(int code, HwParcel request, HwParcel reply, int flags) - throws RemoteException { - // This is a little hacky, but a very easy way to gracefully reject a request for - // an unsupported interface (after queryLocalInterface() returns null, the client - // will attempt a remote transaction to obtain the interface. RemoteException will - // cause it to give up). - throw new RemoteException(); - } - - @Override - public IHwInterface queryLocalInterface(String descriptor) { - if (descriptor.equals("android.hardware.soundtrigger@2.0::ISoundTriggerHw") - || descriptor.equals("android.hardware.soundtrigger@2.1::ISoundTriggerHw") - && mHalDriver instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHw - || descriptor.equals("android.hardware.soundtrigger@2.2::ISoundTriggerHw") - && mHalDriver instanceof android.hardware.soundtrigger.V2_2.ISoundTriggerHw - || descriptor.equals("android.hardware.soundtrigger@2.3::ISoundTriggerHw") - && mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) { - return mHalDriver; - } - return null; - } - - @Override - public boolean linkToDeath(DeathRecipient recipient, long cookie) { - return true; - } - - @Override - public boolean unlinkToDeath(DeathRecipient recipient) { - return true; - } - }; - - when(mHalDriver.asBinder()).thenReturn(binder); + @After + public void tearDown() { + verify(mHalDriver, never()).reboot(); } @Test @@ -836,8 +156,7 @@ public class SoundTriggerMiddlewareImplTest { } @Test - public void testListModules() throws Exception { - initService(true); + public void testListModules() { // Note: input and output properties are NOT the same type, even though they are in any way // equivalent. One is a type that's exposed by the HAL and one is a type that's exposed by // the service. The service actually performs a (trivial) conversion between the two. @@ -846,60 +165,50 @@ public class SoundTriggerMiddlewareImplTest { SoundTriggerModuleProperties properties = allDescriptors[0].properties; - validateDefaultProperties(properties, true); - verifyNotGetProperties(); + TestUtil.validateDefaultProperties(properties, false); } @Test public void testAttachDetach() throws Exception { // Normal attachment / detachment. - initService(true); ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); - verify(callback).onRecognitionAvailabilityChange(true); assertNotNull(module); module.detach(); } @Test - public void testAttachDetachNotAvailable() throws Exception { - // Attachment / detachment during external capture, with a module not supporting concurrent - // capture. - initService(false); + public void testLoadUnloadModel() throws Exception { ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); - verify(callback).onRecognitionAvailabilityChange(false); - assertNotNull(module); - module.detach(); - } - @Test - public void testAttachDetachAvailable() throws Exception { - // Attachment / detachment during external capture, with a module supporting concurrent - // capture. - initService(true); - ISoundTriggerCallback callback = createCallbackMock(); - ISoundTriggerModule module = mService.attach(0, callback); - verify(callback).onRecognitionAvailabilityChange(true); - assertNotNull(module); + final int hwHandle = 7; + int handle = loadGenericModel(module, hwHandle).first; + unloadModel(module, handle, hwHandle); module.detach(); } @Test - public void testLoadUnloadModel() throws Exception { - initService(true); + public void testLoadPreemptModel() throws Exception { ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); final int hwHandle = 7; - int handle = loadGenericModel(module, hwHandle).first; - unloadModel(module, handle, hwHandle); + Pair<Integer, SoundTriggerHwCallback> loadResult = loadGenericModel(module, hwHandle); + + int handle = loadResult.first; + SoundTriggerHwCallback hwCallback = loadResult.second; + + // Signal preemption. + hwCallback.sendUnloadEvent(hwHandle); + + verify(callback).onModelUnloaded(handle); + module.detach(); } @Test public void testLoadUnloadPhraseModel() throws Exception { - initService(true); ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); @@ -911,7 +220,6 @@ public class SoundTriggerMiddlewareImplTest { @Test public void testStartStopRecognition() throws Exception { - initService(true); ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); @@ -931,8 +239,31 @@ public class SoundTriggerMiddlewareImplTest { } @Test + public void testStartRecognitionBusy() throws Exception { + ISoundTriggerCallback callback = createCallbackMock(); + ISoundTriggerModule module = mService.attach(0, callback); + + // Load the model. + final int hwHandle = 7; + int handle = loadGenericModel(module, hwHandle).first; + + // Start the model. + doThrow(new RecoverableException(Status.RESOURCE_CONTENTION)).when( + mHalDriver).startRecognition(eq(7), any()); + + try { + RecognitionConfig config = TestUtil.createRecognitionConfig(); + module.startRecognition(handle, config); + fail("Expected an exception"); + } catch (RecoverableException e) { + assertEquals(Status.RESOURCE_CONTENTION, e.errorCode); + } + + verify(mHalDriver).startRecognition(eq(7), any()); + } + + @Test public void testStartStopPhraseRecognition() throws Exception { - initService(true); ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); @@ -953,7 +284,6 @@ public class SoundTriggerMiddlewareImplTest { @Test public void testRecognition() throws Exception { - initService(true); ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); @@ -968,14 +298,15 @@ public class SoundTriggerMiddlewareImplTest { // Signal a capture from the driver. hwCallback.sendRecognitionEvent(hwHandle, - android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS); + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS, + 101); ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass( RecognitionEvent.class); verify(callback).onRecognition(eq(handle), eventCaptor.capture()); // Validate the event. - validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.SUCCESS); + TestUtil.validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.SUCCESS, 101); // Unload the model. unloadModel(module, handle, hwHandle); @@ -984,7 +315,6 @@ public class SoundTriggerMiddlewareImplTest { @Test public void testPhraseRecognition() throws Exception { - initService(true); ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); @@ -999,14 +329,16 @@ public class SoundTriggerMiddlewareImplTest { // Signal a capture from the driver. hwCallback.sendPhraseRecognitionEvent(hwHandle, - android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS); + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS, + 101); ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass( PhraseRecognitionEvent.class); verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture()); // Validate the event. - validatePhraseRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.SUCCESS); + TestUtil.validatePhraseRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.SUCCESS, + 101); // Unload the model. unloadModel(module, handle, hwHandle); @@ -1015,14 +347,6 @@ public class SoundTriggerMiddlewareImplTest { @Test public void testForceRecognition() throws Exception { - if (!(mHalDriver instanceof android.hardware.soundtrigger.V2_2.ISoundTriggerHw)) { - return; - } - - android.hardware.soundtrigger.V2_2.ISoundTriggerHw driver = - (android.hardware.soundtrigger.V2_2.ISoundTriggerHw) mHalDriver; - - initService(true); ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); @@ -1037,18 +361,18 @@ public class SoundTriggerMiddlewareImplTest { // Force a trigger. module.forceRecognitionEvent(handle); - verify(driver).getModelState(hwHandle); + verify(mHalDriver).getModelState(hwHandle); // Signal a capture from the driver. // '3' means 'forced', there's no constant for that in the HAL. - hwCallback.sendRecognitionEvent(hwHandle, 3); + hwCallback.sendRecognitionEvent(hwHandle, 3, 101); ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass( RecognitionEvent.class); verify(callback).onRecognition(eq(handle), eventCaptor.capture()); // Validate the event. - validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.FORCED); + TestUtil.validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.FORCED, 101); // Stop the recognition. stopRecognition(module, handle, hwHandle); @@ -1059,15 +383,38 @@ public class SoundTriggerMiddlewareImplTest { } @Test - public void testForcePhraseRecognition() throws Exception { - if (!(mHalDriver instanceof android.hardware.soundtrigger.V2_2.ISoundTriggerHw)) { - return; + public void testForceRecognitionNotSupported() throws Exception { + ISoundTriggerCallback callback = createCallbackMock(); + ISoundTriggerModule module = mService.attach(0, callback); + + // Load the model. + final int hwHandle = 17; + Pair<Integer, SoundTriggerHwCallback> modelHandles = loadGenericModel(module, hwHandle); + int handle = modelHandles.first; + + // Initiate a recognition. + startRecognition(module, handle, hwHandle); + + // Force a trigger. + doThrow(new RecoverableException(Status.OPERATION_NOT_SUPPORTED)).when( + mHalDriver).getModelState(hwHandle); + try { + module.forceRecognitionEvent(handle); + fail("Expected an exception"); + } catch (RecoverableException e) { + assertEquals(Status.OPERATION_NOT_SUPPORTED, e.errorCode); } - android.hardware.soundtrigger.V2_2.ISoundTriggerHw driver = - (android.hardware.soundtrigger.V2_2.ISoundTriggerHw) mHalDriver; + // Stop the recognition. + stopRecognition(module, handle, hwHandle); - initService(true); + // Unload the model. + unloadModel(module, handle, hwHandle); + module.detach(); + } + + @Test + public void testForcePhraseRecognition() throws Exception { ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); @@ -1082,18 +429,19 @@ public class SoundTriggerMiddlewareImplTest { // Force a trigger. module.forceRecognitionEvent(handle); - verify(driver).getModelState(hwHandle); + verify(mHalDriver).getModelState(hwHandle); // Signal a capture from the driver. // '3' means 'forced', there's no constant for that in the HAL. - hwCallback.sendPhraseRecognitionEvent(hwHandle, 3); + hwCallback.sendPhraseRecognitionEvent(hwHandle, 3, 101); ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass( PhraseRecognitionEvent.class); verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture()); // Validate the event. - validatePhraseRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.FORCED); + TestUtil.validatePhraseRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.FORCED, + 101); // Stop the recognition. stopRecognition(module, handle, hwHandle); @@ -1104,47 +452,30 @@ public class SoundTriggerMiddlewareImplTest { } @Test - public void testAbortRecognition() throws Exception { - // Make sure the HAL doesn't support concurrent capture. - initService(false); - mService.setCaptureState(false); - + public void testForcePhraseRecognitionNotSupported() throws Exception { ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); - verify(callback).onRecognitionAvailabilityChange(true); // Load the model. - final int hwHandle = 11; - int handle = loadGenericModel(module, hwHandle).first; + final int hwHandle = 17; + Pair<Integer, SoundTriggerHwCallback> modelHandles = loadPhraseModel(module, hwHandle); + int handle = modelHandles.first; // Initiate a recognition. startRecognition(module, handle, hwHandle); - // Abort. - mService.setCaptureState(true); - - ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass( - RecognitionEvent.class); - verify(callback).onRecognition(eq(handle), eventCaptor.capture()); - - // Validate the event. - assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().status); - - // Make sure we are notified of the lost availability. - verify(callback).onRecognitionAvailabilityChange(false); - - // Attempt to start a new recognition - should get an abort event immediately, without - // involving the HAL. - clearInvocations(callback); - clearInvocations(mHalDriver); - module.startRecognition(handle, createRecognitionConfig()); - verify(callback).onRecognition(eq(handle), eventCaptor.capture()); - assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().status); - verifyNotStartRecognition(); + // Force a trigger. + doThrow(new RecoverableException(Status.OPERATION_NOT_SUPPORTED)).when( + mHalDriver).getModelState(hwHandle); + try { + module.forceRecognitionEvent(handle); + fail("Expected an exception"); + } catch (RecoverableException e) { + assertEquals(Status.OPERATION_NOT_SUPPORTED, e.errorCode); + } - // Now enable it and make sure we are notified. - mService.setCaptureState(false); - verify(callback).onRecognitionAvailabilityChange(true); + // Stop the recognition. + stopRecognition(module, handle, hwHandle); // Unload the model. unloadModel(module, handle, hwHandle); @@ -1152,47 +483,30 @@ public class SoundTriggerMiddlewareImplTest { } @Test - public void testAbortPhraseRecognition() throws Exception { + public void testAbortRecognition() throws Exception { // Make sure the HAL doesn't support concurrent capture. - initService(false); - mService.setCaptureState(false); - ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); - verify(callback).onRecognitionAvailabilityChange(true); // Load the model. final int hwHandle = 11; - int handle = loadPhraseModel(module, hwHandle).first; + Pair<Integer, SoundTriggerHwCallback> loadResult = loadGenericModel(module, hwHandle); + int handle = loadResult.first; + SoundTriggerHwCallback hwCallback = loadResult.second; // Initiate a recognition. startRecognition(module, handle, hwHandle); // Abort. - mService.setCaptureState(true); + hwCallback.sendRecognitionEvent(hwHandle, ISoundTriggerHwCallback.RecognitionStatus.ABORT, + 99); - ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass( - PhraseRecognitionEvent.class); - verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture()); + ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass( + RecognitionEvent.class); + verify(callback).onRecognition(eq(handle), eventCaptor.capture()); // Validate the event. - assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().common.status); - - // Make sure we are notified of the lost availability. - verify(callback).onRecognitionAvailabilityChange(false); - - // Attempt to start a new recognition - should get an abort event immediately, without - // involving the HAL. - clearInvocations(callback); - clearInvocations(mHalDriver); - module.startRecognition(handle, createRecognitionConfig()); - verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture()); - assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().common.status); - verifyNotStartRecognition(); - - // Now enable it and make sure we are notified. - mService.setCaptureState(false); - verify(callback).onRecognitionAvailabilityChange(true); + assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().status); // Unload the model. unloadModel(module, handle, hwHandle); @@ -1200,252 +514,133 @@ public class SoundTriggerMiddlewareImplTest { } @Test - public void testNotAbortRecognitionConcurrent() throws Exception { - // Make sure the HAL supports concurrent capture. - initService(true); - - ISoundTriggerCallback callback = createCallbackMock(); - ISoundTriggerModule module = mService.attach(0, callback); - verify(callback).onRecognitionAvailabilityChange(true); - clearInvocations(callback); - - // Load the model. - final int hwHandle = 13; - int handle = loadGenericModel(module, hwHandle).first; - - // Initiate a recognition. - startRecognition(module, handle, hwHandle); - - // Signal concurrent capture. Shouldn't abort. - mService.setCaptureState(true); - verify(callback, never()).onRecognition(anyInt(), any()); - verify(callback, never()).onRecognitionAvailabilityChange(anyBoolean()); - - // Stop the recognition. - stopRecognition(module, handle, hwHandle); - - // Initiating a new one should work fine. - clearInvocations(mHalDriver); - startRecognition(module, handle, hwHandle); - verify(callback, never()).onRecognition(anyInt(), any()); - stopRecognition(module, handle, hwHandle); - - // Unload the model. - module.unloadModel(handle); - module.detach(); - } - - @Test - public void testNotAbortPhraseRecognitionConcurrent() throws Exception { - // Make sure the HAL supports concurrent capture. - initService(true); - + public void testAbortPhraseRecognition() throws Exception { + // Make sure the HAL doesn't support concurrent capture. ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); - verify(callback).onRecognitionAvailabilityChange(true); - clearInvocations(callback); // Load the model. - final int hwHandle = 13; - int handle = loadPhraseModel(module, hwHandle).first; + final int hwHandle = 11; + Pair<Integer, SoundTriggerHwCallback> loadResult = loadPhraseModel(module, hwHandle); + int handle = loadResult.first; + SoundTriggerHwCallback hwCallback = loadResult.second; // Initiate a recognition. startRecognition(module, handle, hwHandle); - // Signal concurrent capture. Shouldn't abort. - mService.setCaptureState(true); - verify(callback, never()).onPhraseRecognition(anyInt(), any()); - verify(callback, never()).onRecognitionAvailabilityChange(anyBoolean()); + // Abort. + hwCallback.sendPhraseRecognitionEvent(hwHandle, + ISoundTriggerHwCallback.RecognitionStatus.ABORT, 333); - // Stop the recognition. - stopRecognition(module, handle, hwHandle); + ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass( + PhraseRecognitionEvent.class); + verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture()); - // Initiating a new one should work fine. - clearInvocations(mHalDriver); - startRecognition(module, handle, hwHandle); - verify(callback, never()).onRecognition(anyInt(), any()); - stopRecognition(module, handle, hwHandle); + // Validate the event. + assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().common.status); // Unload the model. - module.unloadModel(handle); + unloadModel(module, handle, hwHandle); module.detach(); } @Test public void testParameterSupported() throws Exception { - if (!(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw)) { - return; - } - - android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver = - (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; - - initService(false); ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); final int hwHandle = 12; int modelHandle = loadGenericModel(module, hwHandle).first; - doAnswer((Answer<Void>) invocation -> { - android.hardware.soundtrigger.V2_3.ISoundTriggerHw.queryParameterCallback - resultCallback = invocation.getArgument(2); - android.hardware.soundtrigger.V2_3.ModelParameterRange range = - new android.hardware.soundtrigger.V2_3.ModelParameterRange(); - range.start = 23; - range.end = 45; - OptionalModelParameterRange optionalRange = new OptionalModelParameterRange(); - optionalRange.range(range); - resultCallback.onValues(0, optionalRange); - return null; - }).when(driver).queryParameter(eq(hwHandle), - eq(android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR), any()); + android.hardware.soundtrigger.V2_3.ModelParameterRange halRange = + new android.hardware.soundtrigger.V2_3.ModelParameterRange(); + halRange.start = 23; + halRange.end = 45; + + when(mHalDriver.queryParameter(eq(hwHandle), + eq(android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR))).thenReturn( + halRange); ModelParameterRange range = module.queryModelParameterSupport(modelHandle, ModelParameter.THRESHOLD_FACTOR); - verify(driver).queryParameter(eq(hwHandle), - eq(android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR), any()); + verify(mHalDriver).queryParameter(eq(hwHandle), + eq(android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR)); assertEquals(23, range.minInclusive); assertEquals(45, range.maxInclusive); } @Test - public void testParameterNotSupportedOld() throws Exception { - if (mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw) { - return; - } - - initService(false); - ISoundTriggerCallback callback = createCallbackMock(); - ISoundTriggerModule module = mService.attach(0, callback); - final int hwHandle = 13; - int modelHandle = loadGenericModel(module, hwHandle).first; - - ModelParameterRange range = module.queryModelParameterSupport(modelHandle, - ModelParameter.THRESHOLD_FACTOR); - - assertNull(range); - } - - @Test public void testParameterNotSupported() throws Exception { - if (!(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw)) { - return; - } - - android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver = - (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; - - initService(false); ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); final int hwHandle = 13; int modelHandle = loadGenericModel(module, hwHandle).first; - doAnswer(invocation -> { - android.hardware.soundtrigger.V2_3.ISoundTriggerHw.queryParameterCallback - resultCallback = invocation.getArgument(2); - // This is the return of this method. - resultCallback.onValues(0, new OptionalModelParameterRange()); - return null; - }).when(driver).queryParameter(eq(hwHandle), - eq(android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR), any()); + when(mHalDriver.queryParameter(eq(hwHandle), + eq(android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR))).thenReturn( + null); ModelParameterRange range = module.queryModelParameterSupport(modelHandle, ModelParameter.THRESHOLD_FACTOR); - verify(driver).queryParameter(eq(hwHandle), - eq(android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR), any()); + verify(mHalDriver).queryParameter(eq(hwHandle), + eq(android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR)); assertNull(range); } @Test public void testGetParameter() throws Exception { - if (!(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw)) { - return; - } - - android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver = - (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; - - initService(false); ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); final int hwHandle = 14; int modelHandle = loadGenericModel(module, hwHandle).first; - doAnswer(invocation -> { - android.hardware.soundtrigger.V2_3.ISoundTriggerHw.getParameterCallback - resultCallback = invocation.getArgument(2); - // This is the return of this method. - resultCallback.onValues(0, 234); - return null; - }).when(driver).getParameter(eq(hwHandle), - eq(android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR), any()); + when(mHalDriver.getModelParameter(hwHandle, + android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR)).thenReturn( + 234); int value = module.getModelParameter(modelHandle, ModelParameter.THRESHOLD_FACTOR); - verify(driver).getParameter(eq(hwHandle), - eq(android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR), any()); + verify(mHalDriver).getModelParameter(hwHandle, + android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR); assertEquals(234, value); } @Test public void testSetParameter() throws Exception { - if (!(mHalDriver instanceof android.hardware.soundtrigger.V2_3.ISoundTriggerHw)) { - return; - } - - android.hardware.soundtrigger.V2_3.ISoundTriggerHw driver = - (android.hardware.soundtrigger.V2_3.ISoundTriggerHw) mHalDriver; - - initService(false); ISoundTriggerCallback callback = createCallbackMock(); ISoundTriggerModule module = mService.attach(0, callback); final int hwHandle = 17; int modelHandle = loadGenericModel(module, hwHandle).first; - when(driver.setParameter(hwHandle, - android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR, - 456)).thenReturn(0); - module.setModelParameter(modelHandle, ModelParameter.THRESHOLD_FACTOR, 456); - verify(driver).setParameter(hwHandle, + verify(mHalDriver).setModelParameter(hwHandle, android.hardware.soundtrigger.V2_3.ModelParameter.THRESHOLD_FACTOR, 456); } private static class SoundTriggerHwCallback { - private final android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback mCallback; - private final int mCookie; + private final ISoundTriggerHw2.ModelCallback mCallback; - SoundTriggerHwCallback(android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback callback, - int cookie) { + SoundTriggerHwCallback(ISoundTriggerHw2.ModelCallback callback) { mCallback = callback; - mCookie = cookie; } - private void sendRecognitionEvent(int hwHandle, int status) throws RemoteException { - if (mCallback instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback) { - ((android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback) mCallback).recognitionCallback_2_1( - createRecognitionEvent_2_1(hwHandle, status), mCookie); - } else { - mCallback.recognitionCallback(createRecognitionEvent_2_0(hwHandle, status), - mCookie); - } + private void sendRecognitionEvent(int hwHandle, int status, int captureSession) { + mCallback.recognitionCallback( + TestUtil.createRecognitionEvent_2_1(hwHandle, status, captureSession)); + } + + private void sendPhraseRecognitionEvent(int hwHandle, int status, int captureSession) { + mCallback.phraseRecognitionCallback( + TestUtil.createPhraseRecognitionEvent_2_1(hwHandle, status, captureSession)); } - private void sendPhraseRecognitionEvent(int hwHandle, int status) throws RemoteException { - if (mCallback instanceof android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback) { - ((android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback) mCallback).phraseRecognitionCallback_2_1( - createPhraseRecognitionEvent_2_1(hwHandle, status), mCookie); - } else { - mCallback.phraseRecognitionCallback( - createPhraseRecognitionEvent_2_0(hwHandle, status), mCookie); - } + private void sendUnloadEvent(int hwHandle) { + mCallback.modelUnloaded(hwHandle); } } } diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java new file mode 100644 index 000000000000..a2b0c45d4a37 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java @@ -0,0 +1,433 @@ +/* + * 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.soundtrigger_middleware; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.hardware.audio.common.V2_0.AudioConfig; +import android.hardware.audio.common.V2_0.Uuid; +import android.hardware.soundtrigger.V2_1.ISoundTriggerHw; +import android.hardware.soundtrigger.V2_4.ISoundTriggerHwCallback; +import android.media.audio.common.AudioChannelMask; +import android.media.audio.common.AudioFormat; +import android.media.soundtrigger_middleware.AudioCapabilities; +import android.media.soundtrigger_middleware.ConfidenceLevel; +import android.media.soundtrigger_middleware.Phrase; +import android.media.soundtrigger_middleware.PhraseRecognitionEvent; +import android.media.soundtrigger_middleware.PhraseRecognitionExtra; +import android.media.soundtrigger_middleware.PhraseSoundModel; +import android.media.soundtrigger_middleware.RecognitionConfig; +import android.media.soundtrigger_middleware.RecognitionEvent; +import android.media.soundtrigger_middleware.RecognitionMode; +import android.media.soundtrigger_middleware.SoundModel; +import android.media.soundtrigger_middleware.SoundModelType; +import android.media.soundtrigger_middleware.SoundTriggerModuleProperties; +import android.os.HidlMemoryUtil; +import android.os.ParcelFileDescriptor; +import android.os.SharedMemory; +import android.system.ErrnoException; + +import java.io.FileDescriptor; +import java.nio.ByteBuffer; +import java.util.List; + +/** + * Test utilities, aimed at generating populated objects of the various types and validating + * corresponding objects generated by the system under test. + */ +public class TestUtil { + public static SoundModel createGenericSoundModel() { + return createSoundModel(SoundModelType.GENERIC); + } + + private static SoundModel createSoundModel(int type) { + SoundModel model = new SoundModel(); + model.type = type; + model.uuid = "12345678-2345-3456-4567-abcdef987654"; + model.vendorUuid = "87654321-5432-6543-7654-456789fedcba"; + byte[] data = new byte[]{91, 92, 93, 94, 95}; + model.data = new ParcelFileDescriptor(byteArrayToFileDescriptor(data)); + model.dataSize = data.length; + return model; + } + + public static ISoundTriggerHw.SoundModel createGenericSoundModel_2_1() { + return ConversionUtil.aidl2hidlSoundModel(createGenericSoundModel()); + } + + private static void validateSoundModel_2_1(ISoundTriggerHw.SoundModel model, int type) { + assertEquals(type, model.header.type); + assertEquals("12345678-2345-3456-4567-abcdef987654", + ConversionUtil.hidl2aidlUuid(model.header.uuid)); + assertEquals("87654321-5432-6543-7654-456789fedcba", + ConversionUtil.hidl2aidlUuid(model.header.vendorUuid)); + assertArrayEquals(new byte[]{91, 92, 93, 94, 95}, + HidlMemoryUtil.hidlMemoryToByteArray(model.data)); + } + + private static void validateSoundModel_2_0( + android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel model, int type) { + assertEquals(type, model.type); + assertEquals("12345678-2345-3456-4567-abcdef987654", + ConversionUtil.hidl2aidlUuid(model.uuid)); + assertEquals("87654321-5432-6543-7654-456789fedcba", + ConversionUtil.hidl2aidlUuid(model.vendorUuid)); + assertArrayEquals(new Byte[]{91, 92, 93, 94, 95}, model.data.toArray()); + } + + public static void validateGenericSoundModel_2_1(ISoundTriggerHw.SoundModel model) { + validateSoundModel_2_1(model, android.hardware.soundtrigger.V2_0.SoundModelType.GENERIC); + } + + public static void validateGenericSoundModel_2_0( + android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel model) { + validateSoundModel_2_0(model, android.hardware.soundtrigger.V2_0.SoundModelType.GENERIC); + } + + public static PhraseSoundModel createPhraseSoundModel() { + PhraseSoundModel model = new PhraseSoundModel(); + model.common = createSoundModel(SoundModelType.KEYPHRASE); + model.phrases = new Phrase[1]; + model.phrases[0] = new Phrase(); + model.phrases[0].id = 123; + model.phrases[0].users = new int[]{5, 6, 7}; + model.phrases[0].locale = "locale"; + model.phrases[0].text = "text"; + model.phrases[0].recognitionModes = + RecognitionMode.USER_AUTHENTICATION | RecognitionMode.USER_IDENTIFICATION; + return model; + } + + public static void validatePhraseSoundModel_2_1(ISoundTriggerHw.PhraseSoundModel model) { + validateSoundModel_2_1(model.common, + android.hardware.soundtrigger.V2_0.SoundModelType.KEYPHRASE); + validatePhrases(model.phrases); + } + + public static void validatePhraseSoundModel_2_0( + android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel model) { + validateSoundModel_2_0(model.common, + android.hardware.soundtrigger.V2_0.SoundModelType.KEYPHRASE); + validatePhrases(model.phrases); + } + + private static void validatePhrases( + List<android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Phrase> phrases) { + assertEquals(1, phrases.size()); + assertEquals(123, phrases.get(0).id); + assertArrayEquals(new Integer[]{5, 6, 7}, phrases.get(0).users.toArray()); + assertEquals("locale", phrases.get(0).locale); + assertEquals("text", phrases.get(0).text); + assertEquals(RecognitionMode.USER_AUTHENTICATION | RecognitionMode.USER_IDENTIFICATION, + phrases.get(0).recognitionModes); + } + + public static ISoundTriggerHw.PhraseSoundModel createPhraseSoundModel_2_1() { + return ConversionUtil.aidl2hidlPhraseSoundModel(createPhraseSoundModel()); + } + + public static android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Properties createDefaultProperties( + boolean supportConcurrentCapture) { + android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Properties properties = + new android.hardware.soundtrigger.V2_0.ISoundTriggerHw.Properties(); + properties.implementor = "implementor"; + properties.description = "description"; + properties.version = 123; + properties.uuid = new Uuid(); + properties.uuid.timeLow = 1; + properties.uuid.timeMid = 2; + properties.uuid.versionAndTimeHigh = 3; + properties.uuid.variantAndClockSeqHigh = 4; + properties.uuid.node = new byte[]{5, 6, 7, 8, 9, 10}; + + properties.maxSoundModels = 456; + properties.maxKeyPhrases = 567; + properties.maxUsers = 678; + properties.recognitionModes = + android.hardware.soundtrigger.V2_0.RecognitionMode.VOICE_TRIGGER + | android.hardware.soundtrigger.V2_0.RecognitionMode.USER_IDENTIFICATION + | android.hardware.soundtrigger.V2_0.RecognitionMode.USER_AUTHENTICATION + | android.hardware.soundtrigger.V2_0.RecognitionMode.GENERIC_TRIGGER; + properties.captureTransition = true; + properties.maxBufferMs = 321; + properties.concurrentCapture = supportConcurrentCapture; + properties.triggerInEvent = true; + properties.powerConsumptionMw = 432; + return properties; + } + + public static android.hardware.soundtrigger.V2_3.Properties createDefaultProperties_2_3( + boolean supportConcurrentCapture) { + android.hardware.soundtrigger.V2_3.Properties properties = + new android.hardware.soundtrigger.V2_3.Properties(); + properties.base = createDefaultProperties(supportConcurrentCapture); + properties.supportedModelArch = "supportedModelArch"; + properties.audioCapabilities = + android.hardware.soundtrigger.V2_3.AudioCapabilities.ECHO_CANCELLATION + | android.hardware.soundtrigger.V2_3.AudioCapabilities.NOISE_SUPPRESSION; + return properties; + } + + public static void validateDefaultProperties(SoundTriggerModuleProperties properties, + boolean supportConcurrentCapture) { + assertEquals("implementor", properties.implementor); + assertEquals("description", properties.description); + assertEquals(123, properties.version); + assertEquals("00000001-0002-0003-0004-05060708090a", properties.uuid); + assertEquals(456, properties.maxSoundModels); + assertEquals(567, properties.maxKeyPhrases); + assertEquals(678, properties.maxUsers); + assertEquals(RecognitionMode.GENERIC_TRIGGER + | RecognitionMode.USER_AUTHENTICATION + | RecognitionMode.USER_IDENTIFICATION + | RecognitionMode.VOICE_TRIGGER, properties.recognitionModes); + assertTrue(properties.captureTransition); + assertEquals(321, properties.maxBufferMs); + assertEquals(supportConcurrentCapture, properties.concurrentCapture); + assertTrue(properties.triggerInEvent); + assertEquals(432, properties.powerConsumptionMw); + assertEquals("supportedModelArch", properties.supportedModelArch); + assertEquals(AudioCapabilities.ECHO_CANCELLATION | AudioCapabilities.NOISE_SUPPRESSION, + properties.audioCapabilities); + } + + public static RecognitionConfig createRecognitionConfig() { + RecognitionConfig config = new RecognitionConfig(); + config.captureRequested = true; + config.phraseRecognitionExtras = new PhraseRecognitionExtra[]{new PhraseRecognitionExtra()}; + config.phraseRecognitionExtras[0].id = 123; + config.phraseRecognitionExtras[0].confidenceLevel = 4; + config.phraseRecognitionExtras[0].recognitionModes = 5; + config.phraseRecognitionExtras[0].levels = new ConfidenceLevel[]{new ConfidenceLevel()}; + config.phraseRecognitionExtras[0].levels[0].userId = 234; + config.phraseRecognitionExtras[0].levels[0].levelPercent = 34; + config.data = new byte[]{5, 4, 3, 2, 1}; + config.audioCapabilities = AudioCapabilities.ECHO_CANCELLATION + | AudioCapabilities.NOISE_SUPPRESSION; + return config; + } + + public static android.hardware.soundtrigger.V2_3.RecognitionConfig createRecognitionConfig_2_3( + int captureHandle, int captureDevice) { + android.hardware.soundtrigger.V2_3.RecognitionConfig config = + ConversionUtil.aidl2hidlRecognitionConfig(createRecognitionConfig()); + config.base.header.captureDevice = captureDevice; + config.base.header.captureHandle = captureHandle; + return config; + } + + public static void validateRecognitionConfig_2_0( + android.hardware.soundtrigger.V2_0.ISoundTriggerHw.RecognitionConfig config, + int captureHandle, int captureDevice) { + assertTrue(config.captureRequested); + assertEquals(captureDevice, config.captureDevice); + assertEquals(captureHandle, config.captureHandle); + assertEquals(1, config.phrases.size()); + android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halPhraseExtra = + config.phrases.get(0); + assertEquals(123, halPhraseExtra.id); + assertEquals(4, halPhraseExtra.confidenceLevel); + assertEquals(5, halPhraseExtra.recognitionModes); + assertEquals(1, halPhraseExtra.levels.size()); + android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel = halPhraseExtra.levels.get(0); + assertEquals(234, halLevel.userId); + assertEquals(34, halLevel.levelPercent); + assertArrayEquals(new Byte[]{5, 4, 3, 2, 1}, config.data.toArray()); + } + + public static void validateRecognitionConfig_2_1( + android.hardware.soundtrigger.V2_1.ISoundTriggerHw.RecognitionConfig config, + int captureHandle, int captureDevice) { + assertTrue(config.header.captureRequested); + assertEquals(captureDevice, config.header.captureDevice); + assertEquals(captureHandle, config.header.captureHandle); + assertEquals(1, config.header.phrases.size()); + android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halPhraseExtra = + config.header.phrases.get(0); + assertEquals(123, halPhraseExtra.id); + assertEquals(4, halPhraseExtra.confidenceLevel); + assertEquals(5, halPhraseExtra.recognitionModes); + assertEquals(1, halPhraseExtra.levels.size()); + android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel = halPhraseExtra.levels.get(0); + assertEquals(234, halLevel.userId); + assertEquals(34, halLevel.levelPercent); + assertArrayEquals(new byte[]{5, 4, 3, 2, 1}, + HidlMemoryUtil.hidlMemoryToByteArray(config.data)); + } + + public static void validateRecognitionConfig_2_3( + android.hardware.soundtrigger.V2_3.RecognitionConfig config, int captureHandle, + int captureDevice) { + validateRecognitionConfig_2_1(config.base, captureHandle, captureDevice); + + assertEquals(AudioCapabilities.ECHO_CANCELLATION + | AudioCapabilities.NOISE_SUPPRESSION, config.audioCapabilities); + } + + public static android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent createRecognitionEvent_2_0( + int hwHandle, + int status, int captureSession) { + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent halEvent = + new android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent(); + halEvent.status = status; + halEvent.type = SoundModelType.GENERIC; + halEvent.model = hwHandle; + halEvent.captureAvailable = true; + // This field is ignored. + halEvent.captureSession = captureSession; + halEvent.captureDelayMs = 234; + halEvent.capturePreambleMs = 345; + halEvent.triggerInData = true; + halEvent.audioConfig = new AudioConfig(); + halEvent.audioConfig.sampleRateHz = 456; + halEvent.audioConfig.channelMask = AudioChannelMask.IN_LEFT; + halEvent.audioConfig.format = AudioFormat.MP3; + // hwEvent.audioConfig.offloadInfo is irrelevant. + halEvent.data.add((byte) 31); + halEvent.data.add((byte) 32); + halEvent.data.add((byte) 33); + return halEvent; + } + + public static ISoundTriggerHwCallback.RecognitionEvent createRecognitionEvent_2_1( + int hwHandle, + int status, int captureSession) { + ISoundTriggerHwCallback.RecognitionEvent halEvent = + new ISoundTriggerHwCallback.RecognitionEvent(); + halEvent.header = createRecognitionEvent_2_0(hwHandle, status, captureSession); + halEvent.header.data.clear(); + halEvent.data = HidlMemoryUtil.byteArrayToHidlMemory(new byte[]{31, 32, 33}); + return halEvent; + } + + public static void validateRecognitionEvent(RecognitionEvent event, int status, + int captureSession) { + assertEquals(status, event.status); + assertEquals(SoundModelType.GENERIC, event.type); + assertTrue(event.captureAvailable); + assertEquals(captureSession, event.captureSession); + assertEquals(234, event.captureDelayMs); + assertEquals(345, event.capturePreambleMs); + assertTrue(event.triggerInData); + assertEquals(456, event.audioConfig.sampleRateHz); + assertEquals(AudioChannelMask.IN_LEFT, event.audioConfig.channelMask); + assertEquals(AudioFormat.MP3, event.audioConfig.format); + assertArrayEquals(new byte[]{31, 32, 33}, event.data); + } + + public static void validateRecognitionEvent_2_1( + android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent event, + int hwHandle, + int status, int captureSession) { + assertEquals(status, event.header.status); + assertEquals(hwHandle, event.header.model); + assertEquals(SoundModelType.GENERIC, event.header.type); + assertTrue(event.header.captureAvailable); + assertEquals(captureSession, event.header.captureSession); + assertEquals(234, event.header.captureDelayMs); + assertEquals(345, event.header.capturePreambleMs); + assertTrue(event.header.triggerInData); + assertEquals(456, event.header.audioConfig.sampleRateHz); + assertEquals(AudioChannelMask.IN_LEFT, event.header.audioConfig.channelMask); + assertEquals(AudioFormat.MP3, event.header.audioConfig.format); + assertArrayEquals(new byte[]{31, 32, 33}, HidlMemoryUtil.hidlMemoryToByteArray(event.data)); + } + + public static android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent + createPhraseRecognitionEvent_2_0(int hwHandle, int status, int captureSession) { + android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent halEvent = + new android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent(); + halEvent.common = createRecognitionEvent_2_0(hwHandle, status, captureSession); + + android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halExtra = + new android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra(); + halExtra.id = 123; + halExtra.confidenceLevel = 52; + halExtra.recognitionModes = android.hardware.soundtrigger.V2_0.RecognitionMode.VOICE_TRIGGER + | android.hardware.soundtrigger.V2_0.RecognitionMode.GENERIC_TRIGGER; + android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel = + new android.hardware.soundtrigger.V2_0.ConfidenceLevel(); + halLevel.userId = 31; + halLevel.levelPercent = 43; + halExtra.levels.add(halLevel); + halEvent.phraseExtras.add(halExtra); + return halEvent; + } + + public static ISoundTriggerHwCallback.PhraseRecognitionEvent createPhraseRecognitionEvent_2_1( + int hwHandle, int status, int captureSession) { + ISoundTriggerHwCallback.PhraseRecognitionEvent halEvent = + new ISoundTriggerHwCallback.PhraseRecognitionEvent(); + halEvent.common = createRecognitionEvent_2_1(hwHandle, status, captureSession); + + android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra halExtra = + new android.hardware.soundtrigger.V2_0.PhraseRecognitionExtra(); + halExtra.id = 123; + halExtra.confidenceLevel = 52; + halExtra.recognitionModes = android.hardware.soundtrigger.V2_0.RecognitionMode.VOICE_TRIGGER + | android.hardware.soundtrigger.V2_0.RecognitionMode.GENERIC_TRIGGER; + android.hardware.soundtrigger.V2_0.ConfidenceLevel halLevel = + new android.hardware.soundtrigger.V2_0.ConfidenceLevel(); + halLevel.userId = 31; + halLevel.levelPercent = 43; + halExtra.levels.add(halLevel); + halEvent.phraseExtras.add(halExtra); + return halEvent; + } + + public static void validatePhraseRecognitionEvent(PhraseRecognitionEvent event, int status, + int captureSession) { + validateRecognitionEvent(event.common, status, captureSession); + + assertEquals(1, event.phraseExtras.length); + assertEquals(123, event.phraseExtras[0].id); + assertEquals(52, event.phraseExtras[0].confidenceLevel); + assertEquals(RecognitionMode.VOICE_TRIGGER | RecognitionMode.GENERIC_TRIGGER, + event.phraseExtras[0].recognitionModes); + assertEquals(1, event.phraseExtras[0].levels.length); + assertEquals(31, event.phraseExtras[0].levels[0].userId); + assertEquals(43, event.phraseExtras[0].levels[0].levelPercent); + } + + public static void validatePhraseRecognitionEvent_2_1( + android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent event, + int handle, int status, int captureSession) { + validateRecognitionEvent_2_1(event.common, handle, status, captureSession); + + assertEquals(1, event.phraseExtras.size()); + assertEquals(123, event.phraseExtras.get(0).id); + assertEquals(52, event.phraseExtras.get(0).confidenceLevel); + assertEquals(RecognitionMode.VOICE_TRIGGER | RecognitionMode.GENERIC_TRIGGER, + event.phraseExtras.get(0).recognitionModes); + assertEquals(1, event.phraseExtras.get(0).levels.size()); + assertEquals(31, event.phraseExtras.get(0).levels.get(0).userId); + assertEquals(43, event.phraseExtras.get(0).levels.get(0).levelPercent); + } + + private static FileDescriptor byteArrayToFileDescriptor(byte[] data) { + try { + SharedMemory shmem = SharedMemory.create("", data.length); + ByteBuffer buffer = shmem.mapReadWrite(); + buffer.put(data); + return shmem.getFileDescriptor(); + } catch (ErrnoException e) { + throw new RuntimeException(e); + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java index 4284240c72b4..3daa7f0483c6 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ControllerImplTest.java @@ -72,6 +72,7 @@ public class ControllerImplTest { private TestCallback mTestCallback; private TestLocationTimeZoneProvider mTestPrimaryLocationTimeZoneProvider; private TestLocationTimeZoneProvider mTestSecondaryLocationTimeZoneProvider; + private FakeTimeZoneIdValidator mTimeZoneAvailabilityChecker; @Before public void setUp() { @@ -80,10 +81,13 @@ public class ControllerImplTest { // will never get a chance to execute. mTestThreadingDomain = new TestThreadingDomain(); mTestCallback = new TestCallback(mTestThreadingDomain); + mTimeZoneAvailabilityChecker = new FakeTimeZoneIdValidator(); mTestPrimaryLocationTimeZoneProvider = - new TestLocationTimeZoneProvider(mTestThreadingDomain, "primary"); + new TestLocationTimeZoneProvider( + mTestThreadingDomain, "primary", mTimeZoneAvailabilityChecker); mTestSecondaryLocationTimeZoneProvider = - new TestLocationTimeZoneProvider(mTestThreadingDomain, "secondary"); + new TestLocationTimeZoneProvider( + mTestThreadingDomain, "secondary", mTimeZoneAvailabilityChecker); } @Test @@ -1177,8 +1181,10 @@ public class ControllerImplTest { /** * Creates the instance. */ - TestLocationTimeZoneProvider(ThreadingDomain threadingDomain, String providerName) { - super(threadingDomain, providerName); + TestLocationTimeZoneProvider(ThreadingDomain threadingDomain, + String providerName, + TimeZoneIdValidator timeZoneIdValidator) { + super(threadingDomain, providerName, timeZoneIdValidator); } public void setFailDuringInitialization(boolean failInitialization) { @@ -1311,4 +1317,14 @@ public class ControllerImplTest { mTestProviderState.commitLatest(); } } + + private static final class FakeTimeZoneIdValidator + implements LocationTimeZoneProvider.TimeZoneIdValidator { + + @Override + public boolean isValid(@NonNull String timeZoneId) { + return true; + } + + } } diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java index 095c868fc74c..278fdaff260f 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/LocationTimeZoneProviderTest.java @@ -32,6 +32,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static java.util.Arrays.asList; + import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Bundle; @@ -50,7 +52,9 @@ import org.junit.Test; import java.time.Duration; import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicReference; /** @@ -62,20 +66,25 @@ public class LocationTimeZoneProviderTest { private static final long ARBITRARY_ELAPSED_REALTIME_MILLIS = 123456789L; private TestThreadingDomain mTestThreadingDomain; - private TestProviderListener mProviderListener; + private FakeTimeZoneIdValidator mTimeZoneAvailabilityChecker; @Before public void setUp() { mTestThreadingDomain = new TestThreadingDomain(); mProviderListener = new TestProviderListener(); + mTimeZoneAvailabilityChecker = new FakeTimeZoneIdValidator(); } @Test public void lifecycle() { String providerName = "arbitrary"; TestLocationTimeZoneProvider provider = - new TestLocationTimeZoneProvider(mTestThreadingDomain, providerName); + new TestLocationTimeZoneProvider( + mTestThreadingDomain, + providerName, + mTimeZoneAvailabilityChecker); + mTimeZoneAvailabilityChecker.validIds("Europe/London"); // initialize() provider.initialize(mProviderListener); @@ -163,7 +172,10 @@ public class LocationTimeZoneProviderTest { public void defaultHandleTestCommandImpl() { String providerName = "primary"; TestLocationTimeZoneProvider provider = - new TestLocationTimeZoneProvider(mTestThreadingDomain, providerName); + new TestLocationTimeZoneProvider( + mTestThreadingDomain, + providerName, + mTimeZoneAvailabilityChecker); TestCommand testCommand = TestCommand.createForTests("test", new Bundle()); AtomicReference<Bundle> resultReference = new AtomicReference<>(); @@ -180,8 +192,12 @@ public class LocationTimeZoneProviderTest { public void stateRecording() { String providerName = "primary"; TestLocationTimeZoneProvider provider = - new TestLocationTimeZoneProvider(mTestThreadingDomain, providerName); + new TestLocationTimeZoneProvider( + mTestThreadingDomain, + providerName, + mTimeZoneAvailabilityChecker); provider.setStateChangeRecordingEnabled(true); + mTimeZoneAvailabilityChecker.validIds("Europe/London"); // initialize() provider.initialize(mProviderListener); @@ -218,6 +234,34 @@ public class LocationTimeZoneProviderTest { provider.assertLatestRecordedState(PROVIDER_STATE_DESTROYED); } + @Test + public void considerSuggestionWithInvalidTimeZoneIdsAsUncertain() { + String providerName = "primary"; + TestLocationTimeZoneProvider provider = + new TestLocationTimeZoneProvider( + mTestThreadingDomain, + providerName, + mTimeZoneAvailabilityChecker); + provider.setStateChangeRecordingEnabled(true); + provider.initialize(mProviderListener); + + ConfigurationInternal config = USER1_CONFIG_GEO_DETECTION_ENABLED; + Duration arbitraryInitializationTimeout = Duration.ofMinutes(5); + Duration arbitraryInitializationTimeoutFuzz = Duration.ofMinutes(2); + provider.startUpdates(config, arbitraryInitializationTimeout, + arbitraryInitializationTimeoutFuzz); + + List<String> invalidTimeZoneIds = asList("Atlantic/Atlantis"); + TimeZoneProviderSuggestion invalidIdSuggestion = new TimeZoneProviderSuggestion.Builder() + .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS) + .setTimeZoneIds(invalidTimeZoneIds) + .build(); + TimeZoneProviderEvent event = + TimeZoneProviderEvent.createSuggestionEvent(invalidIdSuggestion); + provider.simulateProviderEventReceived(event); + provider.assertLatestRecordedState(PROVIDER_STATE_STARTED_UNCERTAIN); + } + /** A test stand-in for the real {@link LocationTimeZoneProviderController}'s listener. */ private static class TestProviderListener implements ProviderListener { @@ -251,8 +295,9 @@ public class LocationTimeZoneProviderTest { /** Creates the instance. */ TestLocationTimeZoneProvider(@NonNull ThreadingDomain threadingDomain, - @NonNull String providerName) { - super(threadingDomain, providerName); + @NonNull String providerName, + @NonNull TimeZoneIdValidator timeZoneIdValidator) { + super(threadingDomain, providerName, timeZoneIdValidator); } @Override @@ -308,4 +353,19 @@ public class LocationTimeZoneProviderTest { recordedStates.get(recordedStates.size() - 1).stateEnum); } } + + private static final class FakeTimeZoneIdValidator + implements LocationTimeZoneProvider.TimeZoneIdValidator { + private final Set<String> mValidTimeZoneIds = new HashSet<>(); + + @Override + public boolean isValid(@NonNull String timeZoneId) { + return mValidTimeZoneIds.contains(timeZoneId); + } + + public void validIds(String... timeZoneIdss) { + mValidTimeZoneIds.addAll(asList(timeZoneIdss)); + } + + } } diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidatorTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidatorTest.java new file mode 100644 index 000000000000..5561b2c6a7aa --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/location/ZoneInfoDbTimeZoneIdValidatorTest.java @@ -0,0 +1,54 @@ +/* + * 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.timezonedetector.location; + +import static com.google.common.truth.Truth.assertWithMessage; + +import android.platform.test.annotations.Presubmit; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.TimeZone; + +@Presubmit +public class ZoneInfoDbTimeZoneIdValidatorTest { + private final LocationTimeZoneProvider.TimeZoneIdValidator mTzChecker = + new ZoneInfoDbTimeZoneIdValidator(); + + @Test + public void timeZoneIdsFromZoneInfoDbAreValid() { + for (String timeZone : TimeZone.getAvailableIDs()) { + assertWithMessage("Time zone %s should be supported", timeZone) + .that(mTzChecker.isValid(timeZone)).isTrue(); + } + } + + @Test + public void nonExistingZones_areNotSupported() { + List<String> nonExistingTimeZones = Arrays.asList( + "SystemV/HST10", "Atlantic/Atlantis", "EUROPE/LONDON", "Etc/GMT-5:30" + ); + + for (String timeZone : nonExistingTimeZones) { + assertWithMessage(timeZone + " is not a valid time zone") + .that(mTzChecker.isValid(timeZone)) + .isFalse(); + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java index aadab6ea4fd9..2f36c7fb9044 100644 --- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java @@ -365,13 +365,13 @@ public class TunerResourceManagerServiceTest { mTunerResourceManagerService.registerClientProfileInternal( profiles[0], listener, clientId0); assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId0[0]) - .setPriority(clientPriorities[0]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId0[0], clientPriorities[0], 0/*niceValue*/); mTunerResourceManagerService.registerClientProfileInternal( profiles[1], new TestResourcesReclaimListener(), clientId1); assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId1[0]) - .setPriority(clientPriorities[1]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId1[0], clientPriorities[1], 0/*niceValue*/); // Init frontend resources. TunerFrontendInfo[] infos = new TunerFrontendInfo[2]; @@ -415,13 +415,13 @@ public class TunerResourceManagerServiceTest { mTunerResourceManagerService.registerClientProfileInternal( profiles[0], listener, clientId0); assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId0[0]) - .setPriority(clientPriorities[0]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId0[0], clientPriorities[0], 0/*niceValue*/); mTunerResourceManagerService.registerClientProfileInternal( profiles[1], new TestResourcesReclaimListener(), clientId1); assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId1[0]) - .setPriority(clientPriorities[1]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId1[0], clientPriorities[1], 0/*niceValue*/); // Init frontend resources. TunerFrontendInfo[] infos = new TunerFrontendInfo[2]; @@ -511,13 +511,13 @@ public class TunerResourceManagerServiceTest { mTunerResourceManagerService.registerClientProfileInternal( profiles[0], listener, clientId0); assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId0[0]) - .setPriority(clientPriorities[0]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId0[0], clientPriorities[0], 0/*niceValue*/); mTunerResourceManagerService.registerClientProfileInternal( profiles[1], new TestResourcesReclaimListener(), clientId1); assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId1[0]) - .setPriority(clientPriorities[1]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId1[0], clientPriorities[1], 0/*niceValue*/); // Init cas resources. mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/); @@ -567,13 +567,13 @@ public class TunerResourceManagerServiceTest { mTunerResourceManagerService.registerClientProfileInternal( profiles[0], listener, clientId0); assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId0[0]) - .setPriority(clientPriorities[0]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId0[0], clientPriorities[0], 0/*niceValue*/); mTunerResourceManagerService.registerClientProfileInternal( profiles[1], new TestResourcesReclaimListener(), clientId1); assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId1[0]) - .setPriority(clientPriorities[1]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId1[0], clientPriorities[1], 0/*niceValue*/); // Init cicam/cas resources. mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/); @@ -697,13 +697,13 @@ public class TunerResourceManagerServiceTest { mTunerResourceManagerService.registerClientProfileInternal( profiles[0], listener, clientId0); assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId0[0]) - .setPriority(clientPriorities[0]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId0[0], clientPriorities[0], 0/*niceValue*/); mTunerResourceManagerService.registerClientProfileInternal( profiles[1], new TestResourcesReclaimListener(), clientId1); assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); - mTunerResourceManagerService.getClientProfile(clientId1[0]) - .setPriority(clientPriorities[1]); + mTunerResourceManagerService.updateClientPriorityInternal( + clientId1[0], clientPriorities[1], 0/*niceValue*/); // Init lnb resources. int[] lnbHandles = {1}; diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java index a0a390947822..61074baf7d9e 100644 --- a/services/usage/java/com/android/server/usage/StorageStatsService.java +++ b/services/usage/java/com/android/server/usage/StorageStatsService.java @@ -207,7 +207,7 @@ public class StorageStatsService extends IStorageStatsManager.Stub { public boolean isReservedSupported(String volumeUuid, String callingPackage) { if (volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL) { return SystemProperties.getBoolean(StorageManager.PROP_HAS_RESERVED, false) - || Build.IS_CONTAINER; + || Build.IS_ARC; } else { return false; } diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java index 16d83d133fbe..7e543460051e 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java @@ -36,7 +36,6 @@ import android.hardware.soundtrigger.SoundTrigger.ModuleProperties; import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent; import android.hardware.soundtrigger.SoundTrigger.SoundModel; -import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent; import android.hardware.soundtrigger.SoundTriggerModule; import android.os.Binder; import android.os.DeadObjectException; @@ -109,9 +108,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { private boolean mCallActive = false; private @SoundTriggerPowerSaveMode int mSoundTriggerPowerSaveMode = PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED; - // Indicates if the native sound trigger service is disabled or not. - // This is an indirect indication of the microphone being open in some other application. - private boolean mServiceDisabled = false; // Whether ANY recognition (keyphrase or generic) has been requested. private boolean mRecognitionRequested = false; @@ -862,23 +858,19 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } @Override - public void onSoundModelUpdate(SoundModelEvent event) { - if (event == null) { - Slog.w(TAG, "Invalid sound model event!"); - return; - } - if (DBG) Slog.d(TAG, "onSoundModelUpdate: " + event); + public void onModelUnloaded(int modelHandle) { + if (DBG) Slog.d(TAG, "onModelUnloaded: " + modelHandle); synchronized (mLock) { MetricsLogger.count(mContext, "sth_sound_model_updated", 1); - onSoundModelUpdatedLocked(event); + onModelUnloadedLocked(modelHandle); } } @Override - public void onServiceStateChange(int state) { - if (DBG) Slog.d(TAG, "onServiceStateChange, state: " + state); + public void onResourcesAvailable() { + if (DBG) Slog.d(TAG, "onResourcesAvailable"); synchronized (mLock) { - onServiceStateChangedLocked(SoundTrigger.SERVICE_STATE_DISABLED == state); + onResourcesAvailableLocked(); } } @@ -910,15 +902,14 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { updateAllRecognitionsLocked(); } - private void onSoundModelUpdatedLocked(SoundModelEvent event) { - // TODO: Handle sound model update here. + private void onModelUnloadedLocked(int modelHandle) { + ModelData modelData = getModelDataForLocked(modelHandle); + if (modelData != null) { + modelData.setNotLoaded(); + } } - private void onServiceStateChangedLocked(boolean disabled) { - if (disabled == mServiceDisabled) { - return; - } - mServiceDisabled = disabled; + private void onResourcesAvailableLocked() { updateAllRecognitionsLocked(); } @@ -1039,7 +1030,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { if (mModule != null) { mModule.detach(); mModule = null; - mServiceDisabled = false; } } } @@ -1114,8 +1104,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { pw.print(" call active="); pw.println(mCallActive); pw.println(" SoundTrigger Power State=" + mSoundTriggerPowerSaveMode); - pw.print(" service disabled="); - pw.println(mServiceDisabled); } } @@ -1329,8 +1317,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { mSoundTriggerPowerSaveMode = mPowerManager.getSoundTriggerPowerSaveMode(); } - return !mCallActive && !mServiceDisabled - && isRecognitionAllowedByPowerState( + return !mCallActive && isRecognitionAllowedByPowerState( modelData); } @@ -1571,6 +1558,10 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { mModelState = MODEL_LOADED; } + synchronized void setNotLoaded() { + mModelState = MODEL_NOTLOADED; + } + synchronized boolean isModelStarted() { return mModelState == MODEL_STARTED; } diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 4926687f6724..0070f62d3ea9 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -2678,7 +2678,8 @@ public final class SmsManager { * @throws IllegalArgumentException if contentUri is empty */ public void sendMultimediaMessage(@NonNull Context context, @NonNull Uri contentUri, - @Nullable String locationUrl, @Nullable Bundle configOverrides, + @Nullable String locationUrl, + @SuppressWarnings("NullableCollection") @Nullable Bundle configOverrides, @Nullable PendingIntent sentIntent, long messageId) { if (contentUri == null) { throw new IllegalArgumentException("Uri contentUri null"); @@ -2754,7 +2755,8 @@ public final class SmsManager { * @throws IllegalArgumentException if locationUrl or contentUri is empty */ public void downloadMultimediaMessage(@NonNull Context context, @NonNull String locationUrl, - @NonNull Uri contentUri, @Nullable Bundle configOverrides, + @NonNull Uri contentUri, + @SuppressWarnings("NullableCollection") @Nullable Bundle configOverrides, @Nullable PendingIntent downloadedIntent, long messageId) { if (TextUtils.isEmpty(locationUrl)) { throw new IllegalArgumentException("Empty MMS location URL"); diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index cf4e6779b363..5bbd061b471a 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -602,6 +602,43 @@ public class SubscriptionManager { public @interface SimDisplayNameSource {} /** + * Device status is not shared to a remote party. + */ + public static final int D2D_SHARING_DISABLED = 0; + + /** + * Device status is shared with all numbers in the user's contacts. + */ + public static final int D2D_SHARING_ALL_CONTACTS = 1; + + /** + * Device status is shared with all starred contacts. + */ + public static final int D2D_SHARING_STARRED_CONTACTS = 2; + + /** + * Device status is shared whenever possible. + */ + public static final int D2D_SHARING_ALL = 3; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"D2D_SHARING_"}, + value = { + D2D_SHARING_DISABLED, + D2D_SHARING_ALL_CONTACTS, + D2D_SHARING_STARRED_CONTACTS, + D2D_SHARING_ALL + }) + public @interface DeviceToDeviceStatusSharing {} + + /** + * TelephonyProvider column name for device to device sharing status. + * <P>Type: INTEGER (int)</P> + */ + public static final String D2D_STATUS_SHARING = SimInfo.COLUMN_D2D_STATUS_SHARING; + + /** * TelephonyProvider column name for the color of a SIM. * <P>Type: INTEGER (int)</P> */ @@ -3374,6 +3411,36 @@ public class SubscriptionManager { } /** + * Set the device to device status sharing user preference for a subscription ID. The setting + * app uses this method to indicate with whom they wish to share device to device status + * information. + * @param sharing the status sharing preference + * @param subId the unique Subscription ID in database + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public void setDeviceToDeviceStatusSharing(@DeviceToDeviceStatusSharing int sharing, + int subId) { + if (VDBG) { + logd("[setDeviceToDeviceStatusSharing] + sharing: " + sharing + " subId: " + subId); + } + setSubscriptionPropertyHelper(subId, "setDeviceToDeviceSharingStatus", + (iSub)->iSub.setDeviceToDeviceStatusSharing(sharing, subId)); + } + + /** + * Returns the user-chosen device to device status sharing preference + * @param subId Subscription id of subscription + * @return The device to device status sharing preference + */ + public @DeviceToDeviceStatusSharing int getDeviceToDeviceStatusSharing(int subId) { + if (VDBG) { + logd("[getDeviceToDeviceStatusSharing] + subId: " + subId); + } + return getIntegerSubscriptionProperty(subId, D2D_STATUS_SHARING, D2D_SHARING_DISABLED, + mContext); + } + + /** * DO NOT USE. * This API is designed for features that are not finished at this point. Do not call this API. * @hide diff --git a/telephony/java/android/telephony/TelephonyDisplayInfo.java b/telephony/java/android/telephony/TelephonyDisplayInfo.java index 2f89bfb60d3d..448928d3ff0b 100644 --- a/telephony/java/android/telephony/TelephonyDisplayInfo.java +++ b/telephony/java/android/telephony/TelephonyDisplayInfo.java @@ -79,7 +79,7 @@ public final class TelephonyDisplayInfo implements Parcelable { * <li>The device is connected to the NR cellular network on millimeter wave bands. </li> * <li>The device is connected to the specific network which the carrier is using * proprietary means to provide a faster overall data connection than would be otherwise - * possible. This may include using other bands unique to the carrier, or carrier + * possible. This may include using other bands unique to the carrier, or carrier * aggregation, for example.</li> * </ul> * One of the use case is that UX can show a different icon, for example, "5G+" diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index 571efcee0e15..9493c76d9a57 100755 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -300,4 +300,6 @@ interface ISub { boolean canDisablePhysicalSubscription(); int setUiccApplicationsEnabled(boolean enabled, int subscriptionId); + + int setDeviceToDeviceStatusSharing(int sharing, int subId); } diff --git a/tests/SoundTriggerTestApp/res/layout/main.xml b/tests/SoundTriggerTestApp/res/layout/main.xml index 2c6c8d7cae20..1381c0a43c30 100644 --- a/tests/SoundTriggerTestApp/res/layout/main.xml +++ b/tests/SoundTriggerTestApp/res/layout/main.xml @@ -73,6 +73,14 @@ android:text="@string/play_trigger" android:onClick="onPlayTriggerButtonClicked" android:padding="20dp" /> + + <Button + android:id="@+id/get_state_id" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/get_model_state" + android:onClick="onGetModelStateButtonClicked" + android:padding="20dp" /> </LinearLayout> <LinearLayout diff --git a/tests/SoundTriggerTestApp/res/values/strings.xml b/tests/SoundTriggerTestApp/res/values/strings.xml index c48b64884c5e..adb0fcf8e185 100644 --- a/tests/SoundTriggerTestApp/res/values/strings.xml +++ b/tests/SoundTriggerTestApp/res/values/strings.xml @@ -22,6 +22,7 @@ <string name="start_recog">Start</string> <string name="stop_recog">Stop</string> <string name="play_trigger">Play Trigger Audio</string> + <string name="get_model_state">Get State</string> <string name="capture">Capture Audio</string> <string name="stop_capture">Stop Capturing Audio</string> <string name="play_capture">Play Captured Audio</string> diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java index c3c4cf556986..72aa38dc7e4b 100644 --- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java +++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestActivity.java @@ -257,6 +257,14 @@ public class SoundTriggerTestActivity extends Activity implements SoundTriggerTe } } + public synchronized void onGetModelStateButtonClicked(View v) { + if (mService == null) { + Log.e(TAG, "Can't get model state: not bound to SoundTriggerTestService"); + } else { + mService.getModelState(mSelectedModelUuid); + } + } + public synchronized void onCaptureAudioCheckboxClicked(View v) { // See if we have the right permissions if (!mService.hasMicrophonePermission()) { diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java index 380e29984c63..6d4ffcff7d45 100644 --- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java +++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java @@ -23,6 +23,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent; +import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel; import android.media.AudioAttributes; import android.media.AudioFormat; import android.media.AudioManager; @@ -46,6 +48,7 @@ import java.util.Properties; import java.util.Random; import java.util.UUID; + public class SoundTriggerTestService extends Service { private static final String TAG = "SoundTriggerTestSrv"; private static final String INTENT_ACTION = "com.android.intent.action.MANAGE_SOUND_TRIGGER"; @@ -57,6 +60,8 @@ public class SoundTriggerTestService extends Service { private Random mRandom; private UserActivity mUserActivity; + private static int captureCount; + public interface UserActivity { void addModel(UUID modelUuid, String state); void setModelState(UUID modelUuid, String state); @@ -131,6 +136,8 @@ public class SoundTriggerTestService extends Service { } else if (command.equals("set_capture_timeout")) { setCaptureAudioTimeout(getModelUuidFromIntent(intent), intent.getIntExtra("timeout", 5000)); + } else if (command.equals("get_model_state")) { + getModelState(getModelUuidFromIntent(intent)); } else { Log.e(TAG, "Unknown command '" + command + "'"); } @@ -432,6 +439,17 @@ public class SoundTriggerTestService extends Service { return modelInfo != null && modelInfo.captureAudioTrack != null; } + public synchronized void getModelState(UUID modelUuid) { + ModelInfo modelInfo = mModelInfoMap.get(modelUuid); + if (modelInfo == null) { + postError("Could not find model for: " + modelUuid.toString()); + return; + } + int status = mSoundTriggerUtil.getModelState(modelUuid); + postMessage("GetModelState for: " + modelInfo.name + " returns: " + + status); + } + private void loadModelsInDataDir() { // Load all the models in the data dir. boolean loadedModel = false; @@ -527,18 +545,29 @@ public class SoundTriggerTestService extends Service { } } + private class CaptureAudioRecorder implements Runnable { private final ModelInfo mModelInfo; + + // EventPayload and RecognitionEvent are equivalant. Only one will be non-null. private final SoundTriggerDetector.EventPayload mEvent; + private final RecognitionEvent mRecognitionEvent; public CaptureAudioRecorder(ModelInfo modelInfo, SoundTriggerDetector.EventPayload event) { mModelInfo = modelInfo; mEvent = event; + mRecognitionEvent = null; + } + + public CaptureAudioRecorder(ModelInfo modelInfo, RecognitionEvent event) { + mModelInfo = modelInfo; + mEvent = null; + mRecognitionEvent = event; } @Override public void run() { - AudioFormat format = mEvent.getCaptureAudioFormat(); + AudioFormat format = getAudioFormat(); if (format == null) { postErrorToast("No audio format in recognition event."); return; @@ -600,18 +629,21 @@ public class SoundTriggerTestService extends Service { } audioRecord = new AudioRecord(attributes, format, bytesRequired, - mEvent.getCaptureSession()); + getCaptureSession()); byte[] buffer = new byte[bytesRequired]; // Create a file so we can save the output data there for analysis later. FileOutputStream fos = null; try { - fos = new FileOutputStream( new File( - getFilesDir() + File.separator - + mModelInfo.name.replace(' ', '_') - + "_capture_" + format.getChannelCount() + "ch_" - + format.getSampleRate() + "hz_" + encoding + ".pcm")); + File file = new File( + getFilesDir() + File.separator + + mModelInfo.name.replace(' ', '_') + + "_capture_" + format.getChannelCount() + "ch_" + + format.getSampleRate() + "hz_" + encoding + + "_" + (++captureCount) + ".pcm"); + Log.i(TAG, "Writing audio to: " + file); + fos = new FileOutputStream(file); } catch (IOException e) { Log.e(TAG, "Failed to open output for saving PCM data", e); postErrorToast("Failed to open output for saving PCM data: " @@ -635,6 +667,10 @@ public class SoundTriggerTestService extends Service { bytesRequired -= bytesRead; } audioRecord.stop(); + if (fos != null) { + fos.flush(); + fos.close(); + } } catch (Exception e) { Log.e(TAG, "Error recording trigger audio", e); postErrorToast("Error recording trigger audio: " + e.getMessage()); @@ -651,6 +687,26 @@ public class SoundTriggerTestService extends Service { setModelState(mModelInfo, "Recording finished"); } } + + private AudioFormat getAudioFormat() { + if (mEvent != null) { + return mEvent.getCaptureAudioFormat(); + } + if (mRecognitionEvent != null) { + return mRecognitionEvent.captureFormat; + } + return null; + } + + private int getCaptureSession() { + if (mEvent != null) { + return mEvent.getCaptureSession(); + } + if (mRecognitionEvent != null) { + return mRecognitionEvent.captureSession; + } + return 0; + } } // Implementation of SoundTriggerDetector.Callback. diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java index cfe8c855ac81..996a78f2e42a 100644 --- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java +++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerUtil.java @@ -18,6 +18,8 @@ package com.android.test.soundtrigger; import android.annotation.Nullable; import android.content.Context; +import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent; +import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel; import android.media.soundtrigger.SoundTriggerDetector; import android.media.soundtrigger.SoundTriggerManager; import android.os.RemoteException; @@ -27,6 +29,7 @@ import android.util.Log; import com.android.internal.app.ISoundTriggerService; +import java.lang.reflect.Method; import java.lang.RuntimeException; import java.util.UUID; @@ -50,13 +53,31 @@ public class SoundTriggerUtil { * The sound model must contain a valid UUID. * * @param soundModel The sound model to add/update. + * @return The true if the model was loaded successfully, false otherwise. */ public boolean addOrUpdateSoundModel(SoundTriggerManager.Model soundModel) { if (soundModel == null) { throw new RuntimeException("Bad sound model"); } mSoundTriggerManager.updateModel(soundModel); - return true; + // TODO: call loadSoundModel in the soundtrigger manager updateModel method + // instead of here. It is needed to keep soundtrigger manager internal + // state consistent. + return mSoundTriggerManager + .loadSoundModel(getGenericSoundModel(soundModel)) == 0; + } + + private GenericSoundModel getGenericSoundModel( + SoundTriggerManager.Model soundModel) { + try { + Method method = SoundTriggerManager.Model.class + .getDeclaredMethod("getGenericSoundModel"); + method.setAccessible(true); + return (GenericSoundModel) method.invoke(soundModel); + } catch (ReflectiveOperationException e) { + Log.e(TAG, "Failed to getGenericSoundModel: " + soundModel, e); + return null; + } } /** @@ -92,6 +113,16 @@ public class SoundTriggerUtil { return true; } + /** + * Get the current model state + * + * @param modelId The model ID to look-up the sound model for. + * @return 0 if the call succeeds, or an error code if it fails. + */ + public int getModelState(UUID modelId) { + return mSoundTriggerManager.getModelState(modelId); + } + public SoundTriggerDetector createSoundTriggerDetector(UUID modelId, SoundTriggerDetector.Callback callback) { return mSoundTriggerManager.createSoundTriggerDetector(modelId, callback, null); |